import unittest from test import support import base64 import binascii import os import sys import subprocess import struct from array import array class LegacyBase64TestCase(unittest.TestCase): # Legacy API is not as permissive as the modern API def check_type_errors(self, f): self.assertRaises(TypeError, f, "") self.assertRaises(TypeError, f, []) multidimensional = memoryview(b"1234").cast('B', (2, 2)) self.assertRaises(TypeError, f, multidimensional) int_data = memoryview(b"1234").cast('I') self.assertRaises(TypeError, f, int_data) def test_encodebytes(self): eq = self.assertEqual eq(base64.encodebytes(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=\n") eq(base64.encodebytes(b"a"), b"YQ==\n") eq(base64.encodebytes(b"ab"), b"YWI=\n") eq(base64.encodebytes(b"abc"), b"YWJj\n") eq(base64.encodebytes(b""), b"") eq(base64.encodebytes(b"abcdefghijklmnopqrstuvwxyz" b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}"), b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n") # Non-bytes eq(base64.encodebytes(bytearray(b'abc')), b'YWJj\n') eq(base64.encodebytes(memoryview(b'abc')), b'YWJj\n') eq(base64.encodebytes(array('B', b'abc')), b'YWJj\n') self.check_type_errors(base64.encodebytes) def test_decodebytes(self): eq = self.assertEqual eq(base64.decodebytes(b"d3d3LnB5dGhvbi5vcmc=\n"), b"www.python.org") eq(base64.decodebytes(b"YQ==\n"), b"a") eq(base64.decodebytes(b"YWI=\n"), b"ab") eq(base64.decodebytes(b"YWJj\n"), b"abc") eq(base64.decodebytes(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n"), b"abcdefghijklmnopqrstuvwxyz" b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}") eq(base64.decodebytes(b''), b'') # Non-bytes eq(base64.decodebytes(bytearray(b'YWJj\n')), b'abc') eq(base64.decodebytes(memoryview(b'YWJj\n')), b'abc') eq(base64.decodebytes(array('B', b'YWJj\n')), b'abc') self.check_type_errors(base64.decodebytes) def test_encode(self): eq = self.assertEqual from io import BytesIO, StringIO infp = BytesIO(b'abcdefghijklmnopqrstuvwxyz' b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' b'0123456789!@#0^&*();:<>,. []{}') outfp = BytesIO() base64.encode(infp, outfp) eq(outfp.getvalue(), b'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE' b'RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT' b'Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n') # Non-binary files self.assertRaises(TypeError, base64.encode, StringIO('abc'), BytesIO()) self.assertRaises(TypeError, base64.encode, BytesIO(b'abc'), StringIO()) self.assertRaises(TypeError, base64.encode, StringIO('abc'), StringIO()) def test_decode(self): from io import BytesIO, StringIO infp = BytesIO(b'd3d3LnB5dGhvbi5vcmc=') outfp = BytesIO() base64.decode(infp, outfp) self.assertEqual(outfp.getvalue(), b'www.python.org') # Non-binary files self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), BytesIO()) self.assertRaises(TypeError, base64.encode, BytesIO(b'YWJj\n'), StringIO()) self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), StringIO()) class BaseXYTestCase(unittest.TestCase): # Modern API completely ignores exported dimension and format data and # treats any buffer as a stream of bytes def check_encode_type_errors(self, f): self.assertRaises(TypeError, f, "") self.assertRaises(TypeError, f, []) def check_decode_type_errors(self, f): self.assertRaises(TypeError, f, []) def check_other_types(self, f, bytes_data, expected): eq = self.assertEqual eq(f(bytearray(bytes_data)), expected) eq(f(memoryview(bytes_data)), expected) eq(f(array('B', bytes_data)), expected) self.check_nonbyte_element_format(base64.b64encode, bytes_data) self.check_multidimensional(base64.b64encode, bytes_data) def check_multidimensional(self, f, data): padding = b"\x00" if len(data) % 2 else b"" bytes_data = data + padding # Make sure cast works shape = (len(bytes_data) // 2, 2) multidimensional = memoryview(bytes_data).cast('B', shape) self.assertEqual(f(multidimensional), f(bytes_data)) def check_nonbyte_element_format(self, f, data): padding = b"\x00" * ((4 - len(data)) % 4) bytes_data = data + padding # Make sure cast works int_data = memoryview(bytes_data).cast('I') self.assertEqual(f(int_data), f(bytes_data)) def test_b64encode(self): eq = self.assertEqual # Test default alphabet eq(base64.b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=") eq(base64.b64encode(b'\x00'), b'AA==') eq(base64.b64encode(b"a"), b"YQ==") eq(base64.b64encode(b"ab"), b"YWI=") eq(base64.b64encode(b"abc"), b"YWJj") eq(base64.b64encode(b""), b"") eq(base64.b64encode(b"abcdefghijklmnopqrstuvwxyz" b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}"), b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") # Test with arbitrary alternative characters eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=b'*$'), b'01a*b$cd') eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=bytearray(b'*$')), b'01a*b$cd') eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=memoryview(b'*$')), b'01a*b$cd') eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=array('B', b'*$')), b'01a*b$cd') # Non-bytes self.check_other_types(base64.b64encode, b'abcd', b'YWJjZA==') self.check_encode_type_errors(base64.b64encode) self.assertRaises(TypeError, base64.b64encode, b"", altchars="*$") # Test standard alphabet eq(base64.standard_b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=") eq(base64.standard_b64encode(b"a"), b"YQ==") eq(base64.standard_b64encode(b"ab"), b"YWI=") eq(base64.standard_b64encode(b"abc"), b"YWJj") eq(base64.standard_b64encode(b""), b"") eq(base64.standard_b64encode(b"abcdefghijklmnopqrstuvwxyz" b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}"), b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") # Non-bytes self.check_other_types(base64.standard_b64encode, b'abcd', b'YWJjZA==') self.check_encode_type_errors(base64.standard_b64encode) # Test with 'URL safe' alternative characters eq(base64.urlsafe_b64encode(b'\xd3V\xbeo\xf7\x1d'), b'01a-b_cd') # Non-bytes self.check_other_types(base64.urlsafe_b64encode, b'\xd3V\xbeo\xf7\x1d', b'01a-b_cd') self.check_encode_type_errors(base64.urlsafe_b64encode) def test_b64decode(self): eq = self.assertEqual tests = {b"d3d3LnB5dGhvbi5vcmc=": b"www.python.org", b'AA==': b'\x00', b"YQ==": b"a", b"YWI=": b"ab", b"YWJj": b"abc", b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==": b"abcdefghijklmnopqrstuvwxyz" b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}", b'': b'', } for data, res in tests.items(): eq(base64.b64decode(data), res) eq(base64.b64decode(data.decode('ascii')), res) # Non-bytes self.check_other_types(base64.b64decode, b"YWJj", b"abc") self.check_decode_type_errors(base64.b64decode) # Test with arbitrary alternative characters tests_altchars = {(b'01a*b$cd', b'*$'): b'\xd3V\xbeo\xf7\x1d', } for (data, altchars), res in tests_altchars.items(): data_str = data.decode('ascii') altchars_str = altchars.decode('ascii') eq(base64.b64decode(data, altchars=altchars), res) eq(base64.b64decode(data_str, altchars=altchars), res) eq(base64.b64decode(data, altchars=altchars_str), res) eq(base64.b64decode(data_str, altchars=altchars_str), res) # Test standard alphabet for data, res in tests.items(): eq(base64.standard_b64decode(data), res) eq(base64.standard_b64decode(data.decode('ascii')), res) # Non-bytes self.check_other_types(base64.standard_b64decode, b"YWJj", b"abc") self.check_decode_type_errors(base64.standard_b64decode) # Test with 'URL safe' alternative characters tests_urlsafe = {b'01a-b_cd': b'\xd3V\xbeo\xf7\x1d', b'': b'', } for data, res in tests_urlsafe.items(): eq(base64.urlsafe_b64decode(data), res) eq(base64.urlsafe_b64decode(data.decode('ascii')), res) # Non-bytes self.check_other_types(base64.urlsafe_b64decode, b'01a-b_cd', b'\xd3V\xbeo\xf7\x1d') self.check_decode_type_errors(base64.urlsafe_b64decode) def test_b64decode_padding_error(self): self.assertRaises(binascii.Error, base64.b64decode, b'abc') self.assertRaises(binascii.Error, base64.b64decode, 'abc') def test_b64decode_invalid_chars(self): # issue 1466065: Test some invalid characters. tests = ((b'%3d==', b'\xdd'), (b'$3d==', b'\xdd'), (b'[==', b''), (b'YW]3=', b'am'), (b'3{d==', b'\xdd'), (b'3d}==', b'\xdd'), (b'@@', b''), (b'!', b''), (b'YWJj\nYWI=', b'abcab')) for bstr, res in tests: self.assertEqual(base64.b64decode(bstr), res) self.assertEqual(base64.b64decode(bstr.decode('ascii')), res) with self.assertRaises(binascii.Error): base64.b64decode(bstr, validate=True) with self.assertRaises(binascii.Error): base64.b64decode(bstr.decode('ascii'), validate=True) def test_b32encode(self): eq = self.assertEqual eq(base64.b32encode(b''), b'') eq(base64.b32encode(b'\x00'), b'AA======') eq(base64.b32encode(b'a'), b'ME======') eq(base64.b32encode(b'ab'), b'MFRA====') eq(base64.b32encode(b'abc'), b'MFRGG===') eq(base64.b32encode(b'abcd'), b'MFRGGZA=') eq(base64.b32encode(b'abcde'), b'MFRGGZDF') # Non-bytes self.check_other_types(base64.b32encode, b'abcd', b'MFRGGZA=') self.check_encode_type_errors(base64.b32encode) def test_b32decode(self): eq = self.assertEqual tests = {b'': b'', b'AA======': b'\x00', b'ME======': b'a', b'MFRA====': b'ab', b'MFRGG===': b'abc', b'MFRGGZA=': b'abcd', b'MFRGGZDF': b'abcde', } for data, res in tests.items(): eq(base64.b32decode(data), res) eq(base64.b32decode(data.decode('ascii')), res) # Non-bytes self.check_other_types(base64.b32decode, b'MFRGG===', b"abc") self.check_decode_type_errors(base64.b32decode) def test_b32decode_casefold(self): eq = self.assertEqual tests = {b'': b'', b'ME======': b'a', b'MFRA====': b'ab', b'MFRGG===': b'abc', b'MFRGGZA=': b'abcd', b'MFRGGZDF': b'abcde', # Lower cases b'me======': b'a', b'mfra====': b'ab', b'mfrgg===': b'abc', b'mfrggza=': b'abcd', b'mfrggzdf': b'abcde', } for data, res in tests.items(): eq(base64.b32decode(data, True), res) eq(base64.b32decode(data.decode('ascii'), True), res) self.assertRaises(binascii.Error, base64.b32decode, b'me======') self.assertRaises(binascii.Error, base64.b32decode, 'me======') # Mapping zero and one eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe') eq(base64.b32decode('MLO23456'), b'b\xdd\xad\xf3\xbe') map_tests = {(b'M1023456', b'L'): b'b\xdd\xad\xf3\xbe', (b'M1023456', b'I'): b'b\x1d\xad\xf3\xbe', } for (data, map01), res in map_tests.items(): data_str = data.decode('ascii') map01_str = map01.decode('ascii') eq(base64.b32decode(data, map01=map01), res) eq(base64.b32decode(data_str, map01=map01), res) eq(base64.b32decode(data, map01=map01_str), res) eq(base64.b32decode(data_str, map01=map01_str), res) self.assertRaises(binascii.Error, base64.b32decode, data) self.assertRaises(binascii.Error, base64.b32decode, data_str) def test_b32decode_error(self): for data in [b'abc', b'ABCDEF==', b'==ABCDEF']: with self.assertRaises(binascii.Error): base64.b32decode(data) with self.assertRaises(binascii.Error): base64.b32decode(data.decode('ascii')) def test_b16encode(self): eq = self.assertEqual eq(base64.b16encode(b'\x01\x02\xab\xcd\xef'), b'0102ABCDEF') eq(base64.b16encode(b'\x00'), b'00') # Non-bytes self.check_other_types(base64.b16encode, b'\x01\x02\xab\xcd\xef', b'0102ABCDEF') self.check_encode_type_errors(base64.b16encode) def test_b16decode(self): eq = self.assertEqual eq(base64.b16decode(b'0102ABCDEF'), b'\x01\x02\xab\xcd\xef') eq(base64.b16decode('0102ABCDEF'), b'\x01\x02\xab\xcd\xef') eq(base64.b16decode(b'00'), b'\x00') eq(base64.b16decode('00'), b'\x00') # Lower case is not allowed without a flag self.assertRaises(binascii.Error, base64.b16decode, b'0102abcdef') self.assertRaises(binascii.Error, base64.b16decode, '0102abcdef') # Case fold eq(base64.b16decode(b'0102abcdef', True), b'\x01\x02\xab\xcd\xef') eq(base64.b16decode('0102abcdef', True), b'\x01\x02\xab\xcd\xef') # Non-bytes self.check_other_types(base64.b16decode, b"0102ABCDEF", b'\x01\x02\xab\xcd\xef') self.check_decode_type_errors(base64.b16decode) eq(base64.b16decode(bytearray(b"0102abcdef"), True), b'\x01\x02\xab\xcd\xef') eq(base64.b16decode(memoryview(b"0102abcdef"), True), b'\x01\x02\xab\xcd\xef') eq(base64.b16decode(array('B', b"0102abcdef"), True), b'\x01\x02\xab\xcd\xef') def test_decode_nonascii_str(self): decode_funcs = (base64.b64decode, base64.standard_b64decode, base64.urlsafe_b64decode, base64.b32decode, base64.b16decode) for f in decode_funcs: self.assertRaises(ValueError, f, 'with non-ascii \xcb') def test_ErrorHeritage(self): self.assertTrue(issubclass(binascii.Error, ValueError)) class TestMain(unittest.TestCase): def tearDown(self): if os.path.exists(support.TESTFN): os.unlink(support.TESTFN) def get_output(self, *args, **options): args = (sys.executable, '-m', 'base64') + args return subprocess.check_output(args, **options) def test_encode_decode(self): output = self.get_output('-t') self.assertSequenceEqual(output.splitlines(), ( b"b'Aladdin:open sesame'", br"b'QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n'", b"b'Aladdin:open sesame'", )) def test_encode_file(self): with open(support.TESTFN, 'wb') as fp: fp.write(b'a\xffb\n') output = self.get_output('-e', support.TESTFN) self.assertEqual(output.rstrip(), b'Yf9iCg==') with open(support.TESTFN, 'rb') as fp: output = self.get_output('-e', stdin=fp) self.assertEqual(output.rstrip(), b'Yf9iCg==') def test_decode(self): with open(support.TESTFN, 'wb') as fp: fp.write(b'Yf9iCg==') output = self.get_output('-d', support.TESTFN) self.assertEqual(output.rstrip(), b'a\xffb') def test_main(): support.run_unittest(__name__) if __name__ == '__main__': test_main()