(root)/
Python-3.12.0/
Lib/
test/
test_base64.py
       1  import unittest
       2  import base64
       3  import binascii
       4  import os
       5  from array import array
       6  from test.support import os_helper
       7  from test.support import script_helper
       8  
       9  
      10  class ESC[4;38;5;81mLegacyBase64TestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      11  
      12      # Legacy API is not as permissive as the modern API
      13      def check_type_errors(self, f):
      14          self.assertRaises(TypeError, f, "")
      15          self.assertRaises(TypeError, f, [])
      16          multidimensional = memoryview(b"1234").cast('B', (2, 2))
      17          self.assertRaises(TypeError, f, multidimensional)
      18          int_data = memoryview(b"1234").cast('I')
      19          self.assertRaises(TypeError, f, int_data)
      20  
      21      def test_encodebytes(self):
      22          eq = self.assertEqual
      23          eq(base64.encodebytes(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=\n")
      24          eq(base64.encodebytes(b"a"), b"YQ==\n")
      25          eq(base64.encodebytes(b"ab"), b"YWI=\n")
      26          eq(base64.encodebytes(b"abc"), b"YWJj\n")
      27          eq(base64.encodebytes(b""), b"")
      28          eq(base64.encodebytes(b"abcdefghijklmnopqrstuvwxyz"
      29                                 b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      30                                 b"0123456789!@#0^&*();:<>,. []{}"),
      31             b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
      32             b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
      33             b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n")
      34          eq(base64.encodebytes(b"Aladdin:open sesame"),
      35                                b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n")
      36          # Non-bytes
      37          eq(base64.encodebytes(bytearray(b'abc')), b'YWJj\n')
      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)
      41  
      42      def test_decodebytes(self):
      43          eq = self.assertEqual
      44          eq(base64.decodebytes(b"d3d3LnB5dGhvbi5vcmc=\n"), b"www.python.org")
      45          eq(base64.decodebytes(b"YQ==\n"), b"a")
      46          eq(base64.decodebytes(b"YWI=\n"), b"ab")
      47          eq(base64.decodebytes(b"YWJj\n"), b"abc")
      48          eq(base64.decodebytes(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
      49                                 b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
      50                                 b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n"),
      51             b"abcdefghijklmnopqrstuvwxyz"
      52             b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      53             b"0123456789!@#0^&*();:<>,. []{}")
      54          eq(base64.decodebytes(b''), b'')
      55          eq(base64.decodebytes(b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n"),
      56                                b"Aladdin:open sesame")
      57          # Non-bytes
      58          eq(base64.decodebytes(bytearray(b'YWJj\n')), b'abc')
      59          eq(base64.decodebytes(memoryview(b'YWJj\n')), b'abc')
      60          eq(base64.decodebytes(array('B', b'YWJj\n')), b'abc')
      61          self.check_type_errors(base64.decodebytes)
      62  
      63      def test_encode(self):
      64          eq = self.assertEqual
      65          from io import BytesIO, StringIO
      66          infp = BytesIO(b'abcdefghijklmnopqrstuvwxyz'
      67                         b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
      68                         b'0123456789!@#0^&*();:<>,. []{}')
      69          outfp = BytesIO()
      70          base64.encode(infp, outfp)
      71          eq(outfp.getvalue(),
      72             b'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE'
      73             b'RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT'
      74             b'Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n')
      75          # Non-binary files
      76          self.assertRaises(TypeError, base64.encode, StringIO('abc'), BytesIO())
      77          self.assertRaises(TypeError, base64.encode, BytesIO(b'abc'), StringIO())
      78          self.assertRaises(TypeError, base64.encode, StringIO('abc'), StringIO())
      79  
      80      def test_decode(self):
      81          from io import BytesIO, StringIO
      82          infp = BytesIO(b'd3d3LnB5dGhvbi5vcmc=')
      83          outfp = BytesIO()
      84          base64.decode(infp, outfp)
      85          self.assertEqual(outfp.getvalue(), b'www.python.org')
      86          # Non-binary files
      87          self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), BytesIO())
      88          self.assertRaises(TypeError, base64.encode, BytesIO(b'YWJj\n'), StringIO())
      89          self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), StringIO())
      90  
      91  
      92  class ESC[4;38;5;81mBaseXYTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      93  
      94      # Modern API completely ignores exported dimension and format data and
      95      # treats any buffer as a stream of bytes
      96      def check_encode_type_errors(self, f):
      97          self.assertRaises(TypeError, f, "")
      98          self.assertRaises(TypeError, f, [])
      99  
     100      def check_decode_type_errors(self, f):
     101          self.assertRaises(TypeError, f, [])
     102  
     103      def check_other_types(self, f, bytes_data, expected):
     104          eq = self.assertEqual
     105          b = bytearray(bytes_data)
     106          eq(f(b), expected)
     107          # The bytearray wasn't mutated
     108          eq(b, bytes_data)
     109          eq(f(memoryview(bytes_data)), expected)
     110          eq(f(array('B', bytes_data)), expected)
     111          # XXX why is b64encode hardcoded here?
     112          self.check_nonbyte_element_format(base64.b64encode, bytes_data)
     113          self.check_multidimensional(base64.b64encode, bytes_data)
     114  
     115      def check_multidimensional(self, f, data):
     116          padding = b"\x00" if len(data) % 2 else b""
     117          bytes_data = data + padding # Make sure cast works
     118          shape = (len(bytes_data) // 2, 2)
     119          multidimensional = memoryview(bytes_data).cast('B', shape)
     120          self.assertEqual(f(multidimensional), f(bytes_data))
     121  
     122      def check_nonbyte_element_format(self, f, data):
     123          padding = b"\x00" * ((4 - len(data)) % 4)
     124          bytes_data = data + padding # Make sure cast works
     125          int_data = memoryview(bytes_data).cast('I')
     126          self.assertEqual(f(int_data), f(bytes_data))
     127  
     128  
     129      def test_b64encode(self):
     130          eq = self.assertEqual
     131          # Test default alphabet
     132          eq(base64.b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=")
     133          eq(base64.b64encode(b'\x00'), b'AA==')
     134          eq(base64.b64encode(b"a"), b"YQ==")
     135          eq(base64.b64encode(b"ab"), b"YWI=")
     136          eq(base64.b64encode(b"abc"), b"YWJj")
     137          eq(base64.b64encode(b""), b"")
     138          eq(base64.b64encode(b"abcdefghijklmnopqrstuvwxyz"
     139                              b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     140                              b"0123456789!@#0^&*();:<>,. []{}"),
     141             b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
     142             b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
     143             b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==")
     144          # Test with arbitrary alternative characters
     145          eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=b'*$'), b'01a*b$cd')
     146          eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=bytearray(b'*$')),
     147             b'01a*b$cd')
     148          eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=memoryview(b'*$')),
     149             b'01a*b$cd')
     150          eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=array('B', b'*$')),
     151             b'01a*b$cd')
     152          # Non-bytes
     153          self.check_other_types(base64.b64encode, b'abcd', b'YWJjZA==')
     154          self.check_encode_type_errors(base64.b64encode)
     155          self.assertRaises(TypeError, base64.b64encode, b"", altchars="*$")
     156          # Test standard alphabet
     157          eq(base64.standard_b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=")
     158          eq(base64.standard_b64encode(b"a"), b"YQ==")
     159          eq(base64.standard_b64encode(b"ab"), b"YWI=")
     160          eq(base64.standard_b64encode(b"abc"), b"YWJj")
     161          eq(base64.standard_b64encode(b""), b"")
     162          eq(base64.standard_b64encode(b"abcdefghijklmnopqrstuvwxyz"
     163                                       b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     164                                       b"0123456789!@#0^&*();:<>,. []{}"),
     165             b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
     166             b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
     167             b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==")
     168          # Non-bytes
     169          self.check_other_types(base64.standard_b64encode,
     170                                 b'abcd', b'YWJjZA==')
     171          self.check_encode_type_errors(base64.standard_b64encode)
     172          # Test with 'URL safe' alternative characters
     173          eq(base64.urlsafe_b64encode(b'\xd3V\xbeo\xf7\x1d'), b'01a-b_cd')
     174          # Non-bytes
     175          self.check_other_types(base64.urlsafe_b64encode,
     176                                 b'\xd3V\xbeo\xf7\x1d', b'01a-b_cd')
     177          self.check_encode_type_errors(base64.urlsafe_b64encode)
     178  
     179      def test_b64decode(self):
     180          eq = self.assertEqual
     181  
     182          tests = {b"d3d3LnB5dGhvbi5vcmc=": b"www.python.org",
     183                   b'AA==': b'\x00',
     184                   b"YQ==": b"a",
     185                   b"YWI=": b"ab",
     186                   b"YWJj": b"abc",
     187                   b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
     188                   b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
     189                   b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==":
     190  
     191                   b"abcdefghijklmnopqrstuvwxyz"
     192                   b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     193                   b"0123456789!@#0^&*();:<>,. []{}",
     194                   b'': b'',
     195                   }
     196          for data, res in tests.items():
     197              eq(base64.b64decode(data), res)
     198              eq(base64.b64decode(data.decode('ascii')), res)
     199          # Non-bytes
     200          self.check_other_types(base64.b64decode, b"YWJj", b"abc")
     201          self.check_decode_type_errors(base64.b64decode)
     202  
     203          # Test with arbitrary alternative characters
     204          tests_altchars = {(b'01a*b$cd', b'*$'): b'\xd3V\xbeo\xf7\x1d',
     205                            }
     206          for (data, altchars), res in tests_altchars.items():
     207              data_str = data.decode('ascii')
     208              altchars_str = altchars.decode('ascii')
     209  
     210              eq(base64.b64decode(data, altchars=altchars), res)
     211              eq(base64.b64decode(data_str, altchars=altchars), res)
     212              eq(base64.b64decode(data, altchars=altchars_str), res)
     213              eq(base64.b64decode(data_str, altchars=altchars_str), res)
     214  
     215          # Test standard alphabet
     216          for data, res in tests.items():
     217              eq(base64.standard_b64decode(data), res)
     218              eq(base64.standard_b64decode(data.decode('ascii')), res)
     219          # Non-bytes
     220          self.check_other_types(base64.standard_b64decode, b"YWJj", b"abc")
     221          self.check_decode_type_errors(base64.standard_b64decode)
     222  
     223          # Test with 'URL safe' alternative characters
     224          tests_urlsafe = {b'01a-b_cd': b'\xd3V\xbeo\xf7\x1d',
     225                           b'': b'',
     226                           }
     227          for data, res in tests_urlsafe.items():
     228              eq(base64.urlsafe_b64decode(data), res)
     229              eq(base64.urlsafe_b64decode(data.decode('ascii')), res)
     230          # Non-bytes
     231          self.check_other_types(base64.urlsafe_b64decode, b'01a-b_cd',
     232                                 b'\xd3V\xbeo\xf7\x1d')
     233          self.check_decode_type_errors(base64.urlsafe_b64decode)
     234  
     235      def test_b64decode_padding_error(self):
     236          self.assertRaises(binascii.Error, base64.b64decode, b'abc')
     237          self.assertRaises(binascii.Error, base64.b64decode, 'abc')
     238  
     239      def test_b64decode_invalid_chars(self):
     240          # issue 1466065: Test some invalid characters.
     241          tests = ((b'%3d==', b'\xdd'),
     242                   (b'$3d==', b'\xdd'),
     243                   (b'[==', b''),
     244                   (b'YW]3=', b'am'),
     245                   (b'3{d==', b'\xdd'),
     246                   (b'3d}==', b'\xdd'),
     247                   (b'@@', b''),
     248                   (b'!', b''),
     249                   (b"YWJj\n", b"abc"),
     250                   (b'YWJj\nYWI=', b'abcab'))
     251          funcs = (
     252              base64.b64decode,
     253              base64.standard_b64decode,
     254              base64.urlsafe_b64decode,
     255          )
     256          for bstr, res in tests:
     257              for func in funcs:
     258                  with self.subTest(bstr=bstr, func=func):
     259                      self.assertEqual(func(bstr), res)
     260                      self.assertEqual(func(bstr.decode('ascii')), res)
     261              with self.assertRaises(binascii.Error):
     262                  base64.b64decode(bstr, validate=True)
     263              with self.assertRaises(binascii.Error):
     264                  base64.b64decode(bstr.decode('ascii'), validate=True)
     265  
     266          # Normal alphabet characters not discarded when alternative given
     267          res = b'\xFB\xEF\xBE\xFF\xFF\xFF'
     268          self.assertEqual(base64.b64decode(b'++[[//]]', b'[]'), res)
     269          self.assertEqual(base64.urlsafe_b64decode(b'++--//__'), res)
     270  
     271      def test_b32encode(self):
     272          eq = self.assertEqual
     273          eq(base64.b32encode(b''), b'')
     274          eq(base64.b32encode(b'\x00'), b'AA======')
     275          eq(base64.b32encode(b'a'), b'ME======')
     276          eq(base64.b32encode(b'ab'), b'MFRA====')
     277          eq(base64.b32encode(b'abc'), b'MFRGG===')
     278          eq(base64.b32encode(b'abcd'), b'MFRGGZA=')
     279          eq(base64.b32encode(b'abcde'), b'MFRGGZDF')
     280          # Non-bytes
     281          self.check_other_types(base64.b32encode, b'abcd', b'MFRGGZA=')
     282          self.check_encode_type_errors(base64.b32encode)
     283  
     284      def test_b32decode(self):
     285          eq = self.assertEqual
     286          tests = {b'': b'',
     287                   b'AA======': b'\x00',
     288                   b'ME======': b'a',
     289                   b'MFRA====': b'ab',
     290                   b'MFRGG===': b'abc',
     291                   b'MFRGGZA=': b'abcd',
     292                   b'MFRGGZDF': b'abcde',
     293                   }
     294          for data, res in tests.items():
     295              eq(base64.b32decode(data), res)
     296              eq(base64.b32decode(data.decode('ascii')), res)
     297          # Non-bytes
     298          self.check_other_types(base64.b32decode, b'MFRGG===', b"abc")
     299          self.check_decode_type_errors(base64.b32decode)
     300  
     301      def test_b32decode_casefold(self):
     302          eq = self.assertEqual
     303          tests = {b'': b'',
     304                   b'ME======': b'a',
     305                   b'MFRA====': b'ab',
     306                   b'MFRGG===': b'abc',
     307                   b'MFRGGZA=': b'abcd',
     308                   b'MFRGGZDF': b'abcde',
     309                   # Lower cases
     310                   b'me======': b'a',
     311                   b'mfra====': b'ab',
     312                   b'mfrgg===': b'abc',
     313                   b'mfrggza=': b'abcd',
     314                   b'mfrggzdf': b'abcde',
     315                   }
     316  
     317          for data, res in tests.items():
     318              eq(base64.b32decode(data, True), res)
     319              eq(base64.b32decode(data.decode('ascii'), True), res)
     320  
     321          self.assertRaises(binascii.Error, base64.b32decode, b'me======')
     322          self.assertRaises(binascii.Error, base64.b32decode, 'me======')
     323  
     324          # Mapping zero and one
     325          eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe')
     326          eq(base64.b32decode('MLO23456'), b'b\xdd\xad\xf3\xbe')
     327  
     328          map_tests = {(b'M1023456', b'L'): b'b\xdd\xad\xf3\xbe',
     329                       (b'M1023456', b'I'): b'b\x1d\xad\xf3\xbe',
     330                       }
     331          for (data, map01), res in map_tests.items():
     332              data_str = data.decode('ascii')
     333              map01_str = map01.decode('ascii')
     334  
     335              eq(base64.b32decode(data, map01=map01), res)
     336              eq(base64.b32decode(data_str, map01=map01), res)
     337              eq(base64.b32decode(data, map01=map01_str), res)
     338              eq(base64.b32decode(data_str, map01=map01_str), res)
     339              self.assertRaises(binascii.Error, base64.b32decode, data)
     340              self.assertRaises(binascii.Error, base64.b32decode, data_str)
     341  
     342      def test_b32decode_error(self):
     343          tests = [b'abc', b'ABCDEF==', b'==ABCDEF']
     344          prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
     345          for i in range(0, 17):
     346              if i:
     347                  tests.append(b'='*i)
     348              for prefix in prefixes:
     349                  if len(prefix) + i != 8:
     350                      tests.append(prefix + b'='*i)
     351          for data in tests:
     352              with self.subTest(data=data):
     353                  with self.assertRaises(binascii.Error):
     354                      base64.b32decode(data)
     355                  with self.assertRaises(binascii.Error):
     356                      base64.b32decode(data.decode('ascii'))
     357  
     358      def test_b32hexencode(self):
     359          test_cases = [
     360              # to_encode, expected
     361              (b'',      b''),
     362              (b'\x00',  b'00======'),
     363              (b'a',     b'C4======'),
     364              (b'ab',    b'C5H0===='),
     365              (b'abc',   b'C5H66==='),
     366              (b'abcd',  b'C5H66P0='),
     367              (b'abcde', b'C5H66P35'),
     368          ]
     369          for to_encode, expected in test_cases:
     370              with self.subTest(to_decode=to_encode):
     371                  self.assertEqual(base64.b32hexencode(to_encode), expected)
     372  
     373      def test_b32hexencode_other_types(self):
     374          self.check_other_types(base64.b32hexencode, b'abcd', b'C5H66P0=')
     375          self.check_encode_type_errors(base64.b32hexencode)
     376  
     377      def test_b32hexdecode(self):
     378          test_cases = [
     379              # to_decode, expected, casefold
     380              (b'',         b'',      False),
     381              (b'00======', b'\x00',  False),
     382              (b'C4======', b'a',     False),
     383              (b'C5H0====', b'ab',    False),
     384              (b'C5H66===', b'abc',   False),
     385              (b'C5H66P0=', b'abcd',  False),
     386              (b'C5H66P35', b'abcde', False),
     387              (b'',         b'',      True),
     388              (b'00======', b'\x00',  True),
     389              (b'C4======', b'a',     True),
     390              (b'C5H0====', b'ab',    True),
     391              (b'C5H66===', b'abc',   True),
     392              (b'C5H66P0=', b'abcd',  True),
     393              (b'C5H66P35', b'abcde', True),
     394              (b'c4======', b'a',     True),
     395              (b'c5h0====', b'ab',    True),
     396              (b'c5h66===', b'abc',   True),
     397              (b'c5h66p0=', b'abcd',  True),
     398              (b'c5h66p35', b'abcde', True),
     399          ]
     400          for to_decode, expected, casefold in test_cases:
     401              with self.subTest(to_decode=to_decode, casefold=casefold):
     402                  self.assertEqual(base64.b32hexdecode(to_decode, casefold),
     403                                   expected)
     404                  self.assertEqual(base64.b32hexdecode(to_decode.decode('ascii'),
     405                                   casefold), expected)
     406  
     407      def test_b32hexdecode_other_types(self):
     408          self.check_other_types(base64.b32hexdecode, b'C5H66===', b'abc')
     409          self.check_decode_type_errors(base64.b32hexdecode)
     410  
     411      def test_b32hexdecode_error(self):
     412          tests = [b'abc', b'ABCDEF==', b'==ABCDEF', b'c4======']
     413          prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
     414          for i in range(0, 17):
     415              if i:
     416                  tests.append(b'='*i)
     417              for prefix in prefixes:
     418                  if len(prefix) + i != 8:
     419                      tests.append(prefix + b'='*i)
     420          for data in tests:
     421              with self.subTest(to_decode=data):
     422                  with self.assertRaises(binascii.Error):
     423                      base64.b32hexdecode(data)
     424                  with self.assertRaises(binascii.Error):
     425                      base64.b32hexdecode(data.decode('ascii'))
     426  
     427  
     428      def test_b16encode(self):
     429          eq = self.assertEqual
     430          eq(base64.b16encode(b'\x01\x02\xab\xcd\xef'), b'0102ABCDEF')
     431          eq(base64.b16encode(b'\x00'), b'00')
     432          # Non-bytes
     433          self.check_other_types(base64.b16encode, b'\x01\x02\xab\xcd\xef',
     434                                 b'0102ABCDEF')
     435          self.check_encode_type_errors(base64.b16encode)
     436  
     437      def test_b16decode(self):
     438          eq = self.assertEqual
     439          eq(base64.b16decode(b'0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
     440          eq(base64.b16decode('0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
     441          eq(base64.b16decode(b'00'), b'\x00')
     442          eq(base64.b16decode('00'), b'\x00')
     443          # Lower case is not allowed without a flag
     444          self.assertRaises(binascii.Error, base64.b16decode, b'0102abcdef')
     445          self.assertRaises(binascii.Error, base64.b16decode, '0102abcdef')
     446          # Case fold
     447          eq(base64.b16decode(b'0102abcdef', True), b'\x01\x02\xab\xcd\xef')
     448          eq(base64.b16decode('0102abcdef', True), b'\x01\x02\xab\xcd\xef')
     449          # Non-bytes
     450          self.check_other_types(base64.b16decode, b"0102ABCDEF",
     451                                 b'\x01\x02\xab\xcd\xef')
     452          self.check_decode_type_errors(base64.b16decode)
     453          eq(base64.b16decode(bytearray(b"0102abcdef"), True),
     454             b'\x01\x02\xab\xcd\xef')
     455          eq(base64.b16decode(memoryview(b"0102abcdef"), True),
     456             b'\x01\x02\xab\xcd\xef')
     457          eq(base64.b16decode(array('B', b"0102abcdef"), True),
     458             b'\x01\x02\xab\xcd\xef')
     459          # Non-alphabet characters
     460          self.assertRaises(binascii.Error, base64.b16decode, '0102AG')
     461          # Incorrect "padding"
     462          self.assertRaises(binascii.Error, base64.b16decode, '010')
     463  
     464      def test_a85encode(self):
     465          eq = self.assertEqual
     466  
     467          tests = {
     468              b'': b'',
     469              b"www.python.org": b'GB\\6`E-ZP=Df.1GEb>',
     470              bytes(range(255)): b"""!!*-'"9eu7#RLhG$k3[W&.oNg'GVB"(`=52*$$"""
     471                 b"""(B+<_pR,UFcb-n-Vr/1iJ-0JP==1c70M3&s#]4?Ykm5X@_(6q'R884cE"""
     472                 b"""H9MJ8X:f1+h<)lt#=BSg3>[:ZC?t!MSA7]@cBPD3sCi+'.E,fo>FEMbN"""
     473                 b"""G^4U^I!pHnJ:W<)KS>/9Ll%"IN/`jYOHG]iPa.Q$R$jD4S=Q7DTV8*TU"""
     474                 b"""nsrdW2ZetXKAY/Yd(L?['d?O\\@K2_]Y2%o^qmn*`5Ta:aN;TJbg"GZd"""
     475                 b"""*^:jeCE.%f\\,!5gtgiEi8N\\UjQ5OekiqBum-X60nF?)@o_%qPq"ad`"""
     476                 b"""r;HT""",
     477              b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
     478                  b"0123456789!@#0^&*();:<>,. []{}":
     479                  b'@:E_WAS,RgBkhF"D/O92EH6,BF`qtRH$VbC6UX@47n?3D92&&T'
     480                  b":Jand;cHat='/U/0JP==1c70M3&r-I,;<FN.OZ`-3]oSW/g+A(H[P",
     481              b"no padding..": b'DJpY:@:Wn_DJ(RS',
     482              b"zero compression\0\0\0\0": b'H=_,8+Cf>,E,oN2F(oQ1z',
     483              b"zero compression\0\0\0": b'H=_,8+Cf>,E,oN2F(oQ1!!!!',
     484              b"Boundary:\0\0\0\0": b'6>q!aA79M(3WK-[!!',
     485              b"Space compr:    ": b';fH/TAKYK$D/aMV+<VdL',
     486              b'\xff': b'rr',
     487              b'\xff'*2: b's8N',
     488              b'\xff'*3: b's8W*',
     489              b'\xff'*4: b's8W-!',
     490              }
     491  
     492          for data, res in tests.items():
     493              eq(base64.a85encode(data), res, data)
     494              eq(base64.a85encode(data, adobe=False), res, data)
     495              eq(base64.a85encode(data, adobe=True), b'<~' + res + b'~>', data)
     496  
     497          self.check_other_types(base64.a85encode, b"www.python.org",
     498                                 b'GB\\6`E-ZP=Df.1GEb>')
     499  
     500          self.assertRaises(TypeError, base64.a85encode, "")
     501  
     502          eq(base64.a85encode(b"www.python.org", wrapcol=7, adobe=False),
     503             b'GB\\6`E-\nZP=Df.1\nGEb>')
     504          eq(base64.a85encode(b"\0\0\0\0www.python.org", wrapcol=7, adobe=False),
     505             b'zGB\\6`E\n-ZP=Df.\n1GEb>')
     506          eq(base64.a85encode(b"www.python.org", wrapcol=7, adobe=True),
     507             b'<~GB\\6`\nE-ZP=Df\n.1GEb>\n~>')
     508  
     509          eq(base64.a85encode(b' '*8, foldspaces=True, adobe=False), b'yy')
     510          eq(base64.a85encode(b' '*7, foldspaces=True, adobe=False), b'y+<Vd')
     511          eq(base64.a85encode(b' '*6, foldspaces=True, adobe=False), b'y+<U')
     512          eq(base64.a85encode(b' '*5, foldspaces=True, adobe=False), b'y+9')
     513  
     514      def test_b85encode(self):
     515          eq = self.assertEqual
     516  
     517          tests = {
     518              b'': b'',
     519              b'www.python.org': b'cXxL#aCvlSZ*DGca%T',
     520              bytes(range(255)): b"""009C61O)~M2nh-c3=Iws5D^j+6crX17#SKH9337X"""
     521                  b"""AR!_nBqb&%C@Cr{EG;fCFflSSG&MFiI5|2yJUu=?KtV!7L`6nNNJ&ad"""
     522                  b"""OifNtP*GA-R8>}2SXo+ITwPvYU}0ioWMyV&XlZI|Y;A6DaB*^Tbai%j"""
     523                  b"""czJqze0_d@fPsR8goTEOh>41ejE#<ukdcy;l$Dm3n3<ZJoSmMZprN9p"""
     524                  b"""q@|{(sHv)}tgWuEu(7hUw6(UkxVgH!yuH4^z`?@9#Kp$P$jQpf%+1cv"""
     525                  b"""(9zP<)YaD4*xB0K+}+;a;Njxq<mKk)=;`X~?CtLF@bU8V^!4`l`1$(#"""
     526                  b"""{Qdp""",
     527              b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
     528                  b"""0123456789!@#0^&*();:<>,. []{}""":
     529                  b"""VPa!sWoBn+X=-b1ZEkOHadLBXb#`}nd3r%YLqtVJM@UIZOH55pPf$@("""
     530                  b"""Q&d$}S6EqEFflSSG&MFiI5{CeBQRbjDkv#CIy^osE+AW7dwl""",
     531              b'no padding..': b'Zf_uPVPs@!Zf7no',
     532              b'zero compression\x00\x00\x00\x00': b'dS!BNAY*TBaB^jHb7^mG00000',
     533              b'zero compression\x00\x00\x00': b'dS!BNAY*TBaB^jHb7^mG0000',
     534              b"""Boundary:\x00\x00\x00\x00""": b"""LT`0$WMOi7IsgCw00""",
     535              b'Space compr:    ': b'Q*dEpWgug3ZE$irARr(h',
     536              b'\xff': b'{{',
     537              b'\xff'*2: b'|Nj',
     538              b'\xff'*3: b'|Ns9',
     539              b'\xff'*4: b'|NsC0',
     540          }
     541  
     542          for data, res in tests.items():
     543              eq(base64.b85encode(data), res)
     544  
     545          self.check_other_types(base64.b85encode, b"www.python.org",
     546                                 b'cXxL#aCvlSZ*DGca%T')
     547  
     548      def test_a85decode(self):
     549          eq = self.assertEqual
     550  
     551          tests = {
     552              b'': b'',
     553              b'GB\\6`E-ZP=Df.1GEb>': b'www.python.org',
     554              b"""! ! * -'"\n\t\t9eu\r\n7#  RL\vhG$k3[W&.oNg'GVB"(`=52*$$"""
     555                 b"""(B+<_pR,UFcb-n-Vr/1iJ-0JP==1c70M3&s#]4?Ykm5X@_(6q'R884cE"""
     556                 b"""H9MJ8X:f1+h<)lt#=BSg3>[:ZC?t!MSA7]@cBPD3sCi+'.E,fo>FEMbN"""
     557                 b"""G^4U^I!pHnJ:W<)KS>/9Ll%"IN/`jYOHG]iPa.Q$R$jD4S=Q7DTV8*TU"""
     558                 b"""nsrdW2ZetXKAY/Yd(L?['d?O\\@K2_]Y2%o^qmn*`5Ta:aN;TJbg"GZd"""
     559                 b"""*^:jeCE.%f\\,!5gtgiEi8N\\UjQ5OekiqBum-X60nF?)@o_%qPq"ad`"""
     560                 b"""r;HT""": bytes(range(255)),
     561              b"""@:E_WAS,RgBkhF"D/O92EH6,BF`qtRH$VbC6UX@47n?3D92&&T:Jand;c"""
     562                  b"""Hat='/U/0JP==1c70M3&r-I,;<FN.OZ`-3]oSW/g+A(H[P""":
     563                  b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234'
     564                  b'56789!@#0^&*();:<>,. []{}',
     565              b'DJpY:@:Wn_DJ(RS': b'no padding..',
     566              b'H=_,8+Cf>,E,oN2F(oQ1z': b'zero compression\x00\x00\x00\x00',
     567              b'H=_,8+Cf>,E,oN2F(oQ1!!!!': b'zero compression\x00\x00\x00',
     568              b'6>q!aA79M(3WK-[!!': b"Boundary:\x00\x00\x00\x00",
     569              b';fH/TAKYK$D/aMV+<VdL': b'Space compr:    ',
     570              b'rr': b'\xff',
     571              b's8N': b'\xff'*2,
     572              b's8W*': b'\xff'*3,
     573              b's8W-!': b'\xff'*4,
     574              }
     575  
     576          for data, res in tests.items():
     577              eq(base64.a85decode(data), res, data)
     578              eq(base64.a85decode(data, adobe=False), res, data)
     579              eq(base64.a85decode(data.decode("ascii"), adobe=False), res, data)
     580              eq(base64.a85decode(b'<~' + data + b'~>', adobe=True), res, data)
     581              eq(base64.a85decode(data + b'~>', adobe=True), res, data)
     582              eq(base64.a85decode('<~%s~>' % data.decode("ascii"), adobe=True),
     583                 res, data)
     584  
     585          eq(base64.a85decode(b'yy', foldspaces=True, adobe=False), b' '*8)
     586          eq(base64.a85decode(b'y+<Vd', foldspaces=True, adobe=False), b' '*7)
     587          eq(base64.a85decode(b'y+<U', foldspaces=True, adobe=False), b' '*6)
     588          eq(base64.a85decode(b'y+9', foldspaces=True, adobe=False), b' '*5)
     589  
     590          self.check_other_types(base64.a85decode, b'GB\\6`E-ZP=Df.1GEb>',
     591                                 b"www.python.org")
     592  
     593      def test_b85decode(self):
     594          eq = self.assertEqual
     595  
     596          tests = {
     597              b'': b'',
     598              b'cXxL#aCvlSZ*DGca%T': b'www.python.org',
     599              b"""009C61O)~M2nh-c3=Iws5D^j+6crX17#SKH9337X"""
     600                  b"""AR!_nBqb&%C@Cr{EG;fCFflSSG&MFiI5|2yJUu=?KtV!7L`6nNNJ&ad"""
     601                  b"""OifNtP*GA-R8>}2SXo+ITwPvYU}0ioWMyV&XlZI|Y;A6DaB*^Tbai%j"""
     602                  b"""czJqze0_d@fPsR8goTEOh>41ejE#<ukdcy;l$Dm3n3<ZJoSmMZprN9p"""
     603                  b"""q@|{(sHv)}tgWuEu(7hUw6(UkxVgH!yuH4^z`?@9#Kp$P$jQpf%+1cv"""
     604                  b"""(9zP<)YaD4*xB0K+}+;a;Njxq<mKk)=;`X~?CtLF@bU8V^!4`l`1$(#"""
     605                  b"""{Qdp""": bytes(range(255)),
     606              b"""VPa!sWoBn+X=-b1ZEkOHadLBXb#`}nd3r%YLqtVJM@UIZOH55pPf$@("""
     607                  b"""Q&d$}S6EqEFflSSG&MFiI5{CeBQRbjDkv#CIy^osE+AW7dwl""":
     608                  b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
     609                  b"""0123456789!@#0^&*();:<>,. []{}""",
     610              b'Zf_uPVPs@!Zf7no': b'no padding..',
     611              b'dS!BNAY*TBaB^jHb7^mG00000': b'zero compression\x00\x00\x00\x00',
     612              b'dS!BNAY*TBaB^jHb7^mG0000': b'zero compression\x00\x00\x00',
     613              b"""LT`0$WMOi7IsgCw00""": b"""Boundary:\x00\x00\x00\x00""",
     614              b'Q*dEpWgug3ZE$irARr(h': b'Space compr:    ',
     615              b'{{': b'\xff',
     616              b'|Nj': b'\xff'*2,
     617              b'|Ns9': b'\xff'*3,
     618              b'|NsC0': b'\xff'*4,
     619          }
     620  
     621          for data, res in tests.items():
     622              eq(base64.b85decode(data), res)
     623              eq(base64.b85decode(data.decode("ascii")), res)
     624  
     625          self.check_other_types(base64.b85decode, b'cXxL#aCvlSZ*DGca%T',
     626                                 b"www.python.org")
     627  
     628      def test_a85_padding(self):
     629          eq = self.assertEqual
     630  
     631          eq(base64.a85encode(b"x", pad=True), b'GQ7^D')
     632          eq(base64.a85encode(b"xx", pad=True), b"G^'2g")
     633          eq(base64.a85encode(b"xxx", pad=True), b'G^+H5')
     634          eq(base64.a85encode(b"xxxx", pad=True), b'G^+IX')
     635          eq(base64.a85encode(b"xxxxx", pad=True), b'G^+IXGQ7^D')
     636  
     637          eq(base64.a85decode(b'GQ7^D'), b"x\x00\x00\x00")
     638          eq(base64.a85decode(b"G^'2g"), b"xx\x00\x00")
     639          eq(base64.a85decode(b'G^+H5'), b"xxx\x00")
     640          eq(base64.a85decode(b'G^+IX'), b"xxxx")
     641          eq(base64.a85decode(b'G^+IXGQ7^D'), b"xxxxx\x00\x00\x00")
     642  
     643      def test_b85_padding(self):
     644          eq = self.assertEqual
     645  
     646          eq(base64.b85encode(b"x", pad=True), b'cmMzZ')
     647          eq(base64.b85encode(b"xx", pad=True), b'cz6H+')
     648          eq(base64.b85encode(b"xxx", pad=True), b'czAdK')
     649          eq(base64.b85encode(b"xxxx", pad=True), b'czAet')
     650          eq(base64.b85encode(b"xxxxx", pad=True), b'czAetcmMzZ')
     651  
     652          eq(base64.b85decode(b'cmMzZ'), b"x\x00\x00\x00")
     653          eq(base64.b85decode(b'cz6H+'), b"xx\x00\x00")
     654          eq(base64.b85decode(b'czAdK'), b"xxx\x00")
     655          eq(base64.b85decode(b'czAet'), b"xxxx")
     656          eq(base64.b85decode(b'czAetcmMzZ'), b"xxxxx\x00\x00\x00")
     657  
     658      def test_a85decode_errors(self):
     659          illegal = (set(range(32)) | set(range(118, 256))) - set(b' \t\n\r\v')
     660          for c in illegal:
     661              with self.assertRaises(ValueError, msg=bytes([c])):
     662                  base64.a85decode(b'!!!!' + bytes([c]))
     663              with self.assertRaises(ValueError, msg=bytes([c])):
     664                  base64.a85decode(b'!!!!' + bytes([c]), adobe=False)
     665              with self.assertRaises(ValueError, msg=bytes([c])):
     666                  base64.a85decode(b'<~!!!!' + bytes([c]) + b'~>', adobe=True)
     667  
     668          self.assertRaises(ValueError, base64.a85decode,
     669                                        b"malformed", adobe=True)
     670          self.assertRaises(ValueError, base64.a85decode,
     671                                        b"<~still malformed", adobe=True)
     672  
     673          # With adobe=False (the default), Adobe framing markers are disallowed
     674          self.assertRaises(ValueError, base64.a85decode,
     675                                        b"<~~>")
     676          self.assertRaises(ValueError, base64.a85decode,
     677                                        b"<~~>", adobe=False)
     678          base64.a85decode(b"<~~>", adobe=True)  # sanity check
     679  
     680          self.assertRaises(ValueError, base64.a85decode,
     681                                        b"abcx", adobe=False)
     682          self.assertRaises(ValueError, base64.a85decode,
     683                                        b"abcdey", adobe=False)
     684          self.assertRaises(ValueError, base64.a85decode,
     685                                        b"a b\nc", adobe=False, ignorechars=b"")
     686  
     687          self.assertRaises(ValueError, base64.a85decode, b's', adobe=False)
     688          self.assertRaises(ValueError, base64.a85decode, b's8', adobe=False)
     689          self.assertRaises(ValueError, base64.a85decode, b's8W', adobe=False)
     690          self.assertRaises(ValueError, base64.a85decode, b's8W-', adobe=False)
     691          self.assertRaises(ValueError, base64.a85decode, b's8W-"', adobe=False)
     692  
     693      def test_b85decode_errors(self):
     694          illegal = list(range(33)) + \
     695                    list(b'"\',./:[\\]') + \
     696                    list(range(128, 256))
     697          for c in illegal:
     698              with self.assertRaises(ValueError, msg=bytes([c])):
     699                  base64.b85decode(b'0000' + bytes([c]))
     700  
     701          self.assertRaises(ValueError, base64.b85decode, b'|')
     702          self.assertRaises(ValueError, base64.b85decode, b'|N')
     703          self.assertRaises(ValueError, base64.b85decode, b'|Ns')
     704          self.assertRaises(ValueError, base64.b85decode, b'|NsC')
     705          self.assertRaises(ValueError, base64.b85decode, b'|NsC1')
     706  
     707      def test_decode_nonascii_str(self):
     708          decode_funcs = (base64.b64decode,
     709                          base64.standard_b64decode,
     710                          base64.urlsafe_b64decode,
     711                          base64.b32decode,
     712                          base64.b16decode,
     713                          base64.b85decode,
     714                          base64.a85decode)
     715          for f in decode_funcs:
     716              self.assertRaises(ValueError, f, 'with non-ascii \xcb')
     717  
     718      def test_ErrorHeritage(self):
     719          self.assertTrue(issubclass(binascii.Error, ValueError))
     720  
     721      def test_RFC4648_test_cases(self):
     722          # test cases from RFC 4648 section 10
     723          b64encode = base64.b64encode
     724          b32hexencode = base64.b32hexencode
     725          b32encode = base64.b32encode
     726          b16encode = base64.b16encode
     727  
     728          self.assertEqual(b64encode(b""), b"")
     729          self.assertEqual(b64encode(b"f"), b"Zg==")
     730          self.assertEqual(b64encode(b"fo"), b"Zm8=")
     731          self.assertEqual(b64encode(b"foo"), b"Zm9v")
     732          self.assertEqual(b64encode(b"foob"), b"Zm9vYg==")
     733          self.assertEqual(b64encode(b"fooba"), b"Zm9vYmE=")
     734          self.assertEqual(b64encode(b"foobar"), b"Zm9vYmFy")
     735  
     736          self.assertEqual(b32encode(b""), b"")
     737          self.assertEqual(b32encode(b"f"), b"MY======")
     738          self.assertEqual(b32encode(b"fo"), b"MZXQ====")
     739          self.assertEqual(b32encode(b"foo"), b"MZXW6===")
     740          self.assertEqual(b32encode(b"foob"), b"MZXW6YQ=")
     741          self.assertEqual(b32encode(b"fooba"), b"MZXW6YTB")
     742          self.assertEqual(b32encode(b"foobar"), b"MZXW6YTBOI======")
     743  
     744          self.assertEqual(b32hexencode(b""), b"")
     745          self.assertEqual(b32hexencode(b"f"), b"CO======")
     746          self.assertEqual(b32hexencode(b"fo"), b"CPNG====")
     747          self.assertEqual(b32hexencode(b"foo"), b"CPNMU===")
     748          self.assertEqual(b32hexencode(b"foob"), b"CPNMUOG=")
     749          self.assertEqual(b32hexencode(b"fooba"), b"CPNMUOJ1")
     750          self.assertEqual(b32hexencode(b"foobar"), b"CPNMUOJ1E8======")
     751  
     752          self.assertEqual(b16encode(b""), b"")
     753          self.assertEqual(b16encode(b"f"), b"66")
     754          self.assertEqual(b16encode(b"fo"), b"666F")
     755          self.assertEqual(b16encode(b"foo"), b"666F6F")
     756          self.assertEqual(b16encode(b"foob"), b"666F6F62")
     757          self.assertEqual(b16encode(b"fooba"), b"666F6F6261")
     758          self.assertEqual(b16encode(b"foobar"), b"666F6F626172")
     759  
     760  
     761  class ESC[4;38;5;81mTestMain(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     762      def tearDown(self):
     763          if os.path.exists(os_helper.TESTFN):
     764              os.unlink(os_helper.TESTFN)
     765  
     766      def get_output(self, *args):
     767          return script_helper.assert_python_ok('-m', 'base64', *args).out
     768  
     769      def test_encode_file(self):
     770          with open(os_helper.TESTFN, 'wb') as fp:
     771              fp.write(b'a\xffb\n')
     772          output = self.get_output('-e', os_helper.TESTFN)
     773          self.assertEqual(output.rstrip(), b'Yf9iCg==')
     774  
     775      def test_encode_from_stdin(self):
     776          with script_helper.spawn_python('-m', 'base64', '-e') as proc:
     777              out, err = proc.communicate(b'a\xffb\n')
     778          self.assertEqual(out.rstrip(), b'Yf9iCg==')
     779          self.assertIsNone(err)
     780  
     781      def test_decode(self):
     782          with open(os_helper.TESTFN, 'wb') as fp:
     783              fp.write(b'Yf9iCg==')
     784          output = self.get_output('-d', os_helper.TESTFN)
     785          self.assertEqual(output.rstrip(), b'a\xffb')
     786  
     787      def test_prints_usage_with_help_flag(self):
     788          output = self.get_output('-h')
     789          self.assertIn(b'usage: ', output)
     790          self.assertIn(b'-d, -u: decode', output)
     791  
     792      def test_prints_usage_with_invalid_flag(self):
     793          output = script_helper.assert_python_failure('-m', 'base64', '-x').err
     794          self.assertIn(b'usage: ', output)
     795          self.assertIn(b'-d, -u: decode', output)
     796  
     797  if __name__ == '__main__':
     798      unittest.main()