From 128c3d1360024a1b47096629cf5af9644c9d837f Mon Sep 17 00:00:00 2001 From: Apoorv Darshan Date: Thu, 9 Jul 2026 22:25:00 +0530 Subject: [PATCH] Fix Code128 build() producing different output on repeated calls Code128._build mutated self._charset and self._digit_buffer (both set only in __init__) but never reset them. After a build that switched to charset A/B or left a digit buffered, a subsequent build()/encoded call started from stale state and emitted a different, incorrect bit string. Reset both to their initial values at the start of _build() so repeated calls on the same instance are deterministic. Fixes #143 --- barcode/codex.py | 4 ++++ tests/test_code128.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/test_code128.py 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()