cpython/Lib/test/test_base64.py
Serhiy Storchaka 8bf8bf9292
gh-73613: Support Base32 and Base64 without padding (GH-147974)
Add the padded parameter in functions related to Base32 and Base64 codecs
in the binascii and base64 modules.  In the encoding functions it controls
whether the pad character can be added in the output, in the decoding
functions it controls whether padding is required in input.

Padding of input no longer required in base64.urlsafe_b64decode() by default.
2026-04-04 21:26:16 +03:00

1446 lines
66 KiB
Python

import unittest
import base64
import binascii
import string
import sys
import os
from array import array
from test.support import cpython_only, check_impl_detail
from test.support import os_helper
from test.support import script_helper
from test.support.import_helper import ensure_lazy_imports
class LazyImportTest(unittest.TestCase):
@cpython_only
def test_lazy_import(self):
ensure_lazy_imports("base64", {"re", "getopt"})
from test.support.hypothesis_helper import hypothesis
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")
eq(base64.encodebytes(b"Aladdin:open sesame"),
b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\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'')
eq(base64.decodebytes(b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n"),
b"Aladdin:open sesame")
# 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)
@hypothesis.given(payload=hypothesis.strategies.binary())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
def test_bytes_encode_decode_round_trip(self, payload):
encoded = base64.encodebytes(payload)
decoded = base64.decodebytes(encoded)
self.assertEqual(payload, decoded)
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())
@hypothesis.given(payload=hypothesis.strategies.binary())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
def test_legacy_encode_decode_round_trip(self, payload):
from io import BytesIO
payload_file_r = BytesIO(payload)
encoded_file_w = BytesIO()
base64.encode(payload_file_r, encoded_file_w)
encoded_file_r = BytesIO(encoded_file_w.getvalue())
decoded_file_w = BytesIO()
base64.decode(encoded_file_r, decoded_file_w)
decoded = decoded_file_w.getvalue()
self.assertEqual(payload, decoded)
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
b = bytearray(bytes_data)
eq(f(b), expected)
# The bytearray wasn't mutated
eq(b, bytes_data)
eq(f(memoryview(bytes_data)), expected)
eq(f(array('B', bytes_data)), expected)
# XXX why is b64encode hardcoded here?
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_b64encode_padded(self):
b64encode = base64.b64encode
self.assertEqual(b64encode(b'', padded=False), b'')
self.assertEqual(b64encode(b'a', padded=False), b'YQ')
self.assertEqual(b64encode(b'ab', padded=False), b'YWI')
self.assertEqual(b64encode(b'abc', padded=False), b'YWJj')
self.assertEqual(b64encode(b'\xfb', padded=False, altchars=b'-_'), b'-w')
self.assertEqual(b64encode(b'\xfb\xff', padded=False, altchars=b'-_'),
b'-_8')
self.assertEqual(b64encode(b'\xfb\xff\xbf', padded=False, altchars=b'-_'),
b'-_-_')
urlsafe_b64encode = base64.urlsafe_b64encode
self.assertEqual(urlsafe_b64encode(b'', padded=False), b'')
self.assertEqual(urlsafe_b64encode(b'\xfb', padded=False), b'-w')
self.assertEqual(urlsafe_b64encode(b'\xfb\xff', padded=False), b'-_8')
self.assertEqual(urlsafe_b64encode(b'\xfb\xff\xbf', padded=False),
b'-_-_')
def _common_test_wrapcol(self, func, data):
eq = self.assertEqual
expected = func(data)
eq(func(data, wrapcol=0), expected)
eq(func(data, wrapcol=80), expected)
eq(func(b'', wrapcol=0), func(b''))
eq(func(b'', wrapcol=1), func(b''))
eq(func(data, wrapcol=sys.maxsize), expected)
if check_impl_detail():
eq(func(data, wrapcol=sys.maxsize*2), expected)
with self.assertRaises(OverflowError):
func(data, wrapcol=2**1000)
with self.assertRaises(ValueError):
func(data, wrapcol=-80)
with self.assertRaises(TypeError):
func(data, wrapcol=80.0)
with self.assertRaises(TypeError):
func(data, wrapcol='80')
if func is not base64.b16encode:
with self.assertRaises(TypeError):
func(data, wrapcol=None)
def test_b64encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.b64encode, b)
eq(base64.b64encode(b, wrapcol=8), b'd3d3LnB5\ndGhvbi5v\ncmc=')
eq(base64.b64encode(b, wrapcol=11), b'd3d3LnB5\ndGhvbi5v\ncmc=')
eq(base64.b64encode(b, wrapcol=1), b'd3d3\nLnB5\ndGhv\nbi5v\ncmc=')
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 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_altchars(self):
# Test with arbitrary alternative characters
eq = self.assertEqual
res = b'\xd3V\xbeo\xf7\x1d'
for altchars in b'*$', b'+/', b'/+', b'+_', b'-+', b'-/', b'/_':
data = b'01a%cb%ccd' % tuple(altchars)
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)
eq(base64.b64decode(data, altchars=altchars, ignorechars=b'\n'), res)
eq(base64.b64decode(b'/----', altchars=b'-+', ignorechars=b'/'), b'\xfb\xef\xbe')
eq(base64.b64decode(b'/----', altchars=b'+-', ignorechars=b'/'), b'\xff\xff\xff')
eq(base64.b64decode(b'+----', altchars=b'-/', ignorechars=b'+'), b'\xfb\xef\xbe')
eq(base64.b64decode(b'+----', altchars=b'/-', ignorechars=b'+'), b'\xff\xff\xff')
eq(base64.b64decode(b'+/+/', altchars=b'/+', ignorechars=b''), b'\xff\xef\xfe')
eq(base64.b64decode(b'/+/+', altchars=b'+/', ignorechars=b''), b'\xff\xef\xfe')
self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+')
self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-')
self.assertRaises(ValueError, base64.b64decode, '', altchars='+')
self.assertRaises(ValueError, base64.b64decode, '', altchars='+/-')
def test_b64decode_padding_error(self):
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
self.assertRaises(binascii.Error, base64.b64decode, 'abc')
def test_b64decode_padded(self):
b64decode = base64.b64decode
urlsafe_b64decode = base64.urlsafe_b64decode
def check(data, expected, padded=0):
if b'=' in data:
with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
b64decode(data, padded=False, validate=True)
self.assertEqual(b64decode(data, padded=False, ignorechars=b'='),
expected)
self.assertEqual(urlsafe_b64decode(data, padded=True), expected)
self.assertEqual(urlsafe_b64decode(data, padded=False), expected)
data = data.replace(b'=', b'')
self.assertEqual(b64decode(data, padded=False), expected)
self.assertEqual(b64decode(data, padded=False, validate=True),
expected)
self.assertEqual(urlsafe_b64decode(data), expected)
check(b'', b'')
check(b'YQ==', b'a')
check(b'YWI=', b'ab')
check(b'YWJj', b'abc')
check(b'Y=WJj', b'abc')
check(b'YW=Jj', b'abc')
check(b'YWJ=j', b'abc')
with self.assertRaisesRegex(binascii.Error, 'Incorrect padding'):
urlsafe_b64decode(b'YQ', padded=True)
with self.assertRaisesRegex(binascii.Error, 'Incorrect padding'):
urlsafe_b64decode(b'YWI', padded=True)
def _common_test_ignorechars(self, func):
eq = self.assertEqual
eq(func(b'', ignorechars=b' \n'), b'')
eq(func(b'', ignorechars=b''), b'')
eq(func(b' \n', ignorechars=b' \n'), b'')
with self.assertRaises(binascii.Error):
func(b' \n', ignorechars=b'')
with self.assertRaises(binascii.Error):
func(b' \n', ignorechars=b' ')
with self.assertRaises(binascii.Error):
func(b' \n', ignorechars=b'\n')
with self.assertRaises(TypeError):
func(b'', ignorechars='')
with self.assertRaises(TypeError):
func(b'', ignorechars=[])
with self.assertRaises(TypeError):
func(b'', ignorechars=None)
def test_b64decode_invalid_chars(self):
# issue 1466065: Test some invalid characters.
tests = ((b'%3d==', b'\xdd', b'%$'),
(b'$3d==', b'\xdd', b'%$'),
(b'[==', b'', b'[='),
(b'YW]3=', b'am', b']'),
(b'3{d==', b'\xdd', b'{}'),
(b'3d}==', b'\xdd', b'{}'),
(b'@@', b'', b'@!'),
(b'!', b'', b'@!'),
(b"YWJj\n", b"abc", b'\n'),
(b'YWJj\nYWI=', b'abcab', b'\n'),
(b'=YWJj', b'abc', b'='),
(b'Y=WJj', b'abc', b'='),
(b'Y==WJj', b'abc', b'='),
(b'Y===WJj', b'abc', b'='),
(b'YW=Jj', b'abc', b'='),
(b'YWJj=', b'abc', b'='),
(b'YW\nJj', b'abc', b'\n'),
(b'YW\nJj', b'abc', bytearray(b'\n')),
(b'YW\nJj', b'abc', memoryview(b'\n')),
)
funcs = (
base64.b64decode,
base64.standard_b64decode,
base64.urlsafe_b64decode,
)
for bstr, res, ignorechars in tests:
for func in funcs:
with self.subTest(bstr=bstr, func=func):
self.assertEqual(func(bstr), res)
self.assertEqual(func(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)
with self.assertRaises(binascii.Error):
# Even empty ignorechars enables the strict mode.
base64.b64decode(bstr, ignorechars=b'')
r = base64.b64decode(bstr, ignorechars=ignorechars)
self.assertEqual(r, res)
self._common_test_ignorechars(base64.b64decode)
# Normal alphabet characters will be discarded when alternative given
discarded = ("invalid character %a in Base64 data with %s "
"will be discarded in future Python versions")
error = ("invalid character %a in Base64 data with %s "
"will be an error in future Python versions")
with self.assertWarns(FutureWarning) as cm:
r = base64.b64decode(b'++++', altchars=b'-_')
self.assertEqual(r, b'\xfb\xef\xbe')
self.assertEqual(str(cm.warning),
discarded % ('+', "altchars=b'-_' and validate=False"))
with self.assertWarns(FutureWarning) as cm:
r = base64.b64decode(b'////', altchars=b'-_')
self.assertEqual(r, b'\xff\xff\xff')
self.assertEqual(str(cm.warning),
discarded % ('/', "altchars=b'-_' and validate=False"))
with self.assertWarns(DeprecationWarning) as cm:
r = base64.b64decode(b'++++', altchars=b'-_', validate=True)
self.assertEqual(r, b'\xfb\xef\xbe')
self.assertEqual(str(cm.warning),
error % ('+', "altchars=b'-_' and validate=True"))
with self.assertWarns(DeprecationWarning) as cm:
r = base64.b64decode(b'////', altchars=b'-_', validate=True)
self.assertEqual(r, b'\xff\xff\xff')
self.assertEqual(str(cm.warning),
error % ('/', "altchars=b'-_' and validate=True"))
r = base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'+')
self.assertEqual(r, b'')
r = base64.b64decode(b'////', altchars=b'-_', ignorechars=b'/')
self.assertEqual(r, b'')
r = base64.b64decode(b'++++////', altchars=b'-_', validate=False, ignorechars=b'')
self.assertEqual(r, b'')
with self.assertRaisesRegex(binascii.Error, 'Only base64 data is allowed'):
base64.b64decode(b'////', altchars=b'-_', ignorechars=b'')
with self.assertRaisesRegex(binascii.Error, 'Only base64 data is allowed'):
base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'')
r = base64.b64decode(b'++++YWJj----____', altchars=b'-_', ignorechars=b'+')
self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff')
r = base64.b64decode(b'////YWJj----____', altchars=b'-_', ignorechars=b'/')
self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff')
r = base64.b64decode(b'++++,,,,', altchars=b'+,', ignorechars=b'+')
self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff')
r = base64.b64decode(b'////YWJj++++,,,,', altchars=b'+,', ignorechars=b'/')
self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff')
r = base64.b64decode(b'----////', altchars=b'-/', ignorechars=b'/')
self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff')
r = base64.b64decode(b'++++YWJj----////', altchars=b'-/', ignorechars=b'+')
self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff')
with self.assertWarns(FutureWarning) as cm:
self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe')
self.assertEqual(str(cm.warning),
"invalid character '+' in URL-safe Base64 data "
"will be discarded in future Python versions")
with self.assertWarns(FutureWarning) as cm:
self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff')
self.assertEqual(str(cm.warning),
"invalid character '/' in URL-safe Base64 data "
"will be discarded in future Python versions")
with self.assertRaises(binascii.Error):
base64.b64decode(b'+/!', altchars=b'-_')
def _altchars_strategy():
"""Generate 'altchars' for base64 encoding."""
reserved_chars = (string.digits + string.ascii_letters + "=").encode()
allowed_chars = hypothesis.strategies.sampled_from(
[n for n in range(256) if n not in reserved_chars])
two_bytes_strategy = hypothesis.strategies.lists(
allowed_chars, min_size=2, max_size=2, unique=True).map(bytes)
return (hypothesis.strategies.none()
| hypothesis.strategies.just(b"_-")
| two_bytes_strategy)
@hypothesis.given(
payload=hypothesis.strategies.binary(),
altchars=_altchars_strategy(),
validate=hypothesis.strategies.booleans())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", False)
def test_b64_encode_decode_round_trip(self, payload, altchars, validate):
encoded = base64.b64encode(payload, altchars=altchars)
decoded = base64.b64decode(encoded, altchars=altchars,
validate=validate)
self.assertEqual(payload, decoded)
@hypothesis.given(payload=hypothesis.strategies.binary())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
def test_standard_b64_encode_decode_round_trip(self, payload):
encoded = base64.standard_b64encode(payload)
decoded = base64.standard_b64decode(encoded)
self.assertEqual(payload, decoded)
@hypothesis.given(payload=hypothesis.strategies.binary())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
def test_urlsafe_b64_encode_decode_round_trip(self, payload):
encoded = base64.urlsafe_b64encode(payload)
decoded = base64.urlsafe_b64decode(encoded)
self.assertEqual(payload, decoded)
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_b32encode_padded(self):
b32encode = base64.b32encode
self.assertEqual(b32encode(b'', padded=False), b'')
self.assertEqual(b32encode(b'a', padded=False), b'ME')
self.assertEqual(b32encode(b'ab', padded=False), b'MFRA')
self.assertEqual(b32encode(b'abc', padded=False), b'MFRGG')
self.assertEqual(b32encode(b'abcd', padded=False), b'MFRGGZA')
self.assertEqual(b32encode(b'abcde', padded=False), b'MFRGGZDF')
def test_b32encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.b32encode, b)
eq(base64.b32encode(b, wrapcol=16), b'O53XOLTQPF2GQ33O\nFZXXEZY=')
eq(base64.b32encode(b, wrapcol=23), b'O53XOLTQPF2GQ33O\nFZXXEZY=')
eq(base64.b32encode(b, wrapcol=1), b'O53XOLTQ\nPF2GQ33O\nFZXXEZY=')
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, casefold=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======')
def test_b32decode_map01(self):
# Mapping zero and one
eq = self.assertEqual
res_L = b'b\xdd\xad\xf3\xbe'
res_I = b'b\x1d\xad\xf3\xbe'
eq(base64.b32decode(b'MLO23456'), res_L)
eq(base64.b32decode('MLO23456'), res_L)
eq(base64.b32decode(b'MIO23456'), res_I)
eq(base64.b32decode('MIO23456'), res_I)
self.assertRaises(binascii.Error, base64.b32decode, b'M1023456')
self.assertRaises(binascii.Error, base64.b32decode, b'M1O23456')
self.assertRaises(binascii.Error, base64.b32decode, b'ML023456')
self.assertRaises(binascii.Error, base64.b32decode, b'MI023456')
data = b'M1023456'
data_str = data.decode('ascii')
for map01, res in [(b'L', res_L), (b'I', res_I)]:
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)
eq(base64.b32decode(b'M1O23456', map01=map01), res)
eq(base64.b32decode(b'M%c023456' % map01, map01=map01), res)
eq(base64.b32decode(b'M%cO23456' % map01, map01=map01), res)
def test_b32decode_padded(self):
b32decode = base64.b32decode
def check(data, expected):
if b'=' in data:
with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
b32decode(data, padded=False)
self.assertEqual(b32decode(data, padded=False, ignorechars=b'='),
expected)
data = data.replace(b'=', b'')
self.assertEqual(b32decode(data, padded=False), expected)
check(b'', b'')
check(b'ME======', b'a')
check(b'MFRA====', b'ab')
check(b'MFRGG===', b'abc')
check(b'MFRGGZA=', b'abcd')
check(b'MFRGGZDF', b'abcde')
check(b'M=FRGGZDF', b'abcde')
check(b'MF=RGGZDF', b'abcde')
check(b'MFR=GGZDF', b'abcde')
check(b'MFRG=GZDF', b'abcde')
check(b'MFRGG=ZDF', b'abcde')
check(b'MFRGGZ=DF', b'abcde')
check(b'MFRGGZD=F', b'abcde')
def test_b32decode_ignorechars(self):
self._common_test_ignorechars(base64.b32decode)
eq = self.assertEqual
eq(base64.b32decode(b'MFRG\n GZDF\n', ignorechars=b' \n'), b'abcde')
eq(base64.b32decode(b'MFRG\n GZDF\n', ignorechars=bytearray(b' \n')), b'abcde')
eq(base64.b32decode(b'M=======FRGGZDF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MF======RGGZDF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFR=====GGZDF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRG====GZDF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRGG===ZDF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRGGZ==DF', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRGGZD=F', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRGGZDF=', ignorechars=b'='), b'abcde')
eq(base64.b32decode(b'MFRA======', ignorechars=b'='), b'ab')
eq(base64.b32decode(b'mfRggzDfmzTQ====', ignorechars=b'mfgz'),
b'\x88\xe7')
eq(base64.b32decode(b'mfRggzDfmzTQ====', casefold=True, ignorechars=b'mfgz'),
b'abcdefg')
eq(base64.b32decode(b'M0F1R0G1G0Z1D0F1', ignorechars=b'01'), b'abcde')
eq(base64.b32decode(b'M0F1R0G1G0Z1D0F1', map01=b'L', ignorechars=b'01'),
b'c\x8a\xb8\xb8\xcb3\xb2\xb1\xb8\xab')
eq(base64.b32decode(b'M0F1R0G1G0Z1D0F1', map01=b'I', ignorechars=b'01'),
b'c\x8a\x88\xb8\xc83\xb2\x81\xb8\xa8')
def test_b32decode_error(self):
tests = [b'abc', b'ABCDEF==', b'==ABCDEF']
prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
for i in range(0, 17):
if i:
tests.append(b'='*i)
for prefix in prefixes:
if len(prefix) + i != 8:
tests.append(prefix + b'='*i)
for data in tests:
with self.subTest(data=data):
with self.assertRaises(binascii.Error):
base64.b32decode(data)
with self.assertRaises(binascii.Error):
base64.b32decode(data.decode('ascii'))
@hypothesis.given(
payload=hypothesis.strategies.binary(),
casefold=hypothesis.strategies.booleans(),
map01=(
hypothesis.strategies.none()
| hypothesis.strategies.binary(min_size=1, max_size=1)))
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, None)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, None)
def test_b32_encode_decode_round_trip(self, payload, casefold, map01):
encoded = base64.b32encode(payload)
decoded = base64.b32decode(encoded, casefold=casefold, map01=map01)
self.assertEqual(payload, decoded)
def test_b32hexencode(self):
test_cases = [
# to_encode, expected
(b'', b''),
(b'\x00', b'00======'),
(b'a', b'C4======'),
(b'ab', b'C5H0===='),
(b'abc', b'C5H66==='),
(b'abcd', b'C5H66P0='),
(b'abcde', b'C5H66P35'),
]
for to_encode, expected in test_cases:
with self.subTest(to_decode=to_encode):
self.assertEqual(base64.b32hexencode(to_encode), expected)
self.assertEqual(base64.b32hexencode(to_encode, padded=False),
expected.rstrip(b'='))
def test_b32hexencode_other_types(self):
self.check_other_types(base64.b32hexencode, b'abcd', b'C5H66P0=')
self.check_encode_type_errors(base64.b32hexencode)
def test_b32hexencode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.b32hexencode, b)
eq(base64.b32hexencode(b, wrapcol=16), b'ETRNEBJGF5Q6GRRE\n5PNN4PO=')
eq(base64.b32hexencode(b, wrapcol=23), b'ETRNEBJGF5Q6GRRE\n5PNN4PO=')
eq(base64.b32hexencode(b, wrapcol=1), b'ETRNEBJG\nF5Q6GRRE\n5PNN4PO=')
def test_b32hexdecode(self):
test_cases = [
# to_decode, expected, casefold
(b'', b'', False),
(b'00======', b'\x00', False),
(b'C4======', b'a', False),
(b'C5H0====', b'ab', False),
(b'C5H66===', b'abc', False),
(b'C5H66P0=', b'abcd', False),
(b'C5H66P35', b'abcde', False),
(b'', b'', True),
(b'00======', b'\x00', True),
(b'C4======', b'a', True),
(b'C5H0====', b'ab', True),
(b'C5H66===', b'abc', True),
(b'C5H66P0=', b'abcd', True),
(b'C5H66P35', b'abcde', True),
(b'c4======', b'a', True),
(b'c5h0====', b'ab', True),
(b'c5h66===', b'abc', True),
(b'c5h66p0=', b'abcd', True),
(b'c5h66p35', b'abcde', True),
]
for to_decode, expected, casefold in test_cases:
with self.subTest(to_decode=to_decode, casefold=casefold):
self.assertEqual(base64.b32hexdecode(to_decode, casefold),
expected)
self.assertEqual(base64.b32hexdecode(to_decode.decode('ascii'),
casefold), expected)
def test_b32hexdecode_other_types(self):
self.check_other_types(base64.b32hexdecode, b'C5H66===', b'abc')
self.check_decode_type_errors(base64.b32hexdecode)
def test_b32hexdecode_padded(self):
b32hexdecode = base64.b32hexdecode
def check(data, expected):
if b'=' in data:
with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
b32hexdecode(data, padded=False)
self.assertEqual(b32hexdecode(data, padded=False, ignorechars=b'='),
expected)
data = data.replace(b'=', b'')
self.assertEqual(b32hexdecode(data, padded=False), expected)
check(b'', b'')
check(b'C4======', b'a')
check(b'C5H0====', b'ab')
check(b'C5H66===', b'abc')
check(b'C5H66P0=', b'abcd')
check(b'C5H66P35', b'abcde')
check(b'C=5H66P35', b'abcde')
check(b'C5=H66P35', b'abcde')
check(b'C5H=66P35', b'abcde')
check(b'C5H6=6P35', b'abcde')
check(b'C5H66=P35', b'abcde')
check(b'C5H66P=35', b'abcde')
check(b'C5H66P3=5', b'abcde')
def test_b32hexdecode_ignorechars(self):
self._common_test_ignorechars(base64.b32hexdecode)
eq = self.assertEqual
eq(base64.b32hexdecode(b'C5H6\n 6P35\n', ignorechars=b' \n'), b'abcde')
eq(base64.b32hexdecode(b'C5H6\n 6P35\n', ignorechars=bytearray(b' \n')), b'abcde')
eq(base64.b32hexdecode(b'========C5H66P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C=======5H66P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5======H66P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H=====66P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H6====6P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H66===P35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H66P==35', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H66P3=5', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H66P35=', ignorechars=b'='), b'abcde')
eq(base64.b32hexdecode(b'C5H0======', ignorechars=b'='), b'ab')
eq(base64.b32hexdecode(b'c5h66p35cpjmg===', ignorechars=b'cghjmp'),
b')\x8c2')
eq(base64.b32hexdecode(b'c5h66p35cpjmg===', casefold=True,
ignorechars=b'cghjmp'),
b'abcdefgh')
def test_b32hexdecode_error(self):
tests = [b'abc', b'ABCDEF==', b'==ABCDEF', b'c4======']
prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
for i in range(0, 17):
if i:
tests.append(b'='*i)
for prefix in prefixes:
if len(prefix) + i != 8:
tests.append(prefix + b'='*i)
for data in tests:
with self.subTest(to_decode=data):
with self.assertRaises(binascii.Error):
base64.b32hexdecode(data)
with self.assertRaises(binascii.Error):
base64.b32hexdecode(data.decode('ascii'))
@hypothesis.given(
payload=hypothesis.strategies.binary(),
casefold=hypothesis.strategies.booleans())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
def test_b32_hexencode_decode_round_trip(self, payload, casefold):
encoded = base64.b32hexencode(payload)
decoded = base64.b32hexdecode(encoded, casefold=casefold)
self.assertEqual(payload, decoded)
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_b16encode_wrapcol(self):
eq = self.assertEqual
b = b'\x01\x02\xab\xcd\xef'
self._common_test_wrapcol(base64.b16encode, b)
eq(base64.b16encode(b, wrapcol=4), b'0102\nABCD\nEF')
eq(base64.b16encode(b, wrapcol=5), b'0102\nABCD\nEF')
eq(base64.b16encode(b, wrapcol=1), b'01\n02\nAB\nCD\nEF')
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')
# Non-alphabet characters
self.assertRaises(binascii.Error, base64.b16decode, '0102AG')
# Incorrect "padding"
self.assertRaises(binascii.Error, base64.b16decode, '010')
def test_b16decode_ignorechars(self):
self._common_test_ignorechars(base64.b16decode)
eq = self.assertEqual
eq(base64.b16decode(b'A B\nC D\n', ignorechars=b' \n'), b'\xab\xcd')
eq(base64.b16decode(b'A B\nC D\n', ignorechars=bytearray(b' \n')), b'\xab\xcd')
eq(base64.b16decode(b'aBcD', ignorechars=b'ac'), b'\xbd')
eq(base64.b16decode(b'aBcD', casefold=True, ignorechars=b'ac'), b'\xab\xcd')
@hypothesis.given(
payload=hypothesis.strategies.binary(),
casefold=hypothesis.strategies.booleans())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
def test_b16_encode_decode_round_trip(self, payload, casefold):
endoded = base64.b16encode(payload)
decoded = base64.b16decode(endoded, casefold=casefold)
self.assertEqual(payload, decoded)
def test_a85encode(self):
eq = self.assertEqual
tests = {
b'': b'',
b"www.python.org": b'GB\\6`E-ZP=Df.1GEb>',
bytes(range(255)): b"""!!*-'"9eu7#RLhG$k3[W&.oNg'GVB"(`=52*$$"""
b"""(B+<_pR,UFcb-n-Vr/1iJ-0JP==1c70M3&s#]4?Ykm5X@_(6q'R884cE"""
b"""H9MJ8X:f1+h<)lt#=BSg3>[:ZC?t!MSA7]@cBPD3sCi+'.E,fo>FEMbN"""
b"""G^4U^I!pHnJ:W<)KS>/9Ll%"IN/`jYOHG]iPa.Q$R$jD4S=Q7DTV8*TU"""
b"""nsrdW2ZetXKAY/Yd(L?['d?O\\@K2_]Y2%o^qmn*`5Ta:aN;TJbg"GZd"""
b"""*^:jeCE.%f\\,!5gtgiEi8N\\UjQ5OekiqBum-X60nF?)@o_%qPq"ad`"""
b"""r;HT""",
b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b"0123456789!@#0^&*();:<>,. []{}":
b'@:E_WAS,RgBkhF"D/O92EH6,BF`qtRH$VbC6UX@47n?3D92&&T'
b":Jand;cHat='/U/0JP==1c70M3&r-I,;<FN.OZ`-3]oSW/g+A(H[P",
b"no padding..": b'DJpY:@:Wn_DJ(RS',
b"zero compression\0\0\0\0": b'H=_,8+Cf>,E,oN2F(oQ1z',
b"zero compression\0\0\0": b'H=_,8+Cf>,E,oN2F(oQ1!!!!',
b"Boundary:\0\0\0\0": b'6>q!aA79M(3WK-[!!',
b"Space compr: ": b';fH/TAKYK$D/aMV+<VdL',
b'\xff': b'rr',
b'\xff'*2: b's8N',
b'\xff'*3: b's8W*',
b'\xff'*4: b's8W-!',
}
for data, res in tests.items():
eq(base64.a85encode(data), res, data)
eq(base64.a85encode(data, adobe=False), res, data)
eq(base64.a85encode(data, adobe=True), b'<~' + res + b'~>', data)
self.check_other_types(base64.a85encode, b"www.python.org",
b'GB\\6`E-ZP=Df.1GEb>')
self.assertRaises(TypeError, base64.a85encode, "")
eq(base64.a85encode(b' '*8, foldspaces=True, adobe=False), b'yy')
eq(base64.a85encode(b' '*7, foldspaces=True, adobe=False), b'y+<Vd')
eq(base64.a85encode(b' '*6, foldspaces=True, adobe=False), b'y+<U')
eq(base64.a85encode(b' '*5, foldspaces=True, adobe=False), b'y+9')
def test_a85encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.a85encode, b)
eq(base64.a85encode(b, wrapcol=7), b'GB\\6`E-\nZP=Df.1\nGEb>')
eq(base64.a85encode(b"\0\0\0\0www.python.org", wrapcol=7),
b'zGB\\6`E\n-ZP=Df.\n1GEb>')
eq(base64.a85encode(b, wrapcol=75), b'GB\\6`E-ZP=Df.1GEb>')
eq(base64.a85encode(b, wrapcol=1),
b'G\nB\n\\\n6\n`\nE\n-\nZ\nP\n=\nD\nf\n.\n1\nG\nE\nb\n>')
eq(base64.a85encode(b, wrapcol=7, adobe=True),
b'<~GB\\6`\nE-ZP=Df\n.1GEb>\n~>')
eq(base64.a85encode(b, wrapcol=1),
b'G\nB\n\\\n6\n`\nE\n-\nZ\nP\n=\nD\nf\n.\n1\nG\nE\nb\n>')
eq(base64.a85encode(b, wrapcol=1, adobe=True),
b'<~\nGB\n\\6\n`E\n-Z\nP=\nDf\n.1\nGE\nb>\n~>')
with self.assertRaises(ValueError):
base64.a85encode(b, wrapcol=-7, adobe=True)
eq(base64.a85encode(b'', wrapcol=1, adobe=True), b'<~\n~>')
eq(base64.a85encode(b'', wrapcol=3, adobe=True), b'<~\n~>')
eq(base64.a85encode(b'', wrapcol=4, adobe=True), b'<~~>')
def test_b85encode(self):
eq = self.assertEqual
tests = {
b'': b'',
b'www.python.org': b'cXxL#aCvlSZ*DGca%T',
bytes(range(255)): b"""009C61O)~M2nh-c3=Iws5D^j+6crX17#SKH9337X"""
b"""AR!_nBqb&%C@Cr{EG;fCFflSSG&MFiI5|2yJUu=?KtV!7L`6nNNJ&ad"""
b"""OifNtP*GA-R8>}2SXo+ITwPvYU}0ioWMyV&XlZI|Y;A6DaB*^Tbai%j"""
b"""czJqze0_d@fPsR8goTEOh>41ejE#<ukdcy;l$Dm3n3<ZJoSmMZprN9p"""
b"""q@|{(sHv)}tgWuEu(7hUw6(UkxVgH!yuH4^z`?@9#Kp$P$jQpf%+1cv"""
b"""(9zP<)YaD4*xB0K+}+;a;Njxq<mKk)=;`X~?CtLF@bU8V^!4`l`1$(#"""
b"""{Qdp""",
b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
b"""0123456789!@#0^&*();:<>,. []{}""":
b"""VPa!sWoBn+X=-b1ZEkOHadLBXb#`}nd3r%YLqtVJM@UIZOH55pPf$@("""
b"""Q&d$}S6EqEFflSSG&MFiI5{CeBQRbjDkv#CIy^osE+AW7dwl""",
b'no padding..': b'Zf_uPVPs@!Zf7no',
b'zero compression\x00\x00\x00\x00': b'dS!BNAY*TBaB^jHb7^mG00000',
b'zero compression\x00\x00\x00': b'dS!BNAY*TBaB^jHb7^mG0000',
b"""Boundary:\x00\x00\x00\x00""": b"""LT`0$WMOi7IsgCw00""",
b'Space compr: ': b'Q*dEpWgug3ZE$irARr(h',
b'\xff': b'{{',
b'\xff'*2: b'|Nj',
b'\xff'*3: b'|Ns9',
b'\xff'*4: b'|NsC0',
}
for data, res in tests.items():
eq(base64.b85encode(data), res)
self.check_other_types(base64.b85encode, b"www.python.org",
b'cXxL#aCvlSZ*DGca%T')
def test_b85encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.b85encode, b)
eq(base64.b85encode(b, wrapcol=10), b'cXxL#aCvlS\nZ*DGca%T')
eq(base64.b85encode(b, wrapcol=14), b'cXxL#aCvlS\nZ*DGca%T')
eq(base64.b85encode(b, wrapcol=1), b'cXxL#\naCvlS\nZ*DGc\na%T')
def test_z85encode(self):
eq = self.assertEqual
tests = {
b'': b'',
b'\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B': b'HelloWorld',
b'www.python.org': b'CxXl-AcVLsz/dgCA+t',
bytes(range(255)): b"""009c61o!#m2NH?C3>iWS5d]J*6CRx17-skh9337x"""
b"""ar.{NbQB=+c[cR@eg&FcfFLssg=mfIi5%2YjuU>)kTv.7l}6Nnnj=AD"""
b"""oIFnTp/ga?r8($2sxO*itWpVyu$0IOwmYv=xLzi%y&a6dAb/]tBAI+J"""
b"""CZjQZE0{D[FpSr8GOteoH(41EJe-<UKDCY&L:dM3N3<zjOsMmzPRn9P"""
b"""Q[%@^ShV!$TGwUeU^7HuW6^uKXvGh.YUh4]Z})[9-kP:p:JqPF+*1CV"""
b"""^9Zp<!yAd4/Xb0k*$*&A&nJXQ<MkK!>&}x#)cTlf[Bu8v].4}L}1:^-"""
b"""@qDP""",
b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
b"""0123456789!@#0^&*();:<>,. []{}""":
b"""vpA.SwObN*x>?B1zeKohADlbxB-}$ND3R+ylQTvjm[uizoh55PpF:[^"""
b"""q=D:$s6eQefFLssg=mfIi5@cEbqrBJdKV-ciY]OSe*aw7DWL""",
b'no padding..': b'zF{UpvpS[.zF7NO',
b'zero compression\x00\x00\x00\x00': b'Ds.bnay/tbAb]JhB7]Mg00000',
b'zero compression\x00\x00\x00': b'Ds.bnay/tbAb]JhB7]Mg0000',
b"""Boundary:\x00\x00\x00\x00""": b"""lt}0:wmoI7iSGcW00""",
b'Space compr: ': b'q/DePwGUG3ze:IRarR^H',
b'\xff': b'@@',
b'\xff'*2: b'%nJ',
b'\xff'*3: b'%nS9',
b'\xff'*4: b'%nSc0',
}
for data, res in tests.items():
eq(base64.z85encode(data), res)
self.check_other_types(base64.z85encode, b"www.python.org",
b'CxXl-AcVLsz/dgCA+t')
def test_z85encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
self._common_test_wrapcol(base64.z85encode, b)
eq(base64.z85encode(b, wrapcol=10), b'CxXl-AcVLs\nz/dgCA+t')
eq(base64.z85encode(b, wrapcol=14), b'CxXl-AcVLs\nz/dgCA+t')
eq(base64.z85encode(b, wrapcol=1), b'CxXl-\nAcVLs\nz/dgC\nA+t')
def test_a85decode(self):
eq = self.assertEqual
tests = {
b'': b'',
b'GB\\6`E-ZP=Df.1GEb>': b'www.python.org',
b"""! ! * -'"\n\t\t9eu\r\n7# RL\vhG$k3[W&.oNg'GVB"(`=52*$$"""
b"""(B+<_pR,UFcb-n-Vr/1iJ-0JP==1c70M3&s#]4?Ykm5X@_(6q'R884cE"""
b"""H9MJ8X:f1+h<)lt#=BSg3>[:ZC?t!MSA7]@cBPD3sCi+'.E,fo>FEMbN"""
b"""G^4U^I!pHnJ:W<)KS>/9Ll%"IN/`jYOHG]iPa.Q$R$jD4S=Q7DTV8*TU"""
b"""nsrdW2ZetXKAY/Yd(L?['d?O\\@K2_]Y2%o^qmn*`5Ta:aN;TJbg"GZd"""
b"""*^:jeCE.%f\\,!5gtgiEi8N\\UjQ5OekiqBum-X60nF?)@o_%qPq"ad`"""
b"""r;HT""": bytes(range(255)),
b"""@:E_WAS,RgBkhF"D/O92EH6,BF`qtRH$VbC6UX@47n?3D92&&T:Jand;c"""
b"""Hat='/U/0JP==1c70M3&r-I,;<FN.OZ`-3]oSW/g+A(H[P""":
b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234'
b'56789!@#0^&*();:<>,. []{}',
b'DJpY:@:Wn_DJ(RS': b'no padding..',
b'H=_,8+Cf>,E,oN2F(oQ1z': b'zero compression\x00\x00\x00\x00',
b'H=_,8+Cf>,E,oN2F(oQ1!!!!': b'zero compression\x00\x00\x00',
b'6>q!aA79M(3WK-[!!': b"Boundary:\x00\x00\x00\x00",
b';fH/TAKYK$D/aMV+<VdL': b'Space compr: ',
b'rr': b'\xff',
b's8N': b'\xff'*2,
b's8W*': b'\xff'*3,
b's8W-!': b'\xff'*4,
}
for data, res in tests.items():
eq(base64.a85decode(data), res, data)
eq(base64.a85decode(data, adobe=False), res, data)
eq(base64.a85decode(data.decode("ascii"), adobe=False), res, data)
eq(base64.a85decode(b'<~' + data + b'~>', adobe=True), res, data)
eq(base64.a85decode(data + b'~>', adobe=True), res, data)
eq(base64.a85decode('<~%s~>' % data.decode("ascii"), adobe=True),
res, data)
eq(base64.a85decode(b'yy', foldspaces=True, adobe=False), b' '*8)
eq(base64.a85decode(b'y+<Vd', foldspaces=True, adobe=False), b' '*7)
eq(base64.a85decode(b'y+<U', foldspaces=True, adobe=False), b' '*6)
eq(base64.a85decode(b'y+9', foldspaces=True, adobe=False), b' '*5)
eq(base64.a85decode(b'aaaaay', foldspaces=True), b'\xc9\x80\x0b@ ')
self.check_other_types(base64.a85decode, b'GB\\6`E-ZP=Df.1GEb>',
b"www.python.org")
def test_b85decode(self):
eq = self.assertEqual
tests = {
b'': b'',
b'cXxL#aCvlSZ*DGca%T': b'www.python.org',
b"""009C61O)~M2nh-c3=Iws5D^j+6crX17#SKH9337X"""
b"""AR!_nBqb&%C@Cr{EG;fCFflSSG&MFiI5|2yJUu=?KtV!7L`6nNNJ&ad"""
b"""OifNtP*GA-R8>}2SXo+ITwPvYU}0ioWMyV&XlZI|Y;A6DaB*^Tbai%j"""
b"""czJqze0_d@fPsR8goTEOh>41ejE#<ukdcy;l$Dm3n3<ZJoSmMZprN9p"""
b"""q@|{(sHv)}tgWuEu(7hUw6(UkxVgH!yuH4^z`?@9#Kp$P$jQpf%+1cv"""
b"""(9zP<)YaD4*xB0K+}+;a;Njxq<mKk)=;`X~?CtLF@bU8V^!4`l`1$(#"""
b"""{Qdp""": bytes(range(255)),
b"""VPa!sWoBn+X=-b1ZEkOHadLBXb#`}nd3r%YLqtVJM@UIZOH55pPf$@("""
b"""Q&d$}S6EqEFflSSG&MFiI5{CeBQRbjDkv#CIy^osE+AW7dwl""":
b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
b"""0123456789!@#0^&*();:<>,. []{}""",
b'Zf_uPVPs@!Zf7no': b'no padding..',
b'dS!BNAY*TBaB^jHb7^mG00000': b'zero compression\x00\x00\x00\x00',
b'dS!BNAY*TBaB^jHb7^mG0000': b'zero compression\x00\x00\x00',
b"""LT`0$WMOi7IsgCw00""": b"""Boundary:\x00\x00\x00\x00""",
b'Q*dEpWgug3ZE$irARr(h': b'Space compr: ',
b'{{': b'\xff',
b'|Nj': b'\xff'*2,
b'|Ns9': b'\xff'*3,
b'|NsC0': b'\xff'*4,
}
for data, res in tests.items():
eq(base64.b85decode(data), res)
eq(base64.b85decode(data.decode("ascii")), res)
self.check_other_types(base64.b85decode, b'cXxL#aCvlSZ*DGca%T',
b"www.python.org")
def test_z85decode(self):
eq = self.assertEqual
tests = {
b'': b'',
b'CxXl-AcVLsz/dgCA+t': b'www.python.org',
b"""009c61o!#m2NH?C3>iWS5d]J*6CRx17-skh9337x"""
b"""ar.{NbQB=+c[cR@eg&FcfFLssg=mfIi5%2YjuU>)kTv.7l}6Nnnj=AD"""
b"""oIFnTp/ga?r8($2sxO*itWpVyu$0IOwmYv=xLzi%y&a6dAb/]tBAI+J"""
b"""CZjQZE0{D[FpSr8GOteoH(41EJe-<UKDCY&L:dM3N3<zjOsMmzPRn9P"""
b"""Q[%@^ShV!$TGwUeU^7HuW6^uKXvGh.YUh4]Z})[9-kP:p:JqPF+*1CV"""
b"""^9Zp<!yAd4/Xb0k*$*&A&nJXQ<MkK!>&}x#)cTlf[Bu8v].4}L}1:^-"""
b"""@qDP""": bytes(range(255)),
b"""vpA.SwObN*x>?B1zeKohADlbxB-}$ND3R+ylQTvjm[uizoh55PpF:[^"""
b"""q=D:$s6eQefFLssg=mfIi5@cEbqrBJdKV-ciY]OSe*aw7DWL""":
b"""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
b"""0123456789!@#0^&*();:<>,. []{}""",
b'zF{UpvpS[.zF7NO': b'no padding..',
b'Ds.bnay/tbAb]JhB7]Mg00000': b'zero compression\x00\x00\x00\x00',
b'Ds.bnay/tbAb]JhB7]Mg0000': b'zero compression\x00\x00\x00',
b"""lt}0:wmoI7iSGcW00""": b"""Boundary:\x00\x00\x00\x00""",
b'q/DePwGUG3ze:IRarR^H': b'Space compr: ',
b'@@': b'\xff',
b'%nJ': b'\xff'*2,
b'%nS9': b'\xff'*3,
b'%nSc0': b'\xff'*4,
}
for data, res in tests.items():
eq(base64.z85decode(data), res)
eq(base64.z85decode(data.decode("ascii")), res)
self.check_other_types(base64.z85decode, b'CxXl-AcVLsz/dgCA+t',
b'www.python.org')
def test_a85_padding(self):
eq = self.assertEqual
eq(base64.a85encode(b"x", pad=True), b'GQ7^D')
eq(base64.a85encode(b"xx", pad=True), b"G^'2g")
eq(base64.a85encode(b"xxx", pad=True), b'G^+H5')
eq(base64.a85encode(b"xxxx", pad=True), b'G^+IX')
eq(base64.a85encode(b"xxxxx", pad=True), b'G^+IXGQ7^D')
eq(base64.a85decode(b'GQ7^D'), b"x\x00\x00\x00")
eq(base64.a85decode(b"G^'2g"), b"xx\x00\x00")
eq(base64.a85decode(b'G^+H5'), b"xxx\x00")
eq(base64.a85decode(b'G^+IX'), b"xxxx")
eq(base64.a85decode(b'G^+IXGQ7^D'), b"xxxxx\x00\x00\x00")
eq(base64.a85encode(b"\x00", pad=True), b'z')
eq(base64.a85encode(b"\x00"*2, pad=True), b'z')
eq(base64.a85encode(b"\x00"*3, pad=True), b'z')
eq(base64.a85encode(b"\x00"*4, pad=True), b'z')
eq(base64.a85encode(b"\x00"*5, pad=True), b'zz')
def test_b85_padding(self):
eq = self.assertEqual
eq(base64.b85encode(b"x", pad=True), b'cmMzZ')
eq(base64.b85encode(b"xx", pad=True), b'cz6H+')
eq(base64.b85encode(b"xxx", pad=True), b'czAdK')
eq(base64.b85encode(b"xxxx", pad=True), b'czAet')
eq(base64.b85encode(b"xxxxx", pad=True), b'czAetcmMzZ')
eq(base64.b85decode(b'cmMzZ'), b"x\x00\x00\x00")
eq(base64.b85decode(b'cz6H+'), b"xx\x00\x00")
eq(base64.b85decode(b'czAdK'), b"xxx\x00")
eq(base64.b85decode(b'czAet'), b"xxxx")
eq(base64.b85decode(b'czAetcmMzZ'), b"xxxxx\x00\x00\x00")
def test_z85_padding(self):
eq = self.assertEqual
eq(base64.z85encode(b"x", pad=True), b'CMmZz')
eq(base64.z85encode(b"xx", pad=True), b'CZ6h*')
eq(base64.z85encode(b"xxx", pad=True), b'CZaDk')
eq(base64.z85encode(b"xxxx", pad=True), b'CZaET')
eq(base64.z85encode(b"xxxxx", pad=True), b'CZaETCMmZz')
eq(base64.z85decode(b'CMmZz'), b"x\x00\x00\x00")
eq(base64.z85decode(b'CZ6h*'), b"xx\x00\x00")
eq(base64.z85decode(b'CZaDk'), b"xxx\x00")
eq(base64.z85decode(b'CZaET'), b"xxxx")
eq(base64.z85decode(b'CZaETCMmZz'), b"xxxxx\x00\x00\x00")
def test_a85decode_errors(self):
illegal = (set(range(32)) | set(range(118, 256))) - set(b' \t\n\r\v')
for c in illegal:
with self.assertRaises(ValueError, msg=bytes([c])):
base64.a85decode(b'!!!!' + bytes([c]))
with self.assertRaises(ValueError, msg=bytes([c])):
base64.a85decode(b'!!!!' + bytes([c]), adobe=False)
with self.assertRaises(ValueError, msg=bytes([c])):
base64.a85decode(b'<~!!!!' + bytes([c]) + b'~>', adobe=True)
self.assertRaises(ValueError, base64.a85decode,
b"malformed", adobe=True)
self.assertRaises(ValueError, base64.a85decode,
b"<~still malformed", adobe=True)
# With adobe=False (the default), Adobe framing markers are disallowed
self.assertRaises(ValueError, base64.a85decode,
b"<~~>")
self.assertRaises(ValueError, base64.a85decode,
b"<~~>", adobe=False)
base64.a85decode(b"<~~>", adobe=True) # sanity check
self.assertRaises(ValueError, base64.a85decode,
b"abcx", adobe=False)
self.assertRaises(ValueError, base64.a85decode,
b"abcdey", adobe=False)
self.assertRaises(ValueError, base64.a85decode,
b"a b\nc", adobe=False, ignorechars=b"")
self.assertRaises(ValueError, base64.a85decode, b's', adobe=False)
self.assertRaises(ValueError, base64.a85decode, b's8', adobe=False)
self.assertRaises(ValueError, base64.a85decode, b's8W', adobe=False)
self.assertRaises(ValueError, base64.a85decode, b's8W-', adobe=False)
self.assertRaises(ValueError, base64.a85decode, b's8W-"', adobe=False)
self.assertRaises(ValueError, base64.a85decode, b'aaaay',
foldspaces=True)
self.assertEqual(base64.a85decode(b"a b\nc", ignorechars=b" \n"),
b'\xc9\x89')
self._common_test_ignorechars(base64.a85decode)
def test_b85decode_errors(self):
illegal = list(range(33)) + \
list(b'"\',./:[\\]') + \
list(range(128, 256))
for c in illegal:
b = bytes([c])
with self.assertRaises(ValueError, msg=b):
base64.b85decode(b'0000' + b)
self.assertEqual(base64.b85decode(b'0000' + b, ignorechars=b),
b'\x00\x00\x00')
self._common_test_ignorechars(base64.b85decode)
self.assertRaises(ValueError, base64.b85decode, b'|')
self.assertRaises(ValueError, base64.b85decode, b'|N')
self.assertRaises(ValueError, base64.b85decode, b'|Ns')
self.assertRaises(ValueError, base64.b85decode, b'|NsC')
self.assertRaises(ValueError, base64.b85decode, b'|NsC1')
def test_z85decode_errors(self):
illegal = list(range(33)) + \
list(b'"\',;_`|\\~') + \
list(range(128, 256))
for c in illegal:
b = bytes([c])
with self.assertRaises(ValueError, msg=b):
base64.z85decode(b'0000' + b)
self.assertEqual(base64.z85decode(b'0000' + b, ignorechars=b),
b'\x00\x00\x00')
self._common_test_ignorechars(base64.z85decode)
# b'\xff\xff\xff\xff' encodes to b'%nSc0', the following will overflow:
self.assertRaises(ValueError, base64.z85decode, b'%')
self.assertRaises(ValueError, base64.z85decode, b'%n')
self.assertRaises(ValueError, base64.z85decode, b'%nS')
self.assertRaises(ValueError, base64.z85decode, b'%nSc')
self.assertRaises(ValueError, base64.z85decode, b'%nSc1')
def add_padding(self, payload):
"""Add the expected padding for test_?85_encode_decode_round_trip."""
if len(payload) % 4 != 0:
padding = b"\0" * ((-len(payload)) % 4)
payload = payload + padding
return payload
@hypothesis.given(
payload=hypothesis.strategies.binary(),
foldspaces=hypothesis.strategies.booleans(),
wrapcol=(
hypothesis.strategies.just(0)
| hypothesis.strategies.integers(1, 1000)),
pad=hypothesis.strategies.booleans(),
adobe=hypothesis.strategies.booleans(),
)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 0, False, False)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 20, True, True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 0, False, True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 20, True, False)
def test_a85_encode_decode_round_trip(
self, payload, foldspaces, wrapcol, pad, adobe
):
encoded = base64.a85encode(
payload, foldspaces=foldspaces, wrapcol=wrapcol,
pad=pad, adobe=adobe,
)
if wrapcol:
if adobe and wrapcol == 1:
# "adobe" needs wrapcol to be at least 2.
# a85decode quietly uses 2 if 1 is given; it's not worth
# loudly deprecating this behavior.
wrapcol = 2
for line in encoded.splitlines(keepends=False):
self.assertLessEqual(len(line), wrapcol)
if adobe:
self.assertTrue(encoded.startswith(b'<~'))
self.assertTrue(encoded.endswith(b'~>'))
decoded = base64.a85decode(encoded, foldspaces=foldspaces, adobe=adobe)
if pad:
payload = self.add_padding(payload)
self.assertEqual(payload, decoded)
@hypothesis.given(
payload=hypothesis.strategies.binary(),
pad=hypothesis.strategies.booleans())
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
def test_b85_encode_decode_round_trip(self, payload, pad):
encoded = base64.b85encode(payload, pad=pad)
if pad:
payload = self.add_padding(payload)
decoded = base64.b85decode(encoded)
self.assertEqual(payload, decoded)
def test_decode_nonascii_str(self):
decode_funcs = (base64.b64decode,
base64.standard_b64decode,
base64.urlsafe_b64decode,
base64.b32decode,
base64.b16decode,
base64.b85decode,
base64.a85decode,
base64.z85decode)
for f in decode_funcs:
self.assertRaises(ValueError, f, 'with non-ascii \xcb')
def test_ErrorHeritage(self):
self.assertIsSubclass(binascii.Error, ValueError)
def test_RFC4648_test_cases(self):
# test cases from RFC 4648 section 10
b64encode = base64.b64encode
b32hexencode = base64.b32hexencode
b32encode = base64.b32encode
b16encode = base64.b16encode
self.assertEqual(b64encode(b""), b"")
self.assertEqual(b64encode(b"f"), b"Zg==")
self.assertEqual(b64encode(b"fo"), b"Zm8=")
self.assertEqual(b64encode(b"foo"), b"Zm9v")
self.assertEqual(b64encode(b"foob"), b"Zm9vYg==")
self.assertEqual(b64encode(b"fooba"), b"Zm9vYmE=")
self.assertEqual(b64encode(b"foobar"), b"Zm9vYmFy")
self.assertEqual(b32encode(b""), b"")
self.assertEqual(b32encode(b"f"), b"MY======")
self.assertEqual(b32encode(b"fo"), b"MZXQ====")
self.assertEqual(b32encode(b"foo"), b"MZXW6===")
self.assertEqual(b32encode(b"foob"), b"MZXW6YQ=")
self.assertEqual(b32encode(b"fooba"), b"MZXW6YTB")
self.assertEqual(b32encode(b"foobar"), b"MZXW6YTBOI======")
self.assertEqual(b32hexencode(b""), b"")
self.assertEqual(b32hexencode(b"f"), b"CO======")
self.assertEqual(b32hexencode(b"fo"), b"CPNG====")
self.assertEqual(b32hexencode(b"foo"), b"CPNMU===")
self.assertEqual(b32hexencode(b"foob"), b"CPNMUOG=")
self.assertEqual(b32hexencode(b"fooba"), b"CPNMUOJ1")
self.assertEqual(b32hexencode(b"foobar"), b"CPNMUOJ1E8======")
self.assertEqual(b16encode(b""), b"")
self.assertEqual(b16encode(b"f"), b"66")
self.assertEqual(b16encode(b"fo"), b"666F")
self.assertEqual(b16encode(b"foo"), b"666F6F")
self.assertEqual(b16encode(b"foob"), b"666F6F62")
self.assertEqual(b16encode(b"fooba"), b"666F6F6261")
self.assertEqual(b16encode(b"foobar"), b"666F6F626172")
class TestMain(unittest.TestCase):
def tearDown(self):
if os.path.exists(os_helper.TESTFN):
os.unlink(os_helper.TESTFN)
def get_output(self, *args):
return script_helper.assert_python_ok('-m', 'base64', *args).out
def test_encode_file(self):
with open(os_helper.TESTFN, 'wb') as fp:
fp.write(b'a\xffb\n')
output = self.get_output('-e', os_helper.TESTFN)
self.assertEqual(output.rstrip(), b'Yf9iCg==')
def test_encode_from_stdin(self):
with script_helper.spawn_python('-m', 'base64', '-e') as proc:
out, err = proc.communicate(b'a\xffb\n')
self.assertEqual(out.rstrip(), b'Yf9iCg==')
self.assertIsNone(err)
def test_decode(self):
with open(os_helper.TESTFN, 'wb') as fp:
fp.write(b'Yf9iCg==')
output = self.get_output('-d', os_helper.TESTFN)
self.assertEqual(output.rstrip(), b'a\xffb')
def test_prints_usage_with_help_flag(self):
output = self.get_output('-h')
self.assertIn(b'usage: ', output)
self.assertIn(b'-d, -u: decode', output)
def test_prints_usage_with_invalid_flag(self):
output = script_helper.assert_python_failure('-m', 'base64', '-x').err
self.assertIn(b'usage: ', output)
self.assertIn(b'-d, -u: decode', output)
if __name__ == '__main__':
unittest.main()