Skip to content

Commit d075593

Browse files
committed
Test Python and C codepaths in base64 using mixins
Do we really need to test the legacy API twice?
1 parent 4746d18 commit d075593

File tree

1 file changed

+54
-38
lines changed

1 file changed

+54
-38
lines changed

Lib/test/test_base64.py

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,15 @@
22
import binascii
33
import os
44
from array import array
5-
from functools import update_wrapper
65
from test.support import os_helper
76
from test.support import script_helper
87
from test.support.import_helper import import_fresh_module
98

10-
base64 = import_fresh_module("base64", blocked=["_base64"])
9+
py_base64 = import_fresh_module("base64", blocked=["_base64"])
1110
c_base64 = import_fresh_module("base64", fresh=["_base64"])
1211

1312

14-
def with_c_implementation(test_func):
15-
if c_base64 is None:
16-
return test_func
17-
18-
def _test_func(self):
19-
global base64
20-
21-
# Test Python implementation
22-
test_func(self)
23-
24-
# Test C implementation
25-
base64_ = base64
26-
try:
27-
base64 = c_base64
28-
test_func(self)
29-
finally:
30-
base64 = base64_
31-
32-
update_wrapper(_test_func, test_func)
33-
34-
return _test_func
35-
36-
37-
class LegacyBase64TestCase(unittest.TestCase):
13+
class LegacyBase64TestCase:
3814

3915
# Legacy API is not as permissive as the modern API
4016
def check_type_errors(self, f):
@@ -46,6 +22,7 @@ def check_type_errors(self, f):
4622
self.assertRaises(TypeError, f, int_data)
4723

