cpython/Lib/test/test_binascii.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

1376 lines
60 KiB
Python

"""Test the binascii C module."""
import unittest
import binascii
import array
import re
import sys
from test.support import bigmemtest, _1G, _4G, check_impl_detail
from test.support.hypothesis_helper import hypothesis
# Note: "*_hex" functions are aliases for "(un)hexlify"
b2a_functions = ['b2a_ascii85', 'b2a_base32', 'b2a_base64', 'b2a_base85',
'b2a_hex', 'b2a_qp', 'b2a_uu',
'hexlify']
a2b_functions = ['a2b_ascii85', 'a2b_base32', 'a2b_base64', 'a2b_base85',
'a2b_hex', 'a2b_qp', 'a2b_uu',
'unhexlify']
all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx']
class BinASCIITest(unittest.TestCase):
type2test = bytes
# Create binary test data
rawdata = b"The quick brown fox jumps over the lazy dog.\r\n"
# Be slow so we don't depend on other modules
rawdata += bytes(range(256))
rawdata += b'\0'*32
rawdata += b' '*32
rawdata += b"\r\nHello world.\n"
def setUp(self):
self.data = self.type2test(self.rawdata)
def assertConversion(self, original, converted, restored, **kwargs):
self.assertIsInstance(original, bytes)
self.assertIsInstance(converted, bytes)
self.assertIsInstance(restored, bytes)
if converted:
self.assertLess(max(converted), 128)
self.assertEqual(original, restored, msg=f'{self.type2test=} {kwargs=}')
def test_exceptions(self):
# Check module exceptions
self.assertIsSubclass(binascii.Error, Exception)
self.assertIsSubclass(binascii.Incomplete, Exception)
def test_constants(self):
self.assertEqual(binascii.BASE64_ALPHABET,
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz'
b'0123456789+/')
self.assertEqual(binascii.URLSAFE_BASE64_ALPHABET,
binascii.BASE64_ALPHABET[:-2] + b'-_')
self.assertEqual(binascii.UU_ALPHABET, bytes(range(32, 32+64)))
self.assertEqual(binascii.CRYPT_ALPHABET,
b'./0123456789'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz')
self.assertEqual(binascii.BINHEX_ALPHABET,
b'!"#$%&\'()*+,-012345689'
b'@ABCDEFGHIJKLMNPQRSTUVXYZ['
b'`abcdefhijklmpqr')
self.assertEqual(binascii.BASE85_ALPHABET,
b'0123456789'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz'
b'!#$%&()*+-;<=>?@^_`{|}~')
self.assertEqual(binascii.ASCII85_ALPHABET, bytes(range(33, 33+85)))
self.assertEqual(binascii.Z85_ALPHABET,
b'0123456789'
b'abcdefghijklmnopqrstuvwxyz'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'.-:+=^!/*?&<>()[]{}@%$#')
self.assertEqual(binascii.BASE32_ALPHABET,
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
self.assertEqual(binascii.BASE32HEX_ALPHABET,
b'0123456789ABCDEFGHIJKLMNOPQRSTUV')
def test_functions(self):
# Check presence of all functions
for name in all_functions:
self.assertHasAttr(getattr(binascii, name), '__call__')
self.assertRaises(TypeError, getattr(binascii, name))
def test_returned_value(self):
# Limit to the minimum of all limits (b2a_uu)
MAX_ALL = 45
raw = self.rawdata[:MAX_ALL]
for fa, fb in zip(a2b_functions, b2a_functions):
a2b = getattr(binascii, fa)
b2a = getattr(binascii, fb)
try:
a = b2a(self.type2test(raw))
res = a2b(self.type2test(a))
except Exception as err:
self.fail("{}/{} conversion raises {!r}".format(fb, fa, err))
self.assertEqual(res, raw, "{}/{} conversion: "
"{!r} != {!r}".format(fb, fa, res, raw))
self.assertConversion(raw, a, res)
self.assertIsInstance(binascii.crc_hqx(raw, 0), int)
self.assertIsInstance(binascii.crc32(raw), int)
def test_base64valid(self):
# Test base64 with valid data
MAX_BASE64 = 57
lines = []
for i in range(0, len(self.rawdata), MAX_BASE64):
b = self.type2test(self.rawdata[i:i+MAX_BASE64])
a = binascii.b2a_base64(b)
lines.append(a)
res = bytes()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_base64(a)
res += b
self.assertEqual(res, self.rawdata)
def test_base64invalid(self):
# Test base64 with random invalid characters sprinkled throughout
# (This requires a new version of binascii.)
MAX_BASE64 = 57
lines = []
for i in range(0, len(self.data), MAX_BASE64):
b = self.type2test(self.rawdata[i:i+MAX_BASE64])
a = binascii.b2a_base64(b)
lines.append(a)
fillers = bytearray()
valid = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"
for i in range(256):
if i not in valid:
fillers.append(i)
def addnoise(line):
noise = fillers
ratio = len(line) // len(noise)
res = bytearray()
while line and noise:
if len(line) // len(noise) > ratio:
c, line = line[0], line[1:]
else:
c, noise = noise[0], noise[1:]
res.append(c)
return res + noise + line
res = bytearray()
for line in map(addnoise, lines):
a = self.type2test(line)
b = binascii.a2b_base64(a)
res += b
self.assertEqual(res, self.rawdata)
# Test base64 with just invalid characters, which should return
# empty strings. TBD: shouldn't it raise an exception instead ?
self.assertEqual(binascii.a2b_base64(self.type2test(fillers)), b'')
def test_base64_bad_padding(self):
# Test malformed padding
def _assertRegexTemplate(assert_regex, data,
non_strict_mode_expected_result, **kwargs):
data = self.type2test(data)
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base64(data, strict_mode=True, **kwargs)
self.assertEqual(binascii.a2b_base64(data, strict_mode=False),
non_strict_mode_expected_result)
self.assertEqual(binascii.a2b_base64(data, strict_mode=True,
ignorechars=b' ='),
non_strict_mode_expected_result)
self.assertEqual(binascii.a2b_base64(data),
non_strict_mode_expected_result)
def assertLeadingPadding(*args, **kwargs):
_assertRegexTemplate(r'(?i)Leading padding', *args, **kwargs)
def assertDiscontinuousPadding(*args):
_assertRegexTemplate(r'(?i)Discontinuous padding', *args)
def assertExcessPadding(*args):
_assertRegexTemplate(r'(?i)Excess padding', *args)
def assertInvalidLength(data, *args, length=None, **kwargs):
if length is None:
length = len(data.split(b'=', 1)[0].replace(b' ', b''))
assert_regex = fr"(?i)Invalid.+number of data characters \({length}\)"
_assertRegexTemplate(assert_regex, data, *args, **kwargs)
assertExcessPadding(b'ab===', b'i')
assertExcessPadding(b'ab====', b'i')
assertExcessPadding(b'abc==', b'i\xb7')
assertExcessPadding(b'abc===', b'i\xb7')
assertExcessPadding(b'abc====', b'i\xb7')
assertExcessPadding(b'abc=====', b'i\xb7')
assertLeadingPadding(b'=', b'')
assertLeadingPadding(b'==', b'')
assertLeadingPadding(b'===', b'')
assertLeadingPadding(b'====', b'')
assertLeadingPadding(b'=====', b'')
assertLeadingPadding(b'=abcd', b'i\xb7\x1d')
assertLeadingPadding(b'==abcd', b'i\xb7\x1d')
assertLeadingPadding(b'===abcd', b'i\xb7\x1d')
assertLeadingPadding(b'====abcd', b'i\xb7\x1d')
assertLeadingPadding(b'=====abcd', b'i\xb7\x1d')
assertLeadingPadding(b' =abcd', b'i\xb7\x1d', ignorechars=b' ')
assertInvalidLength(b'a=b==', b'i')
assertInvalidLength(b'a=bc=', b'i\xb7')
assertInvalidLength(b'a=bc==', b'i\xb7')
assertInvalidLength(b'a=bcd', b'i\xb7\x1d')
assertInvalidLength(b'a=bcd=', b'i\xb7\x1d')
assertInvalidLength(b' a=b==', b'i', ignorechars=b' ')
assertInvalidLength(b'abcde=f==', b'i\xb7\x1dy')
assertInvalidLength(b' abcde=f==', b'i\xb7\x1dy', ignorechars=b' ')
assertDiscontinuousPadding(b'ab=c=', b'i\xb7')
assertDiscontinuousPadding(b'ab=cd', b'i\xb7\x1d')
assertDiscontinuousPadding(b'ab=cd==', b'i\xb7\x1d')
assertExcessPadding(b'abcd=', b'i\xb7\x1d')
assertExcessPadding(b'abcd==', b'i\xb7\x1d')
assertExcessPadding(b'abcd===', b'i\xb7\x1d')
assertExcessPadding(b'abcd====', b'i\xb7\x1d')
assertExcessPadding(b'abcd=====', b'i\xb7\x1d')
assertExcessPadding(b'abcd==', b'i\xb7\x1d')
assertExcessPadding(b'abcd===', b'i\xb7\x1d')
assertExcessPadding(b'abcd====', b'i\xb7\x1d')
assertExcessPadding(b'abcd=====', b'i\xb7\x1d')
assertExcessPadding(b'abcd=efgh', b'i\xb7\x1dy\xf8!')
assertExcessPadding(b'abcd==efgh', b'i\xb7\x1dy\xf8!')
assertExcessPadding(b'abcd===efgh', b'i\xb7\x1dy\xf8!')
assertExcessPadding(b'abcd====efgh', b'i\xb7\x1dy\xf8!')
assertExcessPadding(b'abcd=====efgh', b'i\xb7\x1dy\xf8!')
def test_a2b_base64_padded(self):
a2b_base64 = binascii.a2b_base64
t = self.type2test
def check(data, expected):
if b'=' in data:
with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
a2b_base64(t(data), padded=False, strict_mode=True)
self.assertEqual(a2b_base64(t(data), padded=False, ignorechars=b'='),
expected)
data = data.replace(b'=', b'')
self.assertEqual(a2b_base64(t(data), padded=False), expected)
self.assertEqual(a2b_base64(t(data), padded=False, strict_mode=True),
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')
def _common_test_ignorechars(self, func):
eq = self.assertEqual
empty = self.type2test(b'')
data = self.type2test(b'\n \n')
ignorechars = self.type2test(b' \n')
eq(func(empty, ignorechars=ignorechars), b'')
eq(func(empty, ignorechars=empty), b'')
eq(func(data, ignorechars=ignorechars), b'')
with self.assertRaises(binascii.Error):
func(data, ignorechars=empty)
with self.assertRaises(binascii.Error):
func(data, ignorechars=ignorechars[1:])
with self.assertRaises(binascii.Error):
func(data, ignorechars=ignorechars[:-1])
with self.assertRaises(TypeError):
func(empty, ignorechars='')
with self.assertRaises(TypeError):
func(empty, ignorechars=[])
with self.assertRaises(TypeError):
func(empty, ignorechars=None)
def test_base64_invalidchars(self):
# Test non-base64 data exceptions
self._common_test_ignorechars(binascii.a2b_base64)
def assertNonBase64Data(data, expected, ignorechars):
data = self.type2test(data)
assert_regex = r'(?i)Only base64 data'
self.assertEqual(binascii.a2b_base64(data), expected)
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base64(data, strict_mode=True)
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base64(data, ignorechars=b'')
self.assertEqual(binascii.a2b_base64(data, ignorechars=ignorechars),
expected)
self.assertEqual(binascii.a2b_base64(data, strict_mode=False, ignorechars=b''),
expected)
assertNonBase64Data(b'\nab==', b'i', ignorechars=b'\n')
assertNonBase64Data(b'ab:(){:|:&};:==', b'i', ignorechars=b':;(){}|&')
assertNonBase64Data(b'a\nb==', b'i', ignorechars=b'\n')
assertNonBase64Data(b'a\x00b==', b'i', ignorechars=b'\x00')
assertNonBase64Data(b'ab:==', b'i', ignorechars=b':')
assertNonBase64Data(b'ab=:=', b'i', ignorechars=b':')
assertNonBase64Data(b'ab==:', b'i', ignorechars=b':')
assertNonBase64Data(b'abc=:', b'i\xb7', ignorechars=b':')
assertNonBase64Data(b'ab==\n', b'i', ignorechars=b'\n')
assertNonBase64Data(b'a\nb==', b'i', ignorechars=bytearray(b'\n'))
assertNonBase64Data(b'a\nb==', b'i', ignorechars=memoryview(b'\n'))
self.assertEqual(binascii.a2b_base64(b'+A-/B_', ignorechars=b'+/-_'),
b'\xf8\x0f\xc1')
self.assertEqual(binascii.a2b_base64(b'+A-/B_', ignorechars=b'+/-_',
alphabet=binascii.URLSAFE_BASE64_ALPHABET),
b'\x03\xe0\x7f')
# Same cell in the cache: '\r' >> 3 == '\n' >> 3.
data = self.type2test(b'\r\n')
with self.assertRaises(binascii.Error):
binascii.a2b_base64(data, ignorechars=b'\r')
self.assertEqual(binascii.a2b_base64(data, ignorechars=b'\r\n'), b'')
# Same bit mask in the cache: '*' & 31 == '\n' & 31.
data = self.type2test(b'*\n')
with self.assertRaises(binascii.Error):
binascii.a2b_base64(data, ignorechars=b'*')
self.assertEqual(binascii.a2b_base64(data, ignorechars=b'*\n'), b'')
def test_base64_excess_data(self):
# Test excess data exceptions
def assertExcessData(data, expected):
assert_regex = r'(?i)Excess data'
data = self.type2test(data)
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base64(data, strict_mode=True)
self.assertEqual(binascii.a2b_base64(data, strict_mode=False),
expected)
self.assertEqual(binascii.a2b_base64(data, strict_mode=True,
ignorechars=b'='),
expected)
self.assertEqual(binascii.a2b_base64(data), expected)
assertExcessData(b'ab==c=', b'i\xb7')
assertExcessData(b'ab==cd', b'i\xb7\x1d')
assertExcessData(b'abc=d', b'i\xb7\x1d')
def test_base64errors(self):
# Test base64 with invalid padding
def assertIncorrectPadding(data, strict_mode=True):
data = self.type2test(data)
with self.assertRaisesRegex(binascii.Error, r'(?i)Incorrect padding'):
binascii.a2b_base64(data)
with self.assertRaisesRegex(binascii.Error, r'(?i)Incorrect padding'):
binascii.a2b_base64(data, strict_mode=False)
if strict_mode:
with self.assertRaisesRegex(binascii.Error, r'(?i)Incorrect padding'):
binascii.a2b_base64(data, strict_mode=True)
assertIncorrectPadding(b'ab')
assertIncorrectPadding(b'ab=')
assertIncorrectPadding(b'abc')
assertIncorrectPadding(b'abcdef')
assertIncorrectPadding(b'abcdef=')
assertIncorrectPadding(b'abcdefg')
assertIncorrectPadding(b'a=b=', strict_mode=False)
assertIncorrectPadding(b'a\nb=', strict_mode=False)
# Test base64 with invalid number of valid characters (1 mod 4)
def assertInvalidLength(data, strict_mode=True):
n_data_chars = len(re.sub(br'[^A-Za-z0-9/+]', br'', data))
data = self.type2test(data)
expected_errmsg_re = \
r'(?i)Invalid.+number of data characters.+' + str(n_data_chars)
with self.assertRaisesRegex(binascii.Error, expected_errmsg_re):
binascii.a2b_base64(data)
with self.assertRaisesRegex(binascii.Error, expected_errmsg_re):
binascii.a2b_base64(data, strict_mode=False)
if strict_mode:
with self.assertRaisesRegex(binascii.Error, expected_errmsg_re):
binascii.a2b_base64(data, strict_mode=True)
assertInvalidLength(b'a')
assertInvalidLength(b'a=')
assertInvalidLength(b'a==')
assertInvalidLength(b'a===')
assertInvalidLength(b'a' * 5)
assertInvalidLength(b'a' * (4 * 87 + 1))
assertInvalidLength(b'A\tB\nC ??DE', # only 5 valid characters
strict_mode=False)
def test_base64_alphabet(self):
alphabet = (b'!"#$%&\'()*+,-012345689@'
b'ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr')
data = self.type2test(self.rawdata)
encoded = binascii.b2a_base64(data, alphabet=alphabet)
trans = bytes.maketrans(binascii.BASE64_ALPHABET, alphabet)
expected = binascii.b2a_base64(data).translate(trans)
self.assertEqual(encoded, expected)
self.assertEqual(binascii.a2b_base64(encoded, alphabet=alphabet), self.rawdata)
self.assertEqual(binascii.b2a_base64(data, alphabet=self.type2test(alphabet)), expected)
data = self.type2test(b'')
self.assertEqual(binascii.b2a_base64(data, alphabet=alphabet), b'\n')
self.assertEqual(binascii.a2b_base64(data, alphabet=alphabet), b'')
for func in binascii.b2a_base64, binascii.a2b_base64:
with self.assertRaises(TypeError):
func(data, alphabet=None)
with self.assertRaises(TypeError):
func(data, alphabet=alphabet.decode())
with self.assertRaises(ValueError):
func(data, alphabet=alphabet[:-1])
with self.assertRaises(ValueError):
func(data, alphabet=alphabet+b'?')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, alphabet=bytearray(alphabet))
def test_ascii85_valid(self):
# Test Ascii85 with valid data
ASCII85_PREFIX = b"<~"
ASCII85_SUFFIX = b"~>"
# Interleave blocks of 4 null bytes and 4 spaces into test data
rawdata = bytearray()
rawlines, i = [], 0
for k in range(1, len(self.rawdata) + 1):
b = b"\0\0\0\0" if k & 1 else b" "
b = b + self.rawdata[i:i + k]
b = b" " if k & 1 else b"\0\0\0\0"
rawdata += b
rawlines.append(b)
i += k
if i >= len(self.rawdata):
break
# Test core parameter combinations
params = (False, False), (False, True), (True, False), (True, True)
for foldspaces, adobe in params:
lines = []
for rawline in rawlines:
b = self.type2test(rawline)
a = binascii.b2a_ascii85(b, foldspaces=foldspaces, adobe=adobe)
lines.append(a)
res = bytearray()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_ascii85(a, foldspaces=foldspaces, adobe=adobe)
res += b
self.assertEqual(res, rawdata)
# Test decoding inputs with length 1 mod 5
params = [
(b"a", False, False, b"", b""),
(b"xbw", False, False, b"wx", b""),
(b"<~c~>", False, True, b"", b""),
(b"{d ~>", False, True, b" {", b""),
(b"ye", True, False, b"", b" "),
(b"z\x01y\x00f", True, False, b"\x00\x01", b"\x00\x00\x00\x00 "),
(b"<~FCfN8yg~>", True, True, b"", b"test "),
(b"FE;\x03#8zFCf\x02N8yh~>", True, True, b"\x02\x03", b"tset\x00\x00\x00\x00test "),
]
for a, foldspaces, adobe, ignorechars, b in params:
kwargs = {"foldspaces": foldspaces, "adobe": adobe, "ignorechars": ignorechars}
self.assertEqual(binascii.a2b_ascii85(self.type2test(a), **kwargs), b)
def test_ascii85_invalid(self):
# Test Ascii85 with invalid characters interleaved
lines, i = [], 0
for k in range(1, len(self.rawdata) + 1):
b = self.type2test(self.rawdata[i:i + k])
a = binascii.b2a_ascii85(b)
lines.append(a)
i += k
if i >= len(self.rawdata):
break
fillers = bytearray()
valid = b"!\"#$%&'()*+,-./0123456789:;<=>?@" \
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu" + b"z"
for i in range(256):
if i not in valid:
fillers.append(i)
def addnoise(line):
res = bytearray()
for i in range(len(line)):
res.append(line[i])
for j in range(i, len(fillers), len(line)):
res.append(fillers[j])
return res
res = bytearray()
for line in map(addnoise, lines):
a = self.type2test(line)
b = binascii.a2b_ascii85(a, ignorechars=fillers)
res += b
self.assertEqual(res, self.rawdata)
# Test Ascii85 with only invalid characters
fillers = self.type2test(fillers)
b = binascii.a2b_ascii85(fillers, ignorechars=fillers)
self.assertEqual(b, b"")
def test_ascii85_errors(self):
def _assertRegexTemplate(assert_regex, data, **kwargs):
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_ascii85(self.type2test(data), **kwargs)
def assertMissingDelimiter(data):
_assertRegexTemplate(r"(?i)end with b'~>'", data, adobe=True)
def assertOverflow(data):
_assertRegexTemplate(r"(?i)Ascii85 overflow", data)
def assertInvalidSpecial(data):
_assertRegexTemplate(r"(?i)'[yz]'.+5-tuple", data, foldspaces=True)
def assertInvalidChar(data, **kwargs):
_assertRegexTemplate(r"(?i)Non-Ascii85 digit", data, **kwargs)
# Test Ascii85 with missing delimiters
assertMissingDelimiter(b"")
assertMissingDelimiter(b"a")
assertMissingDelimiter(b"<~")
assertMissingDelimiter(b"<~!~")
assertMissingDelimiter(b"<~abc>")
assertMissingDelimiter(b"<~has delimiter but not terminal~> !")
# Test Ascii85 with out-of-range encoded value
assertOverflow(b"t")
assertOverflow(b"s9")
assertOverflow(b"s8X")
assertOverflow(b"s8W.")
assertOverflow(b's8W-"')
assertOverflow(b"s8W-!u")
assertOverflow(b"s8W-!s8W-!zs8X")
# Test Ascii85 with misplaced short form groups
assertInvalidSpecial(b"ay")
assertInvalidSpecial(b"az")
assertInvalidSpecial(b"aby")
assertInvalidSpecial(b"ayz")
assertInvalidSpecial(b"abcz")
assertInvalidSpecial(b"abcdy")
assertInvalidSpecial(b"y!and!z!then!!y")
# Test Ascii85 with non-ignored invalid characters
assertInvalidChar(b"j\n")
assertInvalidChar(b" ", ignorechars=b"")
assertInvalidChar(b" valid\x02until\x03", ignorechars=b"\x00\x01\x02\x04")
assertInvalidChar(b"\tFCb", ignorechars=b"\n")
assertInvalidChar(b"xxxB\nP\thU'D v/F+", ignorechars=b" \n\tv")
def _common_test_wrapcol(self, func):
eq = self.assertEqual
data = self.data
expected = func(data)
eq(func(data, wrapcol=0), expected)
eq(func(data, wrapcol=8000), 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')
with self.assertRaises(TypeError):
func(data, wrapcol=None)
def test_ascii85_wrapcol(self):
# Test Ascii85 splitting lines
self._common_test_wrapcol(binascii.b2a_ascii85)
def assertEncode(a_expected, data, n, adobe=False):
b = self.type2test(data)
a = binascii.b2a_ascii85(b, adobe=adobe, wrapcol=n)
self.assertEqual(a, a_expected)
def assertDecode(data, b_expected, adobe=False):
a = self.type2test(data)
b = binascii.a2b_ascii85(a, adobe=adobe, ignorechars=b"\n")
self.assertEqual(b, b_expected)
tests = [
(b"", 0, b"", b"<~~>"),
(b"", 1, b"", b"<~\n~>"),
(b"a", 0, b"@/", b"<~@/~>"),
(b"a", 1, b"@\n/", b"<~\n@/\n~>"),
(b"a", 2, b"@/", b"<~\n@/\n~>"),
(b"a", 3, b"@/", b"<~@\n/~>"),
(b"a", 4, b"@/", b"<~@/\n~>"),
(b"a", 5, b"@/", b"<~@/\n~>"),
(b"a", 6, b"@/", b"<~@/~>"),
(b"a", 7, b"@/", b"<~@/~>"),
(b"a", 123, b"@/", b"<~@/~>"),
(b"this is a test", 7, b"FD,B0+D\nGm>@3BZ\n'F*%",
b"<~FD,B0\n+DGm>@3\nBZ'F*%\n~>"),
(b"a test!!!!!!! ", 11, b"@3BZ'F*&QK+\nX&!P+WqmM+9",
b"<~@3BZ'F*&Q\nK+X&!P+WqmM\n+9~>"),
(b"\0" * 56, 7, b"zzzzzzz\nzzzzzzz", b"<~zzzzz\nzzzzzzz\nzz~>"),
]
for b, n, a, a_wrap in tests:
assertEncode(a, b, n)
assertEncode(a_wrap, b, n, adobe=True)
assertDecode(a, b)
assertDecode(a_wrap, b, adobe=True)
def test_ascii85_pad(self):
# Test Ascii85 with encode padding
rawdata = b"n1n3tee\n ch@rAcTer$"
for i in range(1, len(rawdata) + 1):
padding = -i % 4
b = rawdata[:i]
a_pad = binascii.b2a_ascii85(self.type2test(b), pad=True)
b_pad = binascii.a2b_ascii85(self.type2test(a_pad))
b_pad_expected = b + b"\0" * padding
self.assertEqual(b_pad, b_pad_expected)
# Test Ascii85 short form groups with encode padding
def assertShortPad(data, expected, **kwargs):
data = self.type2test(data)
res = binascii.b2a_ascii85(data, **kwargs)
self.assertEqual(res, expected)
assertShortPad(b"\0", b"!!", pad=False)
assertShortPad(b"\0", b"z", pad=True)
assertShortPad(b"\0" * 2, b"z", pad=True)
assertShortPad(b"\0" * 3, b"z", pad=True)
assertShortPad(b"\0" * 4, b"z", pad=True)
assertShortPad(b"\0" * 5, b"zz", pad=True)
assertShortPad(b"\0" * 6, b"z!!!")
assertShortPad(b" " * 7, b"y+<Vd,", foldspaces=True, pad=True)
assertShortPad(b"\0" * 8, b"<~zz~>",
foldspaces=True, adobe=True, pad=True)
assertShortPad(b"\0\0\0\0abcd \0\0", b"<~z@:E_Wy\nz~>",
foldspaces=True, adobe=True, wrapcol=9, pad=True)
def test_ascii85_ignorechars(self):
# Test Ascii85 with ignored characters
def assertIgnore(data, expected, ignorechars=b"", **kwargs):
data = self.type2test(data)
ignore = self.type2test(ignorechars)
with self.assertRaisesRegex(binascii.Error, r"(?i)Non-Ascii85 digit"):
binascii.a2b_ascii85(data, **kwargs)
res = binascii.a2b_ascii85(data, ignorechars=ignorechars, **kwargs)
self.assertEqual(res, expected)
assertIgnore(b"\n", b"", ignorechars=b"\n")
assertIgnore(b"<~ ~>", b"", ignorechars=b" ", adobe=True)
assertIgnore(b"z|z", b"\0" * 8, ignorechars=b"|||") # repeats don't matter
assertIgnore(b"zz!!|", b"\0" * 9, ignorechars=b"|!z") # ignore only if invalid
assertIgnore(b"<~B P~@~>", b"hi", ignorechars=b" <~>", adobe=True)
assertIgnore(b"zy}", b"\0\0\0\0", ignorechars=b"zy}")
assertIgnore(b"zy}", b"\0\0\0\0 ", ignorechars=b"zy}", foldspaces=True)
def test_base85_valid(self):
# Test base85 with valid data
lines, i = [], 0
for k in range(1, len(self.rawdata) + 1):
b = self.type2test(self.rawdata[i:i + k])
a = binascii.b2a_base85(b)
lines.append(a)
i += k
if i >= len(self.rawdata):
break
res = bytes()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_base85(a)
res += b
self.assertEqual(res, self.rawdata)
# Test decoding inputs with different length
self.assertEqual(binascii.a2b_base85(self.type2test(b'a')), b'')
self.assertEqual(binascii.a2b_base85(self.type2test(b'a')), b'')
self.assertEqual(binascii.a2b_base85(self.type2test(b'ab')), b'q')
self.assertEqual(binascii.a2b_base85(self.type2test(b'abc')), b'qa')
self.assertEqual(binascii.a2b_base85(self.type2test(b'abcd')),
b'qa\x9e')
self.assertEqual(binascii.a2b_base85(self.type2test(b'abcde')),
b'qa\x9e\xb6')
self.assertEqual(binascii.a2b_base85(self.type2test(b'abcdef')),
b'qa\x9e\xb6')
self.assertEqual(binascii.a2b_base85(self.type2test(b'abcdefg')),
b'qa\x9e\xb6\x81')
def test_base85_errors(self):
def _assertRegexTemplate(assert_regex, data, **kwargs):
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base85(self.type2test(data), **kwargs)
def assertNonBase85Data(data):
_assertRegexTemplate(r"(?i)bad base85 character", data)
def assertOverflow(data):
_assertRegexTemplate(r"(?i)base85 overflow", data)
assertNonBase85Data(b"\xda")
assertNonBase85Data(b"00\0\0")
assertNonBase85Data(b"Z )*")
assertNonBase85Data(b"bY*jNb0Hyq\n")
# Test base85 with out-of-range encoded value
assertOverflow(b"}")
assertOverflow(b"|O")
assertOverflow(b"|Nt")
assertOverflow(b"|NsD")
assertOverflow(b"|NsC1")
assertOverflow(b"|NsC0~")
assertOverflow(b"|NsC0|NsC0|NsD0")
def test_base85_wrapcol(self):
self._common_test_wrapcol(binascii.b2a_base85)
b = self.type2test(b'www.python.org')
self.assertEqual(binascii.b2a_base85(b, wrapcol=10),
b'cXxL#aCvlS\nZ*DGca%T')
self.assertEqual(binascii.b2a_base85(b, wrapcol=14),
b'cXxL#aCvlS\nZ*DGca%T')
self.assertEqual(binascii.b2a_base85(b, wrapcol=1),
b'cXxL#\naCvlS\nZ*DGc\na%T')
def test_base85_pad(self):
# Test base85 with encode padding
rawdata = b"n1n3Tee\n ch@rAc\te\r$"
for i in range(1, len(rawdata) + 1):
padding = -i % 4
b = rawdata[:i]
a_pad = binascii.b2a_base85(self.type2test(b), pad=True)
b_pad = binascii.a2b_base85(self.type2test(a_pad))
b_pad_expected = b + b"\0" * padding
self.assertEqual(b_pad, b_pad_expected)
def test_base85_ignorechars(self):
a2b_base85 = binascii.a2b_base85
self._common_test_ignorechars(a2b_base85)
eq = self.assertEqual
eq(a2b_base85(b'VPa\n !s\n', ignorechars=b' \n'), b'abcd')
eq(a2b_base85(b'VPa\n !s\n', ignorechars=bytearray(b' \n')), b'abcd')
eq(a2b_base85(b'A~[B];C', ignorechars=b';[]~'), b'"1\xa3\x15')
eq(a2b_base85(b'A~[B];C', ignorechars=b';[]~',
alphabet=binascii.Z85_ALPHABET), b'r\xd8dv')
def test_base85_alphabet(self):
alphabet = (b'0123456789abcdefghijklmnopqrstuvwxyz'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#')
data = self.type2test(self.rawdata)
encoded = binascii.b2a_base85(data, alphabet=alphabet)
trans = bytes.maketrans(binascii.BASE85_ALPHABET, alphabet)
expected = binascii.b2a_base85(data).translate(trans)
self.assertEqual(encoded, expected)
self.assertEqual(binascii.a2b_base85(encoded, alphabet=alphabet), self.rawdata)
self.assertEqual(binascii.b2a_base85(data, alphabet=self.type2test(alphabet)), expected)
data = self.type2test(b'')
self.assertEqual(binascii.b2a_base85(data, alphabet=alphabet), b'')
self.assertEqual(binascii.a2b_base85(data, alphabet=alphabet), b'')
for func in binascii.b2a_base85, binascii.a2b_base85:
with self.assertRaises(TypeError):
func(data, alphabet=None)
with self.assertRaises(TypeError):
func(data, alphabet=alphabet.decode())
with self.assertRaises(ValueError):
func(data, alphabet=alphabet[:-1])
with self.assertRaises(ValueError):
func(data, alphabet=alphabet+b'?')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, alphabet=bytearray(alphabet))
def test_base32_valid(self):
# Test base32 with valid data
lines = []
step = 0
i = 0
while i < len(self.rawdata):
b = self.type2test(self.rawdata[i:i + step])
a = binascii.b2a_base32(b)
lines.append(a)
i += step
step += 1
res = bytes()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_base32(a)
res += b
self.assertEqual(res, self.rawdata)
def test_base32_errors(self):
def _fixPadding(data):
fixed = data.replace(b"=", b"")
len_8 = len(fixed) % 8
p = 8 - len_8 if len_8 else 0
return fixed + b"=" * p
def _assertRegexTemplate(assert_regex, data, good_padding_result=None, **kwargs):
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base32(self.type2test(data), **kwargs)
if good_padding_result:
fixed = self.type2test(_fixPadding(data))
self.assertEqual(binascii.a2b_base32(fixed), good_padding_result)
def assertNonBase32Data(*args):
_assertRegexTemplate(r"(?i)Only base32 data", *args)
def assertExcessData(*args):
_assertRegexTemplate(r"(?i)Excess data", *args)
def assertExcessPadding(*args):
_assertRegexTemplate(r"(?i)Excess padding", *args)
def assertLeadingPadding(*args, **kwargs):
_assertRegexTemplate(r"(?i)Leading padding", *args, **kwargs)
def assertIncorrectPadding(*args):
_assertRegexTemplate(r"(?i)Incorrect padding", *args)
def assertDiscontinuousPadding(*args):
_assertRegexTemplate(r"(?i)Discontinuous padding", *args)
def assertInvalidLength(data, *args, length=None, **kwargs):
if length is None:
length = len(data.split(b'=', 1)[0].replace(b' ', b''))
assert_regex = fr"(?i)Invalid.+number of data characters \({length}\)"
_assertRegexTemplate(assert_regex, data, *args, **kwargs)
assertNonBase32Data(b"a")
assertNonBase32Data(b"AA-")
assertNonBase32Data(b"ABCDE==!")
assertNonBase32Data(b"ab:(){:|:&};:==")
assertExcessData(b"AB======C")
assertExcessData(b"AB======CD")
assertExcessData(b"ABCD====E")
assertExcessData(b"ABCDE===FGH")
assertExcessData(b"ABCDEFG=H")
assertExcessData(b"432Z====55555555")
assertExcessData(b"BE======EF", b"\t\x08")
assertExcessData(b"BEEF====C", b"\t\x08Q")
assertExcessData(b"BEEFC===AK", b"\t\x08Q\x01")
assertExcessData(b"BEEFCAK=E", b"\t\x08Q\x01D")
assertExcessPadding(b"BE=======", b"\t")
assertExcessPadding(b"BE========", b"\t")
assertExcessPadding(b"BEEF=====", b"\t\x08")
assertExcessPadding(b"BEEF======", b"\t\x08")
assertExcessPadding(b"BEEFC====", b"\t\x08Q")
assertExcessPadding(b"BEEFC=====", b"\t\x08Q")
assertExcessPadding(b"BEEFCAK==", b"\t\x08Q\x01")
assertExcessPadding(b"BEEFCAK===", b"\t\x08Q\x01")
assertExcessPadding(b"BEEFCAKE=", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE==", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE===", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE====", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE=====", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE======", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE=======", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE========", b"\t\x08Q\x01D")
assertExcessPadding(b"BEEFCAKE=========", b"\t\x08Q\x01D")
assertLeadingPadding(b"=", b"")
assertLeadingPadding(b"==", b"")
assertLeadingPadding(b"===", b"")
assertLeadingPadding(b"====", b"")
assertLeadingPadding(b"=====", b"")
assertLeadingPadding(b"======", b"")
assertLeadingPadding(b"=======", b"")
assertLeadingPadding(b"========", b"")
assertLeadingPadding(b"=========", b"")
assertLeadingPadding(b"=BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"==BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"===BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"====BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"=====BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"======BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"=======BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"========BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b"=========BEEFCAKE", b"\t\x08Q\x01D")
assertLeadingPadding(b" =BEEFCAKE", ignorechars=b' ')
assertIncorrectPadding(b"AB")
assertIncorrectPadding(b"ABCD")
assertIncorrectPadding(b"ABCDE")
assertIncorrectPadding(b"ABCDEFG")
assertIncorrectPadding(b"BE=", b"\t")
assertIncorrectPadding(b"BE==", b"\t")
assertIncorrectPadding(b"BE===", b"\t")
assertIncorrectPadding(b"BE====", b"\t")
assertIncorrectPadding(b"BE=====", b"\t")
assertIncorrectPadding(b"BEEF=", b"\t\x08")
assertIncorrectPadding(b"BEEF==", b"\t\x08")
assertIncorrectPadding(b"BEEF===", b"\t\x08")
assertIncorrectPadding(b"BEEFC=", b"\t\x08Q")
assertIncorrectPadding(b"BEEFC==", b"\t\x08Q")
assertDiscontinuousPadding(b"BE=EF===", b"\t\x08")
assertDiscontinuousPadding(b"BE==EF==", b"\t\x08")
assertDiscontinuousPadding(b"BEEF=C==", b"\t\x08Q")
assertDiscontinuousPadding(b"BEEFC=AK", b"\t\x08Q\x01")
assertInvalidLength(b"A")
assertInvalidLength(b"ABC")
assertInvalidLength(b"ABCDEF")
assertInvalidLength(b"ABCDEFGHI")
assertInvalidLength(b"ABCDEFGHIJK")
assertInvalidLength(b"ABCDEFGHIJKLMN")
assertInvalidLength(b"A=")
assertInvalidLength(b"A==")
assertInvalidLength(b"A===")
assertInvalidLength(b"A====")
assertInvalidLength(b"A=====")
assertInvalidLength(b"A======")
assertInvalidLength(b"ABC=")
assertInvalidLength(b"ABC==")
assertInvalidLength(b"ABC===")
assertInvalidLength(b"ABC====")
assertInvalidLength(b"ABCDEF=")
assertInvalidLength(b"B=E=====", b"\t")
assertInvalidLength(b"B==E====", b"\t")
assertInvalidLength(b"BEE=F===", b"\t\x08")
assertInvalidLength(b"BEE==F==", b"\t\x08")
assertInvalidLength(b"BEEFCA=K", b"\t\x08Q\x01")
assertInvalidLength(b"BEEFCA=====K", b"\t\x08Q\x01")
assertInvalidLength(b" A", ignorechars=b' ')
assertInvalidLength(b" ABC", ignorechars=b' ')
assertInvalidLength(b" ABCDEF", ignorechars=b' ')
assertInvalidLength(b" ABCDEFGHI", ignorechars=b' ')
assertInvalidLength(b" ABCDEFGHIJK", ignorechars=b' ')
assertInvalidLength(b" ABCDEFGHIJKLMN", ignorechars=b' ')
assertInvalidLength(b" A=======", ignorechars=b' ')
assertInvalidLength(b" ABC=====", ignorechars=b' ')
assertInvalidLength(b" ABCDEF==", ignorechars=b' ')
def test_a2b_base32_padded(self):
a2b_base32 = binascii.a2b_base32
t = self.type2test
def check(data, expected):
if b'=' in data:
with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
a2b_base32(t(data), padded=False)
self.assertEqual(a2b_base32(t(data), padded=False, ignorechars=b'='),
expected)
data = data.replace(b'=', b'')
self.assertEqual(a2b_base32(t(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_b2a_base32_padded(self):
b2a_base32 = binascii.b2a_base32
t = self.type2test
self.assertEqual(b2a_base32(t(b''), padded=False), b'')
self.assertEqual(b2a_base32(t(b'a'), padded=False), b'ME')
self.assertEqual(b2a_base32(t(b'ab'), padded=False), b'MFRA')
self.assertEqual(b2a_base32(t(b'abc'), padded=False), b'MFRGG')
self.assertEqual(b2a_base32(t(b'abcd'), padded=False), b'MFRGGZA')
self.assertEqual(b2a_base32(t(b'abcde'), padded=False), b'MFRGGZDF')
def test_base32_wrapcol(self):
self._common_test_wrapcol(binascii.b2a_base32)
b = self.type2test(b'www.python.org')
self.assertEqual(binascii.b2a_base32(b, wrapcol=16),
b'O53XOLTQPF2GQ33O\nFZXXEZY=')
self.assertEqual(binascii.b2a_base32(b, wrapcol=23),
b'O53XOLTQPF2GQ33O\nFZXXEZY=')
self.assertEqual(binascii.b2a_base32(b, wrapcol=1),
b'O53XOLTQ\nPF2GQ33O\nFZXXEZY=')
def test_base32_ignorechars(self):
a2b_base32 = binascii.a2b_base32
self._common_test_ignorechars(a2b_base32)
eq = self.assertEqual
eq(a2b_base32(b'MFRG\n GZDF\n', ignorechars=b' \n'), b'abcde')
eq(a2b_base32(b'MFRG\n GZDF\n', ignorechars=bytearray(b' \n')), b'abcde')
eq(a2b_base32(b'M=======FRGGZDF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MF======RGGZDF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFR=====GGZDF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRG====GZDF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRGG===ZDF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRGGZ==DF', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRGGZD=F', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRGGZDF=', ignorechars=b'='), b'abcde')
eq(a2b_base32(b'MFRA======', ignorechars=b'='), b'ab')
eq(a2b_base32(b'A1B3C5W7Z9', ignorechars=b'19WZ'), b'\x00v.\xdb\xf9')
eq(a2b_base32(b'A1B3C5W7Z9', ignorechars=b'19WZ',
alphabet=binascii.BASE32HEX_ALPHABET), b'PV6\x14\xe9')
def test_base32_alphabet(self):
alphabet = b'0Aa1Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9JjKk'
data = self.type2test(self.rawdata)
encoded = binascii.b2a_base32(data, alphabet=alphabet)
trans = bytes.maketrans(binascii.BASE32_ALPHABET, alphabet)
expected = binascii.b2a_base32(data).translate(trans)
self.assertEqual(encoded, expected)
self.assertEqual(binascii.a2b_base32(encoded, alphabet=alphabet), self.rawdata)
self.assertEqual(binascii.b2a_base32(data, alphabet=self.type2test(alphabet)), expected)
data = self.type2test(b'')
self.assertEqual(binascii.b2a_base32(data, alphabet=alphabet), b'')
self.assertEqual(binascii.a2b_base32(data, alphabet=alphabet), b'')
for func in binascii.b2a_base32, binascii.a2b_base32:
with self.assertRaises(TypeError):
func(data, alphabet=None)
with self.assertRaises(TypeError):
func(data, alphabet=alphabet.decode())
with self.assertRaises(ValueError):
func(data, alphabet=alphabet[:-1])
with self.assertRaises(ValueError):
func(data, alphabet=alphabet+b'?')
with self.assertRaises(TypeError):
binascii.a2b_base32(data, alphabet=bytearray(alphabet))
def test_uu(self):
MAX_UU = 45
for backtick in (True, False):
lines = []
for i in range(0, len(self.data), MAX_UU):
b = self.type2test(self.rawdata[i:i+MAX_UU])
a = binascii.b2a_uu(b, backtick=backtick)
lines.append(a)
res = bytes()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_uu(a)
res += b
self.assertEqual(res, self.rawdata)
self.assertEqual(binascii.a2b_uu(b"\x7f"), b"\x00"*31)
self.assertEqual(binascii.a2b_uu(b"\x80"), b"\x00"*32)
self.assertEqual(binascii.a2b_uu(b"\xff"), b"\x00"*31)
self.assertRaises(binascii.Error, binascii.a2b_uu, b"\xff\x00")
self.assertRaises(binascii.Error, binascii.a2b_uu, b"!!!!")
self.assertRaises(binascii.Error, binascii.b2a_uu, 46*b"!")
# Issue #7701 (crash on a pydebug build)
self.assertEqual(binascii.b2a_uu(b'x'), b'!> \n')
self.assertEqual(binascii.b2a_uu(b''), b' \n')
self.assertEqual(binascii.b2a_uu(b'', backtick=True), b'`\n')
self.assertEqual(binascii.a2b_uu(b' \n'), b'')
self.assertEqual(binascii.a2b_uu(b'`\n'), b'')
self.assertEqual(binascii.b2a_uu(b'\x00Cat'), b'$ $-A= \n')
self.assertEqual(binascii.b2a_uu(b'\x00Cat', backtick=True),
b'$`$-A=```\n')
self.assertEqual(binascii.a2b_uu(b'$`$-A=```\n'),
binascii.a2b_uu(b'$ $-A= \n'))
with self.assertRaises(TypeError):
binascii.b2a_uu(b"", True)
@hypothesis.given(
binary=hypothesis.strategies.binary(max_size=45),
backtick=hypothesis.strategies.booleans(),
)
def test_b2a_roundtrip(self, binary, backtick):
converted = binascii.b2a_uu(self.type2test(binary), backtick=backtick)
restored = binascii.a2b_uu(self.type2test(converted))
self.assertConversion(binary, converted, restored, backtick=backtick)
def test_crc_hqx(self):
crc = binascii.crc_hqx(self.type2test(b"Test the CRC-32 of"), 0)
crc = binascii.crc_hqx(self.type2test(b" this string."), crc)
self.assertEqual(crc, 14290)
self.assertRaises(TypeError, binascii.crc_hqx)
self.assertRaises(TypeError, binascii.crc_hqx, self.type2test(b''))
for crc in 0, 1, 0x1234, 0x12345, 0x12345678, -1:
self.assertEqual(binascii.crc_hqx(self.type2test(b''), crc),
crc & 0xffff)
def test_crc32(self):
crc = binascii.crc32(self.type2test(b"Test the CRC-32 of"))
crc = binascii.crc32(self.type2test(b" this string."), crc)
self.assertEqual(crc, 1571220330)
self.assertRaises(TypeError, binascii.crc32)
def test_hex(self):
# test hexlification
s = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000'
t = binascii.b2a_hex(self.type2test(s))
u = binascii.a2b_hex(self.type2test(t))
self.assertEqual(s, u)
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1])
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q')
self.assertRaises(binascii.Error, binascii.a2b_hex, bytes([255, 255]))
self.assertRaises(binascii.Error, binascii.a2b_hex, b'0G')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'0g')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'G0')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'g0')
# Confirm that b2a_hex == hexlify and a2b_hex == unhexlify
self.assertEqual(binascii.hexlify(self.type2test(s)), t)
self.assertEqual(binascii.unhexlify(self.type2test(t)), u)
@hypothesis.given(binary=hypothesis.strategies.binary())
def test_hex_roundtrip(self, binary):
converted = binascii.hexlify(self.type2test(binary))
restored = binascii.unhexlify(self.type2test(converted))
self.assertConversion(binary, converted, restored)
def test_hex_separator(self):
"""Test that hexlify and b2a_hex are binary versions of bytes.hex."""
# Logic of separators is tested in test_bytes.py. This checks that
# arg parsing works and exercises the direct to bytes object code
# path within pystrhex.c.
s = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000'
self.assertEqual(binascii.hexlify(self.type2test(s)), s.hex().encode('ascii'))
expected8 = s.hex('.', 8).encode('ascii')
self.assertEqual(binascii.hexlify(self.type2test(s), '.', 8), expected8)
expected1 = s.hex(':').encode('ascii')
self.assertEqual(binascii.b2a_hex(self.type2test(s), ':'), expected1)
def test_hex_ignorechars(self):
a2b_hex = binascii.a2b_hex
self._common_test_ignorechars(a2b_hex)
self._common_test_ignorechars(binascii.unhexlify)
eq = self.assertEqual
eq(a2b_hex(b'A B\nC D\n', ignorechars=b' \n'), b'\xab\xcd')
eq(a2b_hex(b'A B\nC D\n', ignorechars=bytearray(b' \n')), b'\xab\xcd')
eq(a2b_hex(b'aBcD', ignorechars=b'ac'), b'\xab\xcd')
def test_qp(self):
type2test = self.type2test
a2b_qp = binascii.a2b_qp
b2a_qp = binascii.b2a_qp
a2b_qp(data=b"", header=False) # Keyword arguments allowed
# A test for SF bug 534347 (segfaults without the proper fix)
try:
a2b_qp(b"", **{1:1})
except TypeError:
pass
else:
self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError")
self.assertEqual(a2b_qp(type2test(b"=")), b"")
self.assertEqual(a2b_qp(type2test(b"= ")), b"= ")
self.assertEqual(a2b_qp(type2test(b"==")), b"=")
self.assertEqual(a2b_qp(type2test(b"=\nAB")), b"AB")
self.assertEqual(a2b_qp(type2test(b"=\r\nAB")), b"AB")
self.assertEqual(a2b_qp(type2test(b"=\rAB")), b"") # ?
self.assertEqual(a2b_qp(type2test(b"=\rAB\nCD")), b"CD") # ?
self.assertEqual(a2b_qp(type2test(b"=AB")), b"\xab")
self.assertEqual(a2b_qp(type2test(b"=ab")), b"\xab")
self.assertEqual(a2b_qp(type2test(b"=AX")), b"=AX")
self.assertEqual(a2b_qp(type2test(b"=XA")), b"=XA")
self.assertEqual(a2b_qp(type2test(b"=AB")[:-1]), b"=A")
self.assertEqual(a2b_qp(type2test(b'_')), b'_')
self.assertEqual(a2b_qp(type2test(b'_'), header=True), b' ')
self.assertRaises(TypeError, b2a_qp, foo="bar")
self.assertEqual(a2b_qp(type2test(b"=00\r\n=00")), b"\x00\r\n\x00")
self.assertEqual(b2a_qp(type2test(b"\xff\r\n\xff\n\xff")),
b"=FF\r\n=FF\r\n=FF")
self.assertEqual(b2a_qp(type2test(b"0"*75+b"\xff\r\n\xff\r\n\xff")),
b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF")
self.assertEqual(b2a_qp(type2test(b'\x7f')), b'=7F')
self.assertEqual(b2a_qp(type2test(b'=')), b'=3D')
self.assertEqual(b2a_qp(type2test(b'_')), b'_')
self.assertEqual(b2a_qp(type2test(b'_'), header=True), b'=5F')
self.assertEqual(b2a_qp(type2test(b'x y'), header=True), b'x_y')
self.assertEqual(b2a_qp(type2test(b'x '), header=True), b'x=20')
self.assertEqual(b2a_qp(type2test(b'x y'), header=True, quotetabs=True),
b'x=20y')
self.assertEqual(b2a_qp(type2test(b'x\ty'), header=True), b'x\ty')
self.assertEqual(b2a_qp(type2test(b' ')), b'=20')
self.assertEqual(b2a_qp(type2test(b'\t')), b'=09')
self.assertEqual(b2a_qp(type2test(b' x')), b' x')
self.assertEqual(b2a_qp(type2test(b'\tx')), b'\tx')
self.assertEqual(b2a_qp(type2test(b' x')[:-1]), b'=20')
self.assertEqual(b2a_qp(type2test(b'\tx')[:-1]), b'=09')
self.assertEqual(b2a_qp(type2test(b'\0')), b'=00')
self.assertEqual(b2a_qp(type2test(b'\0\n')), b'=00\n')
self.assertEqual(b2a_qp(type2test(b'\0\n'), quotetabs=True), b'=00\n')
self.assertEqual(b2a_qp(type2test(b'x y\tz')), b'x y\tz')
self.assertEqual(b2a_qp(type2test(b'x y\tz'), quotetabs=True),
b'x=20y=09z')
self.assertEqual(b2a_qp(type2test(b'x y\tz'), istext=False),
b'x y\tz')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n')),
b'x=20\ny=09\n')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), quotetabs=True),
b'x=20\ny=09\n')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), istext=False),
b'x =0Ay\t=0A')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r')),
b'x \ry\t\r')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), quotetabs=True),
b'x=20\ry=09\r')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), istext=False),
b'x =0Dy\t=0D')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n')),
b'x=20\r\ny=09\r\n')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), quotetabs=True),
b'x=20\r\ny=09\r\n')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), istext=False),
b'x =0D=0Ay\t=0D=0A')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1]), b'x \r')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1]), b'x\t\r')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], quotetabs=True),
b'x=20\r')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], quotetabs=True),
b'x=09\r')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], istext=False),
b'x =0D')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], istext=False),
b'x\t=0D')
self.assertEqual(b2a_qp(type2test(b'.')), b'=2E')
self.assertEqual(b2a_qp(type2test(b'.\n')), b'=2E\n')
self.assertEqual(b2a_qp(type2test(b'.\r')), b'=2E\r')
self.assertEqual(b2a_qp(type2test(b'.\0')), b'=2E=00')
self.assertEqual(b2a_qp(type2test(b'a.\n')), b'a.\n')
self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E')
@hypothesis.given(
binary=hypothesis.strategies.binary(),
quotetabs=hypothesis.strategies.booleans(),
istext=hypothesis.strategies.booleans(),
header=hypothesis.strategies.booleans(),
)
def test_b2a_qp_a2b_qp_round_trip(self, binary, quotetabs, istext, header):
converted = binascii.b2a_qp(
self.type2test(binary),
quotetabs=quotetabs, istext=istext, header=header,
)
restored = binascii.a2b_qp(self.type2test(converted), header=header)
self.assertConversion(binary, converted, restored,
quotetabs=quotetabs, istext=istext, header=header)
def test_empty_string(self):
# A test for SF bug #1022953. Make sure SystemError is not raised.
empty = self.type2test(b'')
for func in all_functions:
if func == 'crc_hqx':
# crc_hqx needs 2 arguments
binascii.crc_hqx(empty, 0)
continue
f = getattr(binascii, func)
try:
f(empty)
except Exception as err:
self.fail("{}({!r}) raises {!r}".format(func, empty, err))
def test_unicode_b2a(self):
# Unicode strings are not accepted by b2a_* functions.
for func in set(all_functions) - set(a2b_functions):
try:
self.assertRaises(TypeError, getattr(binascii, func), "test")
except Exception as err:
self.fail('{}("test") raises {!r}'.format(func, err))
# crc_hqx needs 2 arguments
self.assertRaises(TypeError, binascii.crc_hqx, "test", 0)
def test_unicode_a2b(self):
# Unicode strings are accepted by a2b_* functions.
MAX_ALL = 45
raw = self.rawdata[:MAX_ALL]
for fa, fb in zip(a2b_functions, b2a_functions):
a2b = getattr(binascii, fa)
b2a = getattr(binascii, fb)
try:
a = b2a(self.type2test(raw))
binary_res = a2b(a)
a = a.decode('ascii')
res = a2b(a)
except Exception as err:
self.fail("{}/{} conversion raises {!r}".format(fb, fa, err))
self.assertEqual(res, raw, "{}/{} conversion: "
"{!r} != {!r}".format(fb, fa, res, raw))
self.assertEqual(res, binary_res)
self.assertIsInstance(res, bytes)
# non-ASCII string
self.assertRaises(ValueError, a2b, "\x80")
def test_b2a_base64_newline(self):
# Issue #25357: test newline parameter
b = self.type2test(b'hello')
self.assertEqual(binascii.b2a_base64(b),
b'aGVsbG8=\n')
self.assertEqual(binascii.b2a_base64(b, newline=True),
b'aGVsbG8=\n')
self.assertEqual(binascii.b2a_base64(b, newline=False),
b'aGVsbG8=')
b = self.type2test(b'')
self.assertEqual(binascii.b2a_base64(b), b'\n')
self.assertEqual(binascii.b2a_base64(b, newline=True), b'\n')
self.assertEqual(binascii.b2a_base64(b, newline=False), b'')
def test_b2a_base64_padded(self):
b2a_base64 = binascii.b2a_base64
t = self.type2test
self.assertEqual(b2a_base64(t(b''), padded=False), b'\n')
self.assertEqual(b2a_base64(t(b'a'), padded=False), b'YQ\n')
self.assertEqual(b2a_base64(t(b'ab'), padded=False), b'YWI\n')
self.assertEqual(b2a_base64(t(b'abc'), padded=False), b'YWJj\n')
def test_b2a_base64_wrapcol(self):
self._common_test_wrapcol(binascii.b2a_base64)
b = self.type2test(b'www.python.org')
self.assertEqual(binascii.b2a_base64(b, wrapcol=8),
b'd3d3LnB5\ndGhvbi5v\ncmc=\n')
self.assertEqual(binascii.b2a_base64(b, wrapcol=11),
b'd3d3LnB5\ndGhvbi5v\ncmc=\n')
self.assertEqual(binascii.b2a_base64(b, wrapcol=8, newline=False),
b'd3d3LnB5\ndGhvbi5v\ncmc=')
self.assertEqual(binascii.b2a_base64(b, wrapcol=1),
b'd3d3\nLnB5\ndGhv\nbi5v\ncmc=\n')
b = self.type2test(b'')
self.assertEqual(binascii.b2a_base64(b, wrapcol=8, newline=False), b'')
@hypothesis.given(
binary=hypothesis.strategies.binary(),
newline=hypothesis.strategies.booleans(),
)
def test_base64_roundtrip(self, binary, newline):
converted = binascii.b2a_base64(self.type2test(binary), newline=newline)
restored = binascii.a2b_base64(self.type2test(converted))
self.assertConversion(binary, converted, restored, newline=newline)
def test_c_contiguity(self):
m = memoryview(bytearray(b'noncontig'))
noncontig_writable = m[::-2]
with self.assertRaises(BufferError):
binascii.b2a_hex(noncontig_writable)
class ArrayBinASCIITest(BinASCIITest):
def type2test(self, s):
return array.array('B', list(s))
class BytearrayBinASCIITest(BinASCIITest):
type2test = bytearray
class MemoryviewBinASCIITest(BinASCIITest):
type2test = memoryview
class ChecksumBigBufferTestCase(unittest.TestCase):
"""bpo-38256 - check that inputs >=4 GiB are handled correctly."""
@bigmemtest(size=_4G + 4, memuse=1, dry_run=False)
def test_big_buffer(self, size):
data = b"nyan" * (_1G + 1)
self.assertEqual(binascii.crc32(data), 1044521549)
if __name__ == "__main__":
unittest.main()