From 1f3854317c9c803061949b3b4e86aa244bf85128 Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Tue, 3 Aug 2021 20:03:16 -0600 Subject: [PATCH] Get the Damm module tested --- projects/damm/BUILD | 20 +++----------------- projects/damm/{ => src/python}/damm.py | 14 ++++++++++++-- projects/damm/test/python/test_damm.py | 15 +++++++++++++++ projects/damm/test/python/test_hypothesis.py | 11 +++++++++++ projects/damm/test_damm.py | 5 ----- 5 files changed, 41 insertions(+), 24 deletions(-) rename projects/damm/{ => src/python}/damm.py (87%) create mode 100644 projects/damm/test/python/test_damm.py create mode 100644 projects/damm/test/python/test_hypothesis.py delete mode 100644 projects/damm/test_damm.py diff --git a/projects/damm/BUILD b/projects/damm/BUILD index 653a463..0a7f3cf 100644 --- a/projects/damm/BUILD +++ b/projects/damm/BUILD @@ -1,20 +1,6 @@ -py_library( +py_project( name = "damm", - srcs = [ - "damm.py", + test_deps = [ + py_requirement("hypothesis"), ], - imports = [ - "." - ], - visibility = [ - "//visibility:public", - ] -) - -py_pytest( - name = "test_damm", - srcs = glob(["test_*.py"]), - deps = [ - ":damm", - ] ) diff --git a/projects/damm/damm.py b/projects/damm/src/python/damm.py similarity index 87% rename from projects/damm/damm.py rename to projects/damm/src/python/damm.py index 55460df..29bcb5b 100644 --- a/projects/damm/damm.py +++ b/projects/damm/src/python/damm.py @@ -45,12 +45,20 @@ class Damm(NamedTuple): return f"{self.__class__.__name__}({self.value}, {self.encode(self.value)})" @classmethod - def encode(cls, value): + def checkdigit(cls, value: int) -> int: + """Compute a check digit for a given value.""" + state = 0 for digit in str(value): state = cls.MATRIX[state][int(digit)] return state + @classmethod + def encode(cls, value: int) -> str: + """'encode' a value with a check digit.""" + + return f"{value}-{cls.checkdigit(value)}" + @classmethod def verify(cls, value: str) -> bool: """Verify a Damm encoded number, returning its value if valid. @@ -59,11 +67,13 @@ class Damm(NamedTuple): the string is correctly Damm encoded, the Damm of the entire string will be 0. """ - return cls.encode(int(value.replace("-", ""))) == 0 + + return cls.checkdigit(int(value.replace("-", ""))) == 0 @classmethod def from_str(cls, value: str) -> "Damm": """Verify a Damm coded string, and return its decoding.""" + if match := re.fullmatch(cls.DAMM_PATTERN, value): given_value = match.group("value") computed_code = cls.encode(given_value) diff --git a/projects/damm/test/python/test_damm.py b/projects/damm/test/python/test_damm.py new file mode 100644 index 0000000..2846593 --- /dev/null +++ b/projects/damm/test/python/test_damm.py @@ -0,0 +1,15 @@ +from damm import Damm + +import pytest + + +@pytest.mark.parametrize('num', [ + "0", # 0 itself is the start Damm state + "37", # [0, 3] => 7 + "92", # [0, 9] => 2 + "1234", # Amusingly, this is a 0-product. +]) +def test_num_verifies(num): + """Assert that known-good Damm checks pass.""" + + assert Damm.verify(num) diff --git a/projects/damm/test/python/test_hypothesis.py b/projects/damm/test/python/test_hypothesis.py new file mode 100644 index 0000000..70113da --- /dev/null +++ b/projects/damm/test/python/test_hypothesis.py @@ -0,0 +1,11 @@ +from damm import Damm + +from hypothesis import given +from hypothesis.strategies import integers + + +@given(integers(0, 1<<512)) +def test_num_checks_verify(num): + """Assert the generated Damm check for number verifies.""" + + assert Damm.verify(Damm.encode(num)) diff --git a/projects/damm/test_damm.py b/projects/damm/test_damm.py deleted file mode 100644 index 0314556..0000000 --- a/projects/damm/test_damm.py +++ /dev/null @@ -1,5 +0,0 @@ -""" - -""" - -from damm import Damm