blob: 1dcd2b25c79087547c0fb324f4fe23626dc6b87a [file] [log] [blame]
"""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):
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),
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):
_assertRegexTemplate(r'(?i)Leading padding', *args)
def assertDiscontinuousPadding(*args):
_assertRegexTemplate(r'(?i)Discontinuous padding', *args)
def assertExcessPadding(*args):
_assertRegexTemplate(r'(?i)Excess padding', *args)
def assertInvalidLength(*args):
_assertRegexTemplate(r'(?i)Invalid.+number of data characters', *args)
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')
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')
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_base64_invalidchars(self):
# Test non-base64 data exceptions
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'))
# 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'')
data = self.type2test(b'a\nb==')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, ignorechars='')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, ignorechars=[])
with self.assertRaises(TypeError):
binascii.a2b_base64(data, ignorechars=None)
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 test_ascii85_wrapcol(self):
# Test Ascii85 splitting lines
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_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_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):
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_base32(self.type2test(data))
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):
_assertRegexTemplate(r"(?i)Leading padding", *args)
def assertIncorrectPadding(*args):
_assertRegexTemplate(r"(?i)Incorrect padding", *args)
def assertDiscontinuousPadding(*args):
_assertRegexTemplate(r"(?i)Discontinuous padding", *args)
def assertInvalidLength(*args):
_assertRegexTemplate(r"(?i)Invalid.+number of data characters", *args)
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")
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"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")
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_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_wrapcol(self):
b = self.type2test(b'www.python.org')
self.assertEqual(binascii.b2a_base64(b),
b'd3d3LnB5dGhvbi5vcmc=\n')
self.assertEqual(binascii.b2a_base64(b, wrapcol=0),
b'd3d3LnB5dGhvbi5vcmc=\n')
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=76),
b'd3d3LnB5dGhvbi5vcmc=\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')
self.assertEqual(binascii.b2a_base64(b, wrapcol=sys.maxsize),
b'd3d3LnB5dGhvbi5vcmc=\n')
if check_impl_detail():
self.assertEqual(binascii.b2a_base64(b, wrapcol=sys.maxsize*2),
b'd3d3LnB5dGhvbi5vcmc=\n')
with self.assertRaises(OverflowError):
binascii.b2a_base64(b, wrapcol=2**1000)
with self.assertRaises(ValueError):
binascii.b2a_base64(b, wrapcol=-8)
with self.assertRaises(TypeError):
binascii.b2a_base64(b, wrapcol=8.0)
with self.assertRaises(TypeError):
binascii.b2a_base64(b, wrapcol='8')
b = self.type2test(b'')
self.assertEqual(binascii.b2a_base64(b), b'\n')
self.assertEqual(binascii.b2a_base64(b, wrapcol=0), b'\n')
self.assertEqual(binascii.b2a_base64(b, wrapcol=8), b'\n')
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()