test the binascii c module import unittest import binascii import array import re from test support import bigmemtest 1g 4g from test support hypothesishelper import hypothesis note hex functions are aliases for unhexlify b2afunctions b2abase64 b2ahex b2aqp b2auu hexlify a2bfunctions a2bbase64 a2bhex a2bqp a2buu unhexlify allfunctions a2bfunctions b2afunctions crc32 crchqx class binasciitestunittest testcase type2test bytes create binary test data rawdata bthe quick brown fox jumps over the lazy dog rn be slow so we don t depend on other modules rawdata bytesrange256 rawdata brnhello world n def setupself self data self type2testself rawdata def assertconversionself original converted restored kwargs self assertisinstanceoriginal bytes self assertisinstanceconverted bytes self assertisinstancerestored bytes if converted self assertlessmaxconverted 128 self assertequaloriginal restored msgf self type2test kwargs def testexceptionsself check module exceptions self asserttrueissubclassbinascii error exception self asserttrueissubclassbinascii incomplete exception def testfunctionsself check presence of all functions for name in allfunctions self asserttruehasattrgetattrbinascii name call self assertraisestypeerror getattrbinascii name def testreturnedvalueself limit to the minimum of all limits b2auu maxall 45 raw self rawdata maxall for fa fb in zipa2bfunctions b2afunctions a2b getattrbinascii fa b2a getattrbinascii fb try a b2aself type2testraw res a2bself type2testa except exception as err self fail conversion raises r formatfb fa err self assertequalres raw conversion r r formatfb fa res raw self assertconversionraw a res self assertisinstancebinascii crchqxraw 0 int self assertisinstancebinascii crc32raw int def testbase64validself test base64 with valid data maxbase64 57 lines for i in range0 lenself rawdata maxbase64 b self type2testself rawdatai imaxbase64 a binascii b2abase64b lines appenda res bytes for line in lines a self type2testline b binascii a2bbase64a res b self assertequalres self rawdata def testbase64invalidself test base64 with random invalid characters sprinkled throughout this requires a new version of binascii maxbase64 57 lines for i in range0 lenself data maxbase64 b self type2testself rawdatai imaxbase64 a binascii b2abase64b lines appenda fillers bytearray valid babcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789 for i in range256 if i not in valid fillers appendi def addnoiseline noise fillers ratio lenline lennoise res bytearray while line and noise if lenline lennoise ratio c line line0 line1 else c noise noise0 noise1 res appendc return res noise line res bytearray for line in mapaddnoise lines a self type2testline b binascii a2bbase64a res b self assertequalres self rawdata test base64 with just invalid characters which should return empty strings tbd shouldn t it raise an exception instead self assertequalbinascii a2bbase64self type2testfillers b def testbase64strictmodeself test base64 with strict mode on def assertregextemplateassertregex str data bytes nonstrictmodeexpectedresult bytes with self assertraisesregexbinascii error assertregex binascii a2bbase64self type2testdata strictmodetrue self assertequalbinascii a2bbase64self type2testdata strictmodefalse nonstrictmodeexpectedresult self assertequalbinascii a2bbase64self type2testdata nonstrictmodeexpectedresult def assertexcessdatadata nonstrictmodeexpectedresult bytes assertregextemplater iexcess data data nonstrictmodeexpectedresult def assertnonbase64datadata nonstrictmodeexpectedresult bytes assertregextemplater ionly base64 data data nonstrictmodeexpectedresult def assertleadingpaddingdata nonstrictmodeexpectedresult bytes assertregextemplater ileading padding data nonstrictmodeexpectedresult def assertdiscontinuouspaddingdata nonstrictmodeexpectedresult bytes assertregextemplater idiscontinuous padding data nonstrictmodeexpectedresult test excess data exceptions assertexcessdatab aba b i assertexcessdatab ab b i assertexcessdatab ab b i assertexcessdatab abca b ixb7 assertexcessdatab abc b ixb7 assertexcessdatab abn b i test nonbase64 data exceptions assertnonbase64datab nab b i assertnonbase64datab ab b i assertnonbase64datab anb b i assertnonbase64datab ax00b b i test malformed padding assertleadingpaddingb b assertleadingpaddingb b assertleadingpaddingb b assertdiscontinuouspaddingb abc b ixb7 assertdiscontinuouspaddingb abab b ixb6x9b def testbase64errorsself test base64 with invalid padding def assertincorrectpaddingdata with self assertraisesregexbinascii error r iincorrect padding binascii a2bbase64self type2testdata assertincorrectpaddingb ab assertincorrectpaddingb ab assertincorrectpaddingb abc assertincorrectpaddingb abcdef assertincorrectpaddingb abcdef assertincorrectpaddingb abcdefg assertincorrectpaddingb ab assertincorrectpaddingb anb test base64 with invalid number of valid characters 1 mod 4 def assertinvalidlengthdata ndatachars lenre subbr azaz09 br data expectederrmsgre r iinvalid number of data characters strndatachars with self assertraisesregexbinascii error expectederrmsgre binascii a2bbase64self type2testdata assertinvalidlengthb a assertinvalidlengthb a assertinvalidlengthb a assertinvalidlengthb a assertinvalidlengthb a 5 assertinvalidlengthb a 4 87 1 assertinvalidlengthb atbnc de only 5 valid characters def testuuself maxuu 45 for backtick in true false lines for i in range0 lenself data maxuu b self type2testself rawdatai imaxuu a binascii b2auub backtickbacktick lines appenda res bytes for line in lines a self type2testline b binascii a2buua res b self assertequalres self rawdata self assertequalbinascii a2buubx7f bx0031 self assertequalbinascii a2buubx80 bx0032 self assertequalbinascii a2buubxff bx0031 self assertraisesbinascii error binascii a2buu bxffx00 self assertraisesbinascii error binascii a2buu b self assertraisesbinascii error binascii b2auu 46b issue 7701 crash on a pydebug build self assertequalbinascii b2auub x b n self assertequalbinascii b2auub b n self assertequalbinascii b2auub backticktrue b n self assertequalbinascii a2buub n b self assertequalbinascii a2buub n b self assertequalbinascii b2auub x00cat b a n self assertequalbinascii b2auub x00cat backticktrue b an self assertequalbinascii a2buub an binascii a2buub a n with self assertraisestypeerror binascii b2auub true hypothesis given binaryhypothesis strategies binarymaxsize45 backtickhypothesis strategies booleans def testb2aroundtripself binary backtick converted binascii b2auuself type2testbinary backtickbacktick restored binascii a2buuself type2testconverted self assertconversionbinary converted restored backtickbacktick def testcrchqxself crc binascii crchqxself type2testbtest the crc32 of 0 crc binascii crchqxself type2testb this string crc self assertequalcrc 14290 self assertraisestypeerror binascii crchqx self assertraisestypeerror binascii crchqx self type2testb for crc in 0 1 0x1234 0x12345 0x12345678 1 self assertequalbinascii crchqxself type2testb crc crc 0xffff def testcrc32self crc binascii crc32self type2testbtest the crc32 of crc binascii crc32self type2testb this string crc self assertequalcrc 1571220330 self assertraisestypeerror binascii crc32 def testhexself test hexlification s b s005000000000worldi002000000000s005000000000helloi0010000000000 t binascii b2ahexself type2tests u binascii a2bhexself type2testt self assertequals u self assertraisesbinascii error binascii a2bhex t 1 self assertraisesbinascii error binascii a2bhex t 1 b q self assertraisesbinascii error binascii a2bhex bytes255 255 self assertraisesbinascii error binascii a2bhex b 0g self assertraisesbinascii error binascii a2bhex b 0g self assertraisesbinascii error binascii a2bhex b g0 self assertraisesbinascii error binascii a2bhex b g0 confirm that b2ahex hexlify and a2bhex unhexlify self assertequalbinascii hexlifyself type2tests t self assertequalbinascii unhexlifyself type2testt u hypothesis givenbinaryhypothesis strategies binary def testhexroundtripself binary converted binascii hexlifyself type2testbinary restored binascii unhexlifyself type2testconverted self assertconversionbinary converted restored def testhexseparatorself logic of separators is tested in testbytes py this checks that arg parsing works and exercises the direct to bytes object code path within pystrhex c a test for sf bug 534347 segfaults without the proper fix a test for sf bug 1022953 make sure systemerror is not raised crchqx needs 2 arguments unicode strings are not accepted by b2a functions crchqx needs 2 arguments unicode strings are accepted by a2b functions nonascii string issue 25357 test newline parameter bpo38256 check that inputs 4 gib are handled correctly bigmemtestsize4g 4 memuse1 dryrunfalse def testbigbufferself size data bnyan 1g 1 self assertequalbinascii crc32data 1044521549 if name main unittest main note _hex functions are aliases for un hexlify create binary test data be slow so we don t depend on other modules check module exceptions check presence of all functions limit to the minimum of all limits b2a_uu test base64 with valid data test base64 with random invalid characters sprinkled throughout this requires a new version of binascii test base64 with just invalid characters which should return empty strings tbd shouldn t it raise an exception instead test base64 with strict mode on test excess data exceptions test non base64 data exceptions test malformed padding test base64 with invalid padding test base64 with invalid number of valid characters 1 mod 4 only 5 valid characters issue 7701 crash on a pydebug build test hexlification confirm that b2a_hex hexlify and a2b_hex unhexlify 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 keyword arguments allowed a test for sf bug 534347 segfaults without the proper fix a test for sf bug 1022953 make sure systemerror is not raised crc_hqx needs 2 arguments unicode strings are not accepted by b2a_ functions crc_hqx needs 2 arguments unicode strings are accepted by a2b_ functions non ascii string issue 25357 test newline parameter bpo 38256 check that inputs 4 gib are handled correctly
import unittest
import binascii
import array
import re
from test.support import bigmemtest, _1G, _4G
from test.support.hypothesis_helper import hypothesis



