Created
April 27, 2012 09:52
-
-
Save japsu/2507971 to your computer and use it in GitHub Desktop.
Phone number formatting and a minimal-boilerplate testing library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12:50:03 <&Japsu> Koodaa suomalaisten puhelinnumeroiden muotoilua, päädy toteuttamaan oma minimal-boilerplate-testauskirjasto. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Traceback (most recent call last): | |
File "finphone.py", line 73, in <module> | |
assert verify.check(), verify.report() | |
AssertionError: FAILURE (passed 10, failed 15, total 25) | |
FAIL #1: split_area_code | |
INPUT: '035551234' | |
OUTPUT: ['', '035551234'] | |
EXPECTED: ('03', '5551234') | |
FAIL #2: split_area_code | |
INPUT: '095551234' | |
OUTPUT: ['', '095551234'] | |
EXPECTED: ('09', '5551234') | |
FAIL #3: split_area_code | |
INPUT: '0195551234' | |
OUTPUT: ['', '0195551234'] | |
EXPECTED: ('019', '5551234') | |
FAIL #4: split_area_code | |
INPUT: '0505551234' | |
OUTPUT: ['', '0505551234'] | |
EXPECTED: ('050', '5551234') | |
FAIL #5: split_area_code | |
INPUT: '0500555123' | |
OUTPUT: ['', '0500555123'] | |
EXPECTED: ('0500', '555123') | |
FAIL #6: split_area_code | |
INPUT: '0440555123' | |
OUTPUT: ['', '0440555123'] | |
EXPECTED: ('0440', '555123') | |
FAIL #7: format_finnish_phone_number | |
INPUT: '0505551234' | |
OUTPUT: '0 050 555 1234' | |
EXPECTED: '050 555 1234' | |
FAIL #8: format_finnish_phone_number | |
INPUT: '0500555123' | |
OUTPUT: '0 050 055 5123' | |
EXPECTED: '0500 555 123' | |
FAIL #9: format_finnish_phone_number | |
INPUT: '035551234' | |
OUTPUT: '0 035 551 234' | |
EXPECTED: '03 555 1234' | |
FAIL #10: format_finnish_phone_number | |
INPUT: '0195551234' | |
OUTPUT: '0 019 555 1234' | |
EXPECTED: '019 555 1234' | |
FAIL #11: format_finnish_phone_number | |
INPUT: '09555123' | |
OUTPUT: '0 095 55123' | |
EXPECTED: '09 555 123' | |
FAIL #12: format_finnish_phone_number | |
INPUT: '0800123123' | |
OUTPUT: '0 080 012 3123' | |
EXPECTED: '0800 123 123' | |
FAIL #13: format_finnish_phone_number | |
INPUT: '02055512345678' | |
OUTPUT: '0 020 555 123 45678' | |
EXPECTED: '020 555 123 45678' | |
FAIL #14: format_finnish_phone_number | |
INPUT: '020202' | |
OUTPUT: '0 020 202' | |
EXPECTED: '020 202' | |
FAIL #15: format_finnish_phone_number | |
INPUT: '+358505551234' | |
OUTPUT: '0 +35 850 555 1234' | |
EXPECTED: '050 555 1234' | |
FAILURE (passed 10, failed 15, total 25) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from itertools import chain | |
from verify import verify | |
GROUPS_TEST_DATA = [ | |
('12', ['12']), | |
('123', ['123']), | |
('1234', ['1234']), | |
('12345', ['12345']), | |
('123456', ['123', '456']), | |
('1234567', ['123', '4567']), | |
('12345678', ['123', '45678']), | |
('123456789', ['123', '456', '789']), | |
(range(10, 15), [range(10, 15)]), | |
(range(10, 16), [range(10, 13), range(13, 16)]), | |
] | |
@verify(GROUPS_TEST_DATA, list) | |
def split_into_groups(digits, min_length=3): | |
# XXX horrendous recursive generator | |
split, splat = digits[:min_length], digits[min_length:] | |
if len(splat) < min_length: | |
yield split + splat | |
else: | |
yield split | |
for i in split_into_groups(splat, min_length): | |
yield i | |
AREA_CODE_TEST_DATA = [ | |
('035551234', ('03', '5551234')), | |
('095551234', ('09', '5551234')), | |
('0195551234', ('019', '5551234')), | |
('0505551234', ('050', '5551234')), | |
('0500555123', ('0500', '555123')), | |
('0440555123', ('0440', '555123')), | |
] | |
SHORT_AREA_CODES = ['03', '05', '09'] | |
@verify(AREA_CODE_TEST_DATA, list) | |
def split_area_code(phone_number): | |
return '', phone_number | |
PHONE_NUMBER_TEST_DATA = [ | |
('0505551234', '050 555 1234'), # basic format of GSM numbers | |
('0500555123', '0500 555 123'), # NMT to GSM transitional numbers | |
('035551234', '03 555 1234'), # basic format of landline numbers | |
('0195551234', '019 555 1234'), # some areas have a three-digit area code | |
('09555123', '09 555 123'), # there are short 6-digit phone numbers at least in the capital area | |
('0800123123', '0800 123 123'), # "recreational" services | |
('02055512345678', '020 555 123 45678'), # extremely long numbers possible in corporate phones | |
('020202', '020 202'), # fuck fonecta ;) ;) | |
('+358505551234', '050 555 1234'), # convert international phone numbers to Finnish format | |
] | |
@verify(PHONE_NUMBER_TEST_DATA) | |
def format_finnish_phone_number(ugly): | |
area_code, local_number = split_area_code(ugly) | |
groups = split_into_groups(local_number) | |
return " ".join(chain(['0' + area_code], groups)) | |
if __name__ == "__main__": | |
assert verify.check(), verify.report() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12:57:12 <@Japsu> Koodaa suomalaisten puhelinnumerojen muotoilua, päädy toteuttamaan oma minimal-boilerplate-testauskirjasto: https://gist.github.com/2507971 | |
12:58:33 <@Lmmz> puuttuu testicase, jossa kansainvälinen prefiksi on muodossa 00358! | |
12:58:44 <@Japsu> hienoa, kiitos, täytyypä lisätä! | |
12:58:59 <@Japsu> itse finphone.py on siis hyvinkin kesken koska päädyin koodaamaan verify.py:tä! | |
12:59:00 <@Lmmz> ja vireve-numerot | |
12:59:04 <@Lmmz> virve jopa | |
12:59:07 <@Japsu> mitäs ne on muodoltaan? | |
12:59:38 <@Japsu> tajusin just, et 0500, 050, 05 on aikamoinen klusteri | |
12:59:54 <@Japsu> ratkaisu: listaan kaikki suuntanumerot preferenssijärjestyksessä | |
13:00:47 <@Lmmz> niissä virvenumeroissa on monissa aika pitkä prefiksi, muistaakseni joku viisnumeroinen | |
13:00:55 <@Lmmz> sitten on esim. PV:n numerot, joissa on prefiksinä 0299 | |
13:01:23 <@Lmmz> esim. 0299 530342 | |
13:01:26 <@Japsu> hmmjoo | |
13:01:52 <@Lmmz> muillakin viranomaisilla oli jotain jänniä numeroita nykyään, poliisilla taitaa kans olla joku valtakunnallinen "suuntanumero" | |
13:02:05 <@Japsu> täytynee tehdä toi silleen että se yrittää löytää mahdollisimman pitkän suuntanumeron | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# TODO: make verify into a factory called Verify that produces parametrized decorators so that | |
# verify = Verify() | |
# @verify(MY_EXAMPLES) | |
# def myfun(): | |
# .... | |
# verify.check() | |
def identity(x): | |
return x | |
class verify(object): | |
instances = list() | |
failures = None | |
total = None | |
def __init__(self, test_data, treat_output=identity): | |
self.test_data = test_data | |
self.treat_output = treat_output | |
def __call__(self, func): | |
self.func = func | |
self.instances.append(self) | |
return func | |
@classmethod | |
def check(cls): | |
cls.failures = list() | |
cls.total = 0 | |
for instance in cls.instances: | |
for example in instance.test_data: | |
cls.total += 1 | |
input, expected = example | |
output = instance.func(input) | |
output = instance.treat_output(output) | |
if output != expected: | |
cls.failures.append((instance.func, input, output, expected)) | |
return not cls.failures | |
@classmethod | |
def clear(cls): | |
cls.instances = list() | |
cls.total = None | |
cls.failures = None | |
@classmethod | |
def report(cls): | |
msgs = list() | |
failures = len(cls.failures) | |
passes = cls.total - failures | |
if cls.failures is None: | |
msgs.append('NO TESTS WERE RUN') | |
elif not cls.failures: | |
msgs.append('SUCCESS (passed {passes})'.format(**locals())) | |
else: | |
failure_headline = 'FAILURE (passed {passes}, failed {failures}, total {cls.total})'.format(**locals()) | |
msgs.append(failure_headline) | |
for (num, (func, input, output, expected)) in enumerate(cls.failures): | |
num += 1 | |
msgs.append('FAIL #{num}: {func.__name__}\nINPUT: {input!r}\nOUTPUT: {output!r}\nEXPECTED: {expected!r}'.format(**locals())) | |
msgs.append(failure_headline) | |
msgs.append('') | |
return '\n\n'.join(msgs) | |
def test_verify(): | |
TEST1 = zip(range(5), range(5)) | |
func1 = verify(TEST1)(identity) | |
assert verify.check(), verify.failures | |
print verify.report() | |
verify.clear() | |
TEST2 = [('1','1'), ('1', '2')] | |
func2 = verify(TEST2)(identity) | |
assert not verify.check(), verify.failures | |
assert verify.failures == [(identity, '1', '1', '2')], verify.failures | |
if __name__ == "__main__": | |
test_verify() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment