Skip to content

Commit 101edf6

Browse files
gpsheadclaude
andcommitted
Improve base85/ascii85 canonical test coverage
- Test non-canonical rejection for all partial group sizes (2/3/4 chars) - Test digit-0 1-char group for ascii85 (exercises chunk_len==0 guard) - Test boundary byte values (\x00, \xff) at each group size Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9b78bdd commit 101edf6

File tree

1 file changed

+35
-21
lines changed

1 file changed

+35
-21
lines changed

Lib/test/test_binascii.py

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,8 @@ def test_base85_canonical(self):
807807
# 1-char partial groups are never produced by a conforming encoder
808808
with self.assertRaises(binascii.Error):
809809
binascii.a2b_base85(b'V', canonical=True)
810+
# Digit 0 in a 1-char group exercises the explicit chunk_len==0
811+
# guard (without it the division check would see 0/P == 0/P).
810812
with self.assertRaises(binascii.Error):
811813
binascii.a2b_base85(b'0', canonical=True)
812814

@@ -817,22 +819,27 @@ def test_base85_canonical(self):
817819
decoded = binascii.a2b_base85(encoded, canonical=True)
818820
self.assertEqual(decoded, data)
819821

820-
# Non-canonical 2-char group (1 output byte)
821-
canonical_enc = binascii.b2a_base85(b'a')
822-
self.assertEqual(canonical_enc, b'VE')
823-
# VF decodes to b'a' but is not canonical
824-
with self.assertRaises(binascii.Error):
825-
binascii.a2b_base85(b'VF', canonical=True)
826-
827-
# Non-canonical 3-char group (2 output bytes)
828-
canonical_enc = binascii.b2a_base85(b'ab')
829-
decoded_canonical = binascii.a2b_base85(canonical_enc, canonical=True)
830-
self.assertEqual(decoded_canonical, b'ab')
831-
# Increment last digit to make non-canonical
832-
non_canonical = canonical_enc[:-1] + bytes([canonical_enc[-1] + 1])
833-
self.assertEqual(binascii.a2b_base85(non_canonical), b'ab')
834-
with self.assertRaises(binascii.Error):
835-
binascii.a2b_base85(non_canonical, canonical=True)
822+
# Test non-canonical rejection for each partial group size
823+
# (2-char/1-byte, 3-char/2-byte, 4-char/3-byte).
824+
# Incrementing the last digit by 1 produces a non-canonical
825+
# encoding. For 4-char groups (n_pad=1) a +1 can change the
826+
# output byte, so we use b'ab\x00' whose canonical form allows
827+
# a +1 that still decodes to the same 3 bytes.
828+
for data in [b'a', b'ab', b'ab\x00']:
829+
canonical_enc = binascii.b2a_base85(data)
830+
non_canonical = (canonical_enc[:-1]
831+
+ bytes([canonical_enc[-1] + 1]))
832+
# Same decoded output without canonical check
833+
self.assertEqual(binascii.a2b_base85(non_canonical), data)
834+
# Rejected with canonical=True
835+
with self.assertRaises(binascii.Error):
836+
binascii.a2b_base85(non_canonical, canonical=True)
837+
838+
# Boundary bytes: \x00 and \xff for each partial group size
839+
for data in [b'\x00', b'\x00\x00', b'\x00\x00\x00',
840+
b'\xff', b'\xff\xff', b'\xff\xff\xff']:
841+
canonical_enc = binascii.b2a_base85(data)
842+
binascii.a2b_base85(canonical_enc, canonical=True)
836843

837844
# Full 5-char groups are always canonical (no padding bits)
838845
self.assertEqual(
@@ -849,6 +856,9 @@ def test_ascii85_canonical(self):
849856
# 1-char partial groups are never produced by a conforming encoder
850857
with self.assertRaises(binascii.Error):
851858
binascii.a2b_ascii85(b'@', canonical=True)
859+
# Digit 0 ('!' in ascii85) exercises the explicit chunk_len==0 guard
860+
with self.assertRaises(binascii.Error):
861+
binascii.a2b_ascii85(b'!', canonical=True)
852862

853863
# Verify round-trip: encode then decode with canonical=True works
854864
for data in [b'a', b'ab', b'abc', b'abcd', b'abcde',
@@ -857,11 +867,15 @@ def test_ascii85_canonical(self):
857867
decoded = binascii.a2b_ascii85(encoded, canonical=True)
858868
self.assertEqual(decoded, data)
859869

860-
# Non-canonical 2-char group
861-
canonical_enc = binascii.b2a_ascii85(b'a')
862-
self.assertEqual(canonical_enc, b'@/')
863-
with self.assertRaises(binascii.Error):
864-
binascii.a2b_ascii85(b'@0', canonical=True)
870+
# Test non-canonical rejection for each partial group size.
871+
# See test_base85_canonical for why b'ab\x00' is used for 3 bytes.
872+
for data in [b'a', b'ab', b'ab\x00']:
873+
canonical_enc = binascii.b2a_ascii85(data)
874+
non_canonical = (canonical_enc[:-1]
875+
+ bytes([canonical_enc[-1] + 1]))
876+
self.assertEqual(binascii.a2b_ascii85(non_canonical), data)
877+
with self.assertRaises(binascii.Error):
878+
binascii.a2b_ascii85(non_canonical, canonical=True)
865879

866880
# Full 5-char groups are always canonical
867881
self.assertEqual(

0 commit comments

Comments
 (0)