b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_qp', 'b2a_uu',
                 'hexlify']
a2b_functions = ['a2b_base64', 'a2b_hex', 'a2b_qp', 'a2b_uu',
                 'unhexlify']
all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx']


class BinASCIITest(unittest.TestCase):

    type2test = bytes
    
    rawdata = b"The quick brown fox jumps over the lazy dog.\r\n"
    
    rawdata += bytes(range(256))
    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):
        
        self.assertTrue(issubclass(binascii.Error, Exception))
        self.assertTrue(issubclass(binascii.Incomplete, Exception))

    def test_functions(self):
        
        for name in all_functions:
            self.assertTrue(hasattr(getattr(binascii, name), '__call__'))
            self.assertRaises(TypeError, getattr(binascii, name))

    def test_returned_value(self):
        
        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):
        
        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):
        
        
        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)

        
        
        self.assertEqual(binascii.a2b_base64(self.type2test(fillers)), b'')

    def test_base64_strict_mode(self):
        
        def _assertRegexTemplate(assert_regex: str, data: bytes, non_strict_mode_expected_result: bytes):
            with self.assertRaisesRegex(binascii.Error, assert_regex):
                binascii.a2b_base64(self.type2test(data), strict_mode=True)
            self.assertEqual(binascii.a2b_base64(self.type2test(data), strict_mode=False),
                             non_strict_mode_expected_result)
            self.assertEqual(binascii.a2b_base64(self.type2test(data)),
                             non_strict_mode_expected_result)

        def assertExcessData(data, non_strict_mode_expected_result: bytes):
            _assertRegexTemplate(r'(?i)Excess data', data, non_strict_mode_expected_result)

        def assertNonBase64Data(data, non_strict_mode_expected_result: bytes):
            _assertRegexTemplate(r'(?i)Only base64 data', data, non_strict_mode_expected_result)

        def assertLeadingPadding(data, non_strict_mode_expected_result: bytes):
            _assertRegexTemplate(r'(?i)Leading padding', data, non_strict_mode_expected_result)

        def assertDiscontinuousPadding(data, non_strict_mode_expected_result: bytes):
            _assertRegexTemplate(r'(?i)Discontinuous padding', data, non_strict_mode_expected_result)

        
        assertExcessData(b'ab==a', b'i')
        assertExcessData(b'ab===', b'i')
        assertExcessData(b'ab==:', b'i')
        assertExcessData(b'abc=a', b'i\xb7')
        assertExcessData(b'abc=:', b'i\xb7')
        assertExcessData(b'ab==\n', b'i')

        
        assertNonBase64Data(b'\nab==', b'i')
        assertNonBase64Data(b'ab:(){:|:&};:==', b'i')
        assertNonBase64Data(b'a\nb==', b'i')
        assertNonBase64Data(b'a\x00b==', b'i')

        
        assertLeadingPadding(b'=', b'')
        assertLeadingPadding(b'==', b'')
        assertLeadingPadding(b'===', b'')
        assertDiscontinuousPadding(b'ab=c=', b'i\xb7')
        assertDiscontinuousPadding(b'ab=ab==', b'i\xb6\x9b')


    def test_base64errors(self):
        
        def assertIncorrectPadding(data):
            with self.assertRaisesRegex(binascii.Error, r'(?i)Incorrect padding'):
                binascii.a2b_base64(self.type2test(data))

        assertIncorrectPadding(b'ab')
        assertIncorrectPadding(b'ab=')
        assertIncorrectPadding(b'abc')
        assertIncorrectPadding(b'abcdef')
        assertIncorrectPadding(b'abcdef=')
        assertIncorrectPadding(b'abcdefg')
        assertIncorrectPadding(b'a=b=')
        assertIncorrectPadding(b'a\nb=')

        
        def assertInvalidLength(data):
            n_data_chars = len(re.sub(br'[^A-Za-z0-9/+]', br'', 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(self.type2test(data))

        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')  

    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"!")

        
        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):
        
        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')

        
        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):
        
        
        
        
        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)  

        
        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):
        
        empty = self.type2test(b'')
        for func in all_functions:
            if func == 'crc_hqx':
                
                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):
        
        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))
        
        self.assertRaises(TypeError, binascii.crc_hqx, "test", 0)

    def test_unicode_a2b(self):
        
        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)
            
            self.assertRaises(ValueError, a2b, "\x80")

    def test_b2a_base64_newline(self):
        
        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=')

    @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):
    

    @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()