Skip to content

Commit

Permalink
Add fake automotive vin number function (#1879) (#1884)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyanghsieh committed Jul 7, 2023
1 parent 597e80a commit d23efeb
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
41 changes: 41 additions & 0 deletions faker/providers/automotive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,36 @@
localized = True


def calculate_vin_str_weight(s: str, weight_factor: list) -> int:
"""
multiply s(str) by weight_factor char by char
e.g.
input: s="ABCDE", weight_factor=[1, 2, 3, 4, 5]
return: A*1 + B*2 + C*3 + D*4 + E*5
will multiply 0 when len(weight_factor) less than len(s)
"""

def _get_char_weight(c: str) -> int:
"""A=1, B=2, ...., I=9,
J=1, K=2, ..., R=9,
S=2, T=3, ..., Z=9
"""
if ord(c) <= 64: # 0-9
return int(c)
if ord(c) <= 73: # A-I
return ord(c) - 64
if ord(c) <= 82: # J-R
return ord(c) - 73
# S-Z
return ord(c) - 81

res = 0
for i, c in enumerate(s):
res += _get_char_weight(c) * weight_factor[i] if i < len(weight_factor) else 0
return res


class Provider(BaseProvider):
"""Implement default automotive provider for Faker."""

Expand All @@ -20,3 +50,14 @@ def license_plate(self) -> str:
self.random_element(self.license_formats),
)
return self.numerify(temp)

def vin(self) -> str:
"""Generate vin number."""
vin_chars = "1234567890ABCDEFGHJKLMNPRSTUVWXYZ" # I, O, Q are restricted
front_part = self.bothify("????????", letters=vin_chars)
rear_part = self.bothify("????????", letters=vin_chars)
front_part_weight = calculate_vin_str_weight(front_part, [8, 7, 6, 5, 4, 3, 2, 10])
rear_part_weight = calculate_vin_str_weight(rear_part, [9, 8, 7, 6, 5, 4, 3, 2])
checksum = (front_part_weight + rear_part_weight) % 11
checksum_char = "X" if checksum == 10 else str(checksum)
return front_part + checksum_char + rear_part
14 changes: 14 additions & 0 deletions tests/providers/test_automotive.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from faker.providers.automotive.ru_RU import Provider as RuRuAutomotiveProvider
from faker.providers.automotive.sk_SK import Provider as SkSkAutomotiveProvider
from faker.providers.automotive.tr_TR import Provider as TrTrAutomotiveProvider
from faker.providers.automotive import calculate_vin_str_weight


class _SimpleAutomotiveTestMixin:
Expand All @@ -23,6 +24,19 @@ def test_license_plate(self, faker, num_samples):
assert match is not None
self.perform_extra_checks(license_plate, match)

def test_vin(self, faker, num_samples):
for _ in range(num_samples):
vin_number = faker.vin()
# length check: 17
assert len(vin_number) == 17

# verify checksum: vin_number[8]
front_part_weight = calculate_vin_str_weight(vin_number[:8], [8, 7, 6, 5, 4, 3, 2, 10])
rear_part_weight = calculate_vin_str_weight(vin_number[9:], [9, 8, 7, 6, 5, 4, 3, 2])
checksum = (front_part_weight + rear_part_weight) % 11
checksum_str = "X" if checksum == 10 else str(checksum)
assert vin_number[8] == checksum_str


class TestArBh(_SimpleAutomotiveTestMixin):
"""Test ar_BH automotive provider methods"""
Expand Down

0 comments on commit d23efeb

Please sign in to comment.