Skip to content

Commit

Permalink
Fix ssn provider for zh_TW (#1851)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyanghsieh committed May 2, 2023
1 parent c46c69c commit 0927375
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
43 changes: 40 additions & 3 deletions faker/providers/ssn/zh_TW/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
from .. import Provider as SsnProvider


class Provider(SsnProvider):
ssn_formats = ("?#########",)
def checksum(s: str) -> int:
def _get_alphabet_weight(c: str) -> int:
"""A=10, B=11, ...., H=17,
I=34,
J=18, K=19, ..., N=22,
O=35,
P=23, Q=24, ..., V=29,
W=32,
X=30, Y=31, Z=33
"""
if ord(c) < 73: # A-H
return ord(c) - 55
if ord(c) == 73: # I
return ord(c) - 39
if ord(c) < 79: # J-N
return ord(c) - 56
if ord(c) == 79: # O
return ord(c) - 44
if ord(c) < 87: # P-V
return ord(c) - 57
if ord(c) == 87: # W
return ord(c) - 55
if ord(c) < 90: # X, Y
return ord(c) - 58
return ord(c) - 57 # Z

res = 0
for i, c in enumerate(s):
if i == 0:
res = _get_alphabet_weight(c) % 10 * 9 + _get_alphabet_weight(c) // 10
elif i < 9:
res += int(c) * (9 - i)
else:
res += int(c)
return res


class Provider(SsnProvider):
def ssn(self) -> str:
return self.bothify(self.random_element(self.ssn_formats)).upper()
ssn_without_last_char = self.numerify(self.random_uppercase_letter() + str(self.random_int(1, 2)) + "#######")
last_char = str((10 - checksum(ssn_without_last_char) % 10) % 10)
return ssn_without_last_char + last_char
23 changes: 23 additions & 0 deletions tests/providers/test_ssn.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from faker.providers.ssn.pt_BR import checksum as pt_checksum
from faker.providers.ssn.ro_RO import ssn_checksum as ro_ssn_checksum
from faker.providers.ssn.ro_RO import vat_checksum as ro_vat_checksum
from faker.providers.ssn.zh_TW import checksum as tw_checksum
from faker.utils.checksums import luhn_checksum


Expand Down Expand Up @@ -1271,3 +1272,25 @@ def check_length(self):
def test_vat_id(self):
for _ in range(100):
assert re.search(r"^LV\d{11}$", self.fake.vat_id())


class TestZhTW(unittest.TestCase):
num_sample_runs = 10

def setUp(self):
self.fake = Faker("zh_TW")
Faker.seed(0)
self.samples = [self.fake.ssn() for _ in range(self.num_sample_runs)]

def test_length(self):
for sample in self.samples:
assert len(sample) == 10

def test_gender(self):
"""only '1' and '2' are allowed in the second char"""
for sample in self.samples:
assert sample[1] == "1" or sample[1] == "2"

def test_checksum(self):
for sample in self.samples:
assert tw_checksum(sample) % 10 == 0

0 comments on commit 0927375

Please sign in to comment.