55import os
66import sys
77import subprocess
8-
8+ import struct
9+ from array import array
910
1011
1112class LegacyBase64TestCase (unittest .TestCase ):
13+
14+ # Legacy API is not as permissive as the modern API
15+ def check_type_errors (self , f ):
16+ self .assertRaises (TypeError , f , "" )
17+ self .assertRaises (TypeError , f , [])
18+ multidimensional = memoryview (b"1234" ).cast ('B' , (2 , 2 ))
19+ self .assertRaises (TypeError , f , multidimensional )
20+ int_data = memoryview (b"1234" ).cast ('I' )
21+ self .assertRaises (TypeError , f , int_data )
22+
1223 def test_encodebytes (self ):
1324 eq = self .assertEqual
1425 eq (base64 .encodebytes (b"www.python.org" ), b"d3d3LnB5dGhvbi5vcmc=\n " )
@@ -24,7 +35,9 @@ def test_encodebytes(self):
2435 b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n " )
2536 # Non-bytes
2637 eq (base64 .encodebytes (bytearray (b'abc' )), b'YWJj\n ' )
27- self .assertRaises (TypeError , base64 .encodebytes , "" )
38+ eq (base64 .encodebytes (memoryview (b'abc' )), b'YWJj\n ' )
39+ eq (base64 .encodebytes (array ('B' , b'abc' )), b'YWJj\n ' )
40+ self .check_type_errors (base64 .encodebytes )
2841
2942 def test_decodebytes (self ):
3043 eq = self .assertEqual
@@ -41,7 +54,9 @@ def test_decodebytes(self):
4154 eq (base64 .decodebytes (b'' ), b'' )
4255 # Non-bytes
4356 eq (base64 .decodebytes (bytearray (b'YWJj\n ' )), b'abc' )
44- self .assertRaises (TypeError , base64 .decodebytes , "" )
57+ eq (base64 .decodebytes (memoryview (b'YWJj\n ' )), b'abc' )
58+ eq (base64 .decodebytes (array ('B' , b'YWJj\n ' )), b'abc' )
59+ self .check_type_errors (base64 .decodebytes )
4560
4661 def test_encode (self ):
4762 eq = self .assertEqual
@@ -73,6 +88,38 @@ def test_decode(self):
7388
7489
7590class BaseXYTestCase (unittest .TestCase ):
91+
92+ # Modern API completely ignores exported dimension and format data and
93+ # treats any buffer as a stream of bytes
94+ def check_encode_type_errors (self , f ):
95+ self .assertRaises (TypeError , f , "" )
96+ self .assertRaises (TypeError , f , [])
97+
98+ def check_decode_type_errors (self , f ):
99+ self .assertRaises (TypeError , f , [])
100+
101+ def check_other_types (self , f , bytes_data , expected ):
102+ eq = self .assertEqual
103+ eq (f (bytearray (bytes_data )), expected )
104+ eq (f (memoryview (bytes_data )), expected )
105+ eq (f (array ('B' , bytes_data )), expected )
106+ self .check_nonbyte_element_format (base64 .b64encode , bytes_data )
107+ self .check_multidimensional (base64 .b64encode , bytes_data )
108+
109+ def check_multidimensional (self , f , data ):
110+ padding = b"\x00 " if len (data ) % 2 else b""
111+ bytes_data = data + padding # Make sure cast works
112+ shape = (len (bytes_data ) // 2 , 2 )
113+ multidimensional = memoryview (bytes_data ).cast ('B' , shape )
114+ self .assertEqual (f (multidimensional ), f (bytes_data ))
115+
116+ def check_nonbyte_element_format (self , f , data ):
117+ padding = b"\x00 " * ((4 - len (data )) % 4 )
118+ bytes_data = data + padding # Make sure cast works
119+ int_data = memoryview (bytes_data ).cast ('I' )
120+ self .assertEqual (f (int_data ), f (bytes_data ))
121+
122+
76123 def test_b64encode (self ):
77124 eq = self .assertEqual
78125 # Test default alphabet
@@ -90,13 +137,16 @@ def test_b64encode(self):
90137 b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==" )
91138 # Test with arbitrary alternative characters
92139 eq (base64 .b64encode (b'\xd3 V\xbe o\xf7 \x1d ' , altchars = b'*$' ), b'01a*b$cd' )
93- # Non-bytes
94- eq (base64 .b64encode (bytearray (b'abcd' )), b'YWJjZA==' )
95140 eq (base64 .b64encode (b'\xd3 V\xbe o\xf7 \x1d ' , altchars = bytearray (b'*$' )),
96141 b'01a*b$cd' )
97- # Check if passing a str object raises an error
98- self .assertRaises (TypeError , base64 .b64encode , "" )
99- self .assertRaises (TypeError , base64 .b64encode , b"" , altchars = "" )
142+ eq (base64 .b64encode (b'\xd3 V\xbe o\xf7 \x1d ' , altchars = memoryview (b'*$' )),
143+ b'01a*b$cd' )
144+ eq (base64 .b64encode (b'\xd3 V\xbe o\xf7 \x1d ' , altchars = array ('B' , b'*$' )),
145+ b'01a*b$cd' )
146+ # Non-bytes
147+ self .check_other_types (base64 .b64encode , b'abcd' , b'YWJjZA==' )
148+ self .check_encode_type_errors (base64 .b64encode )
149+ self .assertRaises (TypeError , base64 .b64encode , b"" , altchars = "*$" )
100150 # Test standard alphabet
101151 eq (base64 .standard_b64encode (b"www.python.org" ), b"d3d3LnB5dGhvbi5vcmc=" )
102152 eq (base64 .standard_b64encode (b"a" ), b"YQ==" )
@@ -110,15 +160,15 @@ def test_b64encode(self):
110160 b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
111161 b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==" )
112162 # Non-bytes
113- eq (base64 .standard_b64encode ( bytearray ( b'abcd' )), b'YWJjZA==' )
114- # Check if passing a str object raises an error
115- self .assertRaises ( TypeError , base64 .standard_b64encode , "" )
163+ self . check_other_types (base64 .standard_b64encode ,
164+ b'abcd' , b'YWJjZA==' )
165+ self .check_encode_type_errors ( base64 .standard_b64encode )
116166 # Test with 'URL safe' alternative characters
117167 eq (base64 .urlsafe_b64encode (b'\xd3 V\xbe o\xf7 \x1d ' ), b'01a-b_cd' )
118168 # Non-bytes
119- eq (base64 .urlsafe_b64encode ( bytearray ( b' \xd3 V \xbe o \xf7 \x1d ' )), b'01a-b_cd' )
120- # Check if passing a str object raises an error
121- self .assertRaises ( TypeError , base64 .urlsafe_b64encode , "" )
169+ self . check_other_types (base64 .urlsafe_b64encode ,
170+ b' \xd3 V \xbe o \xf7 \x1d ' , b'01a-b_cd' )
171+ self .check_encode_type_errors ( base64 .urlsafe_b64encode )
122172
123173 def test_b64decode (self ):
124174 eq = self .assertEqual
@@ -141,7 +191,8 @@ def test_b64decode(self):
141191 eq (base64 .b64decode (data ), res )
142192 eq (base64 .b64decode (data .decode ('ascii' )), res )
143193 # Non-bytes
144- eq (base64 .b64decode (bytearray (b"YWJj" )), b"abc" )
194+ self .check_other_types (base64 .b64decode , b"YWJj" , b"abc" )
195+ self .check_decode_type_errors (base64 .b64decode )
145196
146197 # Test with arbitrary alternative characters
147198 tests_altchars = {(b'01a*b$cd' , b'*$' ): b'\xd3 V\xbe o\xf7 \x1d ' ,
@@ -160,7 +211,8 @@ def test_b64decode(self):
160211 eq (base64 .standard_b64decode (data ), res )
161212 eq (base64 .standard_b64decode (data .decode ('ascii' )), res )
162213 # Non-bytes
163- eq (base64 .standard_b64decode (bytearray (b"YWJj" )), b"abc" )
214+ self .check_other_types (base64 .standard_b64decode , b"YWJj" , b"abc" )
215+ self .check_decode_type_errors (base64 .standard_b64decode )
164216
165217 # Test with 'URL safe' alternative characters
166218 tests_urlsafe = {b'01a-b_cd' : b'\xd3 V\xbe o\xf7 \x1d ' ,
@@ -170,7 +222,9 @@ def test_b64decode(self):
170222 eq (base64 .urlsafe_b64decode (data ), res )
171223 eq (base64 .urlsafe_b64decode (data .decode ('ascii' )), res )
172224 # Non-bytes
173- eq (base64 .urlsafe_b64decode (bytearray (b'01a-b_cd' )), b'\xd3 V\xbe o\xf7 \x1d ' )
225+ self .check_other_types (base64 .urlsafe_b64decode , b'01a-b_cd' ,
226+ b'\xd3 V\xbe o\xf7 \x1d ' )
227+ self .check_decode_type_errors (base64 .urlsafe_b64decode )
174228
175229 def test_b64decode_padding_error (self ):
176230 self .assertRaises (binascii .Error , base64 .b64decode , b'abc' )
@@ -205,8 +259,8 @@ def test_b32encode(self):
205259 eq (base64 .b32encode (b'abcd' ), b'MFRGGZA=' )
206260 eq (base64 .b32encode (b'abcde' ), b'MFRGGZDF' )
207261 # Non-bytes
208- eq (base64 .b32encode ( bytearray ( b'abcd' )) , b'MFRGGZA=' )
209- self .assertRaises ( TypeError , base64 .b32encode , "" )
262+ self . check_other_types (base64 .b32encode , b'abcd' , b'MFRGGZA=' )
263+ self .check_encode_type_errors ( base64 .b32encode )
210264
211265 def test_b32decode (self ):
212266 eq = self .assertEqual
@@ -222,7 +276,8 @@ def test_b32decode(self):
222276 eq (base64 .b32decode (data ), res )
223277 eq (base64 .b32decode (data .decode ('ascii' )), res )
224278 # Non-bytes
225- eq (base64 .b32decode (bytearray (b'MFRGG===' )), b'abc' )
279+ self .check_other_types (base64 .b32decode , b'MFRGG===' , b"abc" )
280+ self .check_decode_type_errors (base64 .b32decode )
226281
227282 def test_b32decode_casefold (self ):
228283 eq = self .assertEqual
@@ -277,8 +332,9 @@ def test_b16encode(self):
277332 eq (base64 .b16encode (b'\x01 \x02 \xab \xcd \xef ' ), b'0102ABCDEF' )
278333 eq (base64 .b16encode (b'\x00 ' ), b'00' )
279334 # Non-bytes
280- eq (base64 .b16encode (bytearray (b'\x01 \x02 \xab \xcd \xef ' )), b'0102ABCDEF' )
281- self .assertRaises (TypeError , base64 .b16encode , "" )
335+ self .check_other_types (base64 .b16encode , b'\x01 \x02 \xab \xcd \xef ' ,
336+ b'0102ABCDEF' )
337+ self .check_encode_type_errors (base64 .b16encode )
282338
283339 def test_b16decode (self ):
284340 eq = self .assertEqual
@@ -293,7 +349,15 @@ def test_b16decode(self):
293349 eq (base64 .b16decode (b'0102abcdef' , True ), b'\x01 \x02 \xab \xcd \xef ' )
294350 eq (base64 .b16decode ('0102abcdef' , True ), b'\x01 \x02 \xab \xcd \xef ' )
295351 # Non-bytes
296- eq (base64 .b16decode (bytearray (b"0102ABCDEF" )), b'\x01 \x02 \xab \xcd \xef ' )
352+ self .check_other_types (base64 .b16decode , b"0102ABCDEF" ,
353+ b'\x01 \x02 \xab \xcd \xef ' )
354+ self .check_decode_type_errors (base64 .b16decode )
355+ eq (base64 .b16decode (bytearray (b"0102abcdef" ), True ),
356+ b'\x01 \x02 \xab \xcd \xef ' )
357+ eq (base64 .b16decode (memoryview (b"0102abcdef" ), True ),
358+ b'\x01 \x02 \xab \xcd \xef ' )
359+ eq (base64 .b16decode (array ('B' , b"0102abcdef" ), True ),
360+ b'\x01 \x02 \xab \xcd \xef ' )
297361
298362 def test_decode_nonascii_str (self ):
299363 decode_funcs = (base64 .b64decode ,
0 commit comments