4824
def test_encodebytes(self):
25+
base64 = self.module
4926
eq = self.assertEqual
5027
eq(base64.encodebytes(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=\n")
5128
eq(base64.encodebytes(b"a"), b"YQ==\n")
@@ -67,6 +44,7 @@ def test_encodebytes(self):
6744
self.check_type_errors(base64.encodebytes)
6845

6946
def test_decodebytes(self):
47+
base64 = self.module
7048
eq = self.assertEqual
7149
eq(base64.decodebytes(b"d3d3LnB5dGhvbi5vcmc=\n"), b"www.python.org")
7250
eq(base64.decodebytes(b"YQ==\n"), b"a")
@@ -88,6 +66,7 @@ def test_decodebytes(self):
8866
self.check_type_errors(base64.decodebytes)
8967

9068
def test_encode(self):
69+
base64 = self.module
9170
eq = self.assertEqual
9271
from io import BytesIO, StringIO
9372
infp = BytesIO(b'abcdefghijklmnopqrstuvwxyz'
@@ -105,6 +84,7 @@ def test_encode(self):
10584
self.assertRaises(TypeError, base64.encode, StringIO('abc'), StringIO())
10685

10786
def test_decode(self):
87+
base64 = self.module
10888
from io import BytesIO, StringIO
10989
infp = BytesIO(b'd3d3LnB5dGhvbi5vcmc=')
11090
outfp = BytesIO()
@@ -116,7 +96,16 @@ def test_decode(self):
11696
self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), StringIO())
11797

11898

119-
class BaseXYTestCase(unittest.TestCase):
99+
class LegacyBase64TestCasePython(LegacyBase64TestCase, unittest.TestCase):
100+
module = py_base64
101+
102+
103+
@unittest.skipUnless(c_base64, "requires _base64")
104+
class LegacyBase64TestCaseC(LegacyBase64TestCase, unittest.TestCase):
105+
module = c_base64
106+
107+
108+
class BaseXYTestCase:
120109

121110
# Modern API completely ignores exported dimension and format data and
122111
# treats any buffer as a stream of bytes
@@ -128,6 +117,7 @@ def check_decode_type_errors(self, f):
128117
self.assertRaises(TypeError, f, [])
129118

130119
def check_other_types(self, f, bytes_data, expected):
120+
base64 = self.module
131121
eq = self.assertEqual
132122
b = bytearray(bytes_data)
133123
eq(f(b), expected)
@@ -154,6 +144,7 @@ def check_nonbyte_element_format(self, f, data):
154144

155145

156146
def test_b64encode(self):
147+
base64 = self.module
157148
eq = self.assertEqual
158149
# Test default alphabet
159150
eq(base64.b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=")
@@ -204,6 +195,7 @@ def test_b64encode(self):
204195
self.check_encode_type_errors(base64.urlsafe_b64encode)
205196

206197
def test_b64decode(self):
198+
base64 = self.module
207199
eq = self.assertEqual
208200

209201
tests = {b"d3d3LnB5dGhvbi5vcmc=": b"www.python.org",
@@ -260,10 +252,12 @@ def test_b64decode(self):
260252
self.check_decode_type_errors(base64.urlsafe_b64decode)
261253

262254
def test_b64decode_padding_error(self):
255+
base64 = self.module
263256
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
264257
self.assertRaises(binascii.Error, base64.b64decode, 'abc')
265258

266259
def test_b64decode_invalid_chars(self):
260+
base64 = self.module
267261
# issue 1466065: Test some invalid characters.
268262
tests = ((b'%3d==', b'\xdd'),
269263
(b'$3d==', b'\xdd'),
@@ -296,6 +290,7 @@ def test_b64decode_invalid_chars(self):
296290
self.assertEqual(base64.urlsafe_b64decode(b'++--//__'), res)
297291

298292
def test_b32encode(self):
293+
base64 = self.module
299294
eq = self.assertEqual
300295
eq(base64.b32encode(b''), b'')
301296
eq(base64.b32encode(b'\x00'), b'AA======')
@@ -309,6 +304,7 @@ def test_b32encode(self):
309304
self.check_encode_type_errors(base64.b32encode)
310305

311306
def test_b32decode(self):
307+
base64 = self.module
312308
eq = self.assertEqual
313309
tests = {b'': b'',
314310
b'AA======': b'\x00',
@@ -326,6 +322,7 @@ def test_b32decode(self):
326322
self.check_decode_type_errors(base64.b32decode)
327323

328324
def test_b32decode_casefold(self):
325+
base64 = self.module
329326
eq = self.assertEqual
330327
tests = {b'': b'',
331328
b'ME======': b'a',
@@ -367,6 +364,7 @@ def test_b32decode_casefold(self):
367364
self.assertRaises(binascii.Error, base64.b32decode, data_str)
368365

369366
def test_b32decode_error(self):
367+
base64 = self.module
370368
tests = [b'abc', b'ABCDEF==', b'==ABCDEF']
371369
prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
372370
for i in range(0, 17):
@@ -383,6 +381,7 @@ def test_b32decode_error(self):
383381
base64.b32decode(data.decode('ascii'))
384382

385383
def test_b32hexencode(self):
384+
base64 = self.module
386385
test_cases = [
387386
# to_encode, expected
388387
(b'', b''),
@@ -398,10 +397,12 @@ def test_b32hexencode(self):
398397
self.assertEqual(base64.b32hexencode(to_encode), expected)
399398

400399
def test_b32hexencode_other_types(self):
400+
base64 = self.module
401401
self.check_other_types(base64.b32hexencode, b'abcd', b'C5H66P0=')
402402
self.check_encode_type_errors(base64.b32hexencode)
403403

404404
def test_b32hexdecode(self):
405+
base64 = self.module
405406
test_cases = [
406407
# to_decode, expected, casefold
407408
(b'', b'', False),
@@ -432,10 +433,12 @@ def test_b32hexdecode(self):
432433
casefold), expected)
433434

434435
def test_b32hexdecode_other_types(self):
436+
base64 = self.module
435437
self.check_other_types(base64.b32hexdecode, b'C5H66===', b'abc')
436438
self.check_decode_type_errors(base64.b32hexdecode)
437439

438440
def test_b32hexdecode_error(self):
441+
base64 = self.module
439442
tests = [b'abc', b'ABCDEF==', b'==ABCDEF', b'c4======']
440443
prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
441444
for i in range(0, 17):
@@ -453,6 +456,7 @@ def test_b32hexdecode_error(self):
453456

454457

455458
def test_b16encode(self):
459+
base64 = self.module
456460
eq = self.assertEqual
457461
eq(base64.b16encode(b'\x01\x02\xab\xcd\xef'), b'0102ABCDEF')
458462
eq(base64.b16encode(b'\x00'), b'00')
@@ -462,6 +466,7 @@ def test_b16encode(self):
462466
self.check_encode_type_errors(base64.b16encode)
463467

464468
def test_b16decode(self):
469+
base64 = self.module
465470
eq = self.assertEqual
466471
eq(base64.b16decode(b'0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
467472
eq(base64.b16decode('0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
@@ -488,8 +493,8 @@ def test_b16decode(self):
488493
# Incorrect "padding"
489494
self.assertRaises(binascii.Error, base64.b16decode, '010')
490495

491-
@with_c_implementation
492496
def test_a85encode(self):
497+
base64 = self.module
493498
eq = self.assertEqual
494499

495500
tests = {
@@ -539,8 +544,8 @@ def test_a85encode(self):
539544
eq(base64.a85encode(b' '*6, foldspaces=True, adobe=False), b'y+<U')
540545
eq(base64.a85encode(b' '*5, foldspaces=True, adobe=False), b'y+9')
541546

542-
@with_c_implementation
543547
def test_b85encode(self):
548+
base64 = self.module
544549
eq = self.assertEqual
545550

546551
tests = {
@@ -574,8 +579,8 @@ def test_b85encode(self):
574579
self.check_other_types(base64.b85encode, b"www.python.org",
575580
b'cXxL#aCvlSZ*DGca%T')
576581

577-
@with_c_implementation
578582
def test_z85encode(self):
583+
base64 = self.module
579584
eq = self.assertEqual
580585

581586
tests = {
@@ -609,8 +614,8 @@ def test_z85encode(self):
609614
self.check_other_types(base64.z85encode, b"www.python.org",
610615
b'CxXl-AcVLsz/dgCA+t')
611616

612-
@with_c_implementation
613617
def test_a85decode(self):
618+
base64 = self.module
614619
eq = self.assertEqual
615620

616621
tests = {
@@ -656,8 +661,8 @@ def test_a85decode(self):
656661
self.check_other_types(base64.a85decode, b'GB\\6`E-ZP=Df.1GEb>',
657662
b"www.python.org")
658663

659-
@with_c_implementation
660664
def test_b85decode(self):
665+
base64 = self.module
661666
eq = self.assertEqual
662667

663668
tests = {
@@ -692,8 +697,8 @@ def test_b85decode(self):
692697
self.check_other_types(base64.b85decode, b'cXxL#aCvlSZ*DGca%T',
693698
b"www.python.org")
694699

695-
@with_c_implementation
696700
def test_z85decode(self):
701+
base64 = self.module
697702
eq = self.assertEqual
698703

699704
tests = {
@@ -728,8 +733,8 @@ def test_z85decode(self):
728733
self.check_other_types(base64.z85decode, b'CxXl-AcVLsz/dgCA+t',
729734
b'www.python.org')
730735

731-
@with_c_implementation
732736
def test_a85_padding(self):
737+
base64 = self.module
733738
eq = self.assertEqual
734739

735740
eq(base64.a85encode(b"x", pad=True), b'GQ7^D')
@@ -744,8 +749,8 @@ def test_a85_padding(self):
744749
eq(base64.a85decode(b'G^+IX'), b"xxxx")
745750
eq(base64.a85decode(b'G^+IXGQ7^D'), b"xxxxx\x00\x00\x00")
746751

747-
@with_c_implementation
748752
def test_b85_padding(self):
753+
base64 = self.module
749754
eq = self.assertEqual
750755

751756
eq(base64.b85encode(b"x", pad=True), b'cmMzZ')
@@ -760,8 +765,8 @@ def test_b85_padding(self):
760765
eq(base64.b85decode(b'czAet'), b"xxxx")
761766
eq(base64.b85decode(b'czAetcmMzZ'), b"xxxxx\x00\x00\x00")
762767

763-
@with_c_implementation
764768
def test_a85decode_errors(self):
769+
base64 = self.module
765770
illegal = (set(range(32)) | set(range(118, 256))) - set(b' \t\n\r\v')
766771
for c in illegal:
767772
with self.assertRaises(ValueError, msg=bytes([c])):
@@ -798,8 +803,8 @@ def test_a85decode_errors(self):
798803
self.assertRaises(ValueError, base64.a85decode, b'aaaay',
799804
foldspaces=True)
800805

801-
@with_c_implementation
802806
def test_b85decode_errors(self):
807+
base64 = self.module
803808
illegal = list(range(33)) + \
804809
list(b'"\',./:[\\]') + \
805810
list(range(128, 256))
@@ -813,8 +818,8 @@ def test_b85decode_errors(self):
813818
self.assertRaises(ValueError, base64.b85decode, b'|NsC')
814819
self.assertRaises(ValueError, base64.b85decode, b'|NsC1')
815820

816-
@with_c_implementation
817821
def test_z85decode_errors(self):
822+
base64 = self.module
818823
illegal = list(range(33)) + \
819824
list(b'"\',;_`|\\~') + \
820825
list(range(128, 256))
@@ -830,6 +835,7 @@ def test_z85decode_errors(self):
830835
self.assertRaises(ValueError, base64.z85decode, b'%nSc1')
831836

832837
def test_decode_nonascii_str(self):
838+
base64 = self.module
833839
decode_funcs = (base64.b64decode,
834840
base64.standard_b64decode,
835841
base64.urlsafe_b64decode,
@@ -845,6 +851,7 @@ def test_ErrorHeritage(self):
845851
self.assertTrue(issubclass(binascii.Error, ValueError))
846852

847853
def test_RFC4648_test_cases(self):
854+
base64 = self.module
848855
# test cases from RFC 4648 section 10
849856
b64encode = base64.b64encode
850857
b32hexencode = base64.b32hexencode
@@ -884,6 +891,15 @@ def test_RFC4648_test_cases(self):
884891
self.assertEqual(b16encode(b"foobar"), b"666F6F626172")
885892

886893

894+
class BaseXYTestCasePython(BaseXYTestCase, unittest.TestCase):
895+
module = py_base64
896+
897+
898+
@unittest.skipUnless(c_base64, "requires _base64")
899+
class BaseXYTestCaseC(BaseXYTestCase, unittest.TestCase):
900+
module = c_base64
901+
902+
887903
class TestMain(unittest.TestCase):
888904
def tearDown(self):
889905
if os.path.exists(os_helper.TESTFN):

0 commit comments

Comments
 (0)