diff --git a/barcode/codex.py b/barcode/codex.py index 9a60c31..987e065 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -278,6 +278,10 @@ def _calculate_checksum(self, encoded: list[int]) -> int: return sum(cs) % 103 def _build(self) -> list[int]: + # Reset the state that gets mutated while building so that repeated + # calls on the same instance are deterministic (see #143). + self._charset = "C" + self._digit_buffer = "" encoded: list[int] = [code128.START_CODES[self._charset]] for i, char in enumerate(self.code): encoded.extend(self._maybe_switch_charset(i)) diff --git a/tests/test_code128.py b/tests/test_code128.py new file mode 100644 index 0000000..7f4765c --- /dev/null +++ b/tests/test_code128.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from barcode.codex import Code128 + + +def test_build_is_stable_across_repeated_calls() -> None: + """Calling build() repeatedly on the same instance must be deterministic. + + Regression test for #143: ``_build`` mutated ``_charset`` and + ``_digit_buffer`` without resetting them, so a second call started from + stale state and produced a different bit string. + """ + code = Code128("12A") + first = code.build() + assert code.build() == first + assert code.build() == first + + +def test_encoded_is_stable_across_repeated_calls() -> None: + """The ``encoded`` property must also be deterministic across calls.""" + code = Code128("12A") + first = code.encoded + assert code.encoded == first + assert code.encoded == first + + +def test_reused_instance_matches_fresh_instance() -> None: + """A reused instance must encode identically to a freshly built one.""" + reused = Code128("123ABC456") + reused.build() # dirties the internal charset/buffer state + assert reused.build() == Code128("123ABC456").build()