1 """Test the binascii C module.""" 2 3 from test import test_support 4 import unittest 5 import binascii 6 import array 7 8 # Note: "*_hex" functions are aliases for "(un)hexlify" 9 b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu', 10 'hexlify', 'rlecode_hqx'] 11 a2b_functions = ['a2b_base64', 'a2b_hex', 'a2b_hqx', 'a2b_qp', 'a2b_uu', 12 'unhexlify', 'rledecode_hqx'] 13 all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx'] 14 15 16 class BinASCIITest(unittest.TestCase): 17 18 type2test = str 19 # Create binary test data 20 rawdata = "The quick brown fox jumps over the lazy dog.\r\n" 21 # Be slow so we don't depend on other modules 22 rawdata += "".join(map(chr, xrange(256))) 23 rawdata += "\r\nHello world.\n" 24 25 def setUp(self): 26 self.data = self.type2test(self.rawdata) 27 28 def test_exceptions(self): 29 # Check module exceptions 30 self.assertTrue(issubclass(binascii.Error, Exception)) 31 self.assertTrue(issubclass(binascii.Incomplete, Exception)) 32 33 def test_functions(self): 34 # Check presence of all functions 35 for name in all_functions: 36 self.assertTrue(hasattr(getattr(binascii, name), '__call__')) 37 self.assertRaises(TypeError, getattr(binascii, name)) 38 39 def test_returned_value(self): 40 # Limit to the minimum of all limits (b2a_uu) 41 MAX_ALL = 45 42 raw = self.rawdata[:MAX_ALL] 43 for fa, fb in zip(a2b_functions, b2a_functions): 44 a2b = getattr(binascii, fa) 45 b2a = getattr(binascii, fb) 46 try: 47 a = b2a(self.type2test(raw)) 48 res = a2b(self.type2test(a)) 49 except Exception, err: 50 self.fail("{}/{} conversion raises {!r}".format(fb, fa, err)) 51 if fb == 'b2a_hqx': 52 # b2a_hqx returns a tuple 53 res, _ = res 54 self.assertEqual(res, raw, "{}/{} conversion: " 55 "{!r} != {!r}".format(fb, fa, res, raw)) 56 self.assertIsInstance(res, str) 57 self.assertIsInstance(a, str) 58 self.assertLess(max(ord(c) for c in a), 128) 59 self.assertIsInstance(binascii.crc_hqx(raw, 0), int) 60 self.assertIsInstance(binascii.crc32(raw), int) 61 62 def test_base64valid(self): 63 # Test base64 with valid data 64 MAX_BASE64 = 57 65 lines = [] 66 for i in range(0, len(self.rawdata), MAX_BASE64): 67 b = self.type2test(self.rawdata[i:i+MAX_BASE64]) 68 a = binascii.b2a_base64(b) 69 lines.append(a) 70 res = "" 71 for line in lines: 72 a = self.type2test(line) 73 b = binascii.a2b_base64(a) 74 res = res + b 75 self.assertEqual(res, self.rawdata) 76 77 def test_base64invalid(self): 78 # Test base64 with random invalid characters sprinkled throughout 79 # (This requires a new version of binascii.) 80 MAX_BASE64 = 57 81 lines = [] 82 for i in range(0, len(self.data), MAX_BASE64): 83 b = self.type2test(self.rawdata[i:i+MAX_BASE64]) 84 a = binascii.b2a_base64(b) 85 lines.append(a) 86 87 fillers = "" 88 valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" 89 for i in xrange(256): 90 c = chr(i) 91 if c not in valid: 92 fillers += c 93 def addnoise(line): 94 noise = fillers 95 ratio = len(line) // len(noise) 96 res = "" 97 while line and noise: 98 if len(line) // len(noise) > ratio: 99 c, line = line[0], line[1:] 100 else: 101 c, noise = noise[0], noise[1:] 102 res += c 103 return res + noise + line 104 res = "" 105 for line in map(addnoise, lines): 106 a = self.type2test(line) 107 b = binascii.a2b_base64(a) 108 res += b 109 self.assertEqual(res, self.rawdata) 110 111 # Test base64 with just invalid characters, which should return 112 # empty strings. TBD: shouldn't it raise an exception instead ? 113 self.assertEqual(binascii.a2b_base64(self.type2test(fillers)), '') 114 115 def test_uu(self): 116 MAX_UU = 45 117 lines = [] 118 for i in range(0, len(self.data), MAX_UU): 119 b = self.type2test(self.rawdata[i:i+MAX_UU]) 120 a = binascii.b2a_uu(b) 121 lines.append(a) 122 res = "" 123 for line in lines: 124 a = self.type2test(line) 125 b = binascii.a2b_uu(a) 126 res += b 127 self.assertEqual(res, self.rawdata) 128 129 self.assertEqual(binascii.a2b_uu("\x7f"), "\x00"*31) 130 self.assertEqual(binascii.a2b_uu("\x80"), "\x00"*32) 131 self.assertEqual(binascii.a2b_uu("\xff"), "\x00"*31) 132 self.assertRaises(binascii.Error, binascii.a2b_uu, "\xff\x00") 133 self.assertRaises(binascii.Error, binascii.a2b_uu, "!!!!") 134 135 self.assertRaises(binascii.Error, binascii.b2a_uu, 46*"!") 136 137 # Issue #7701 (crash on a pydebug build) 138 self.assertEqual(binascii.b2a_uu('x'), '!> \n') 139 140 def test_crc32(self): 141 crc = binascii.crc32(self.type2test("Test the CRC-32 of")) 142 crc = binascii.crc32(self.type2test(" this string."), crc) 143 self.assertEqual(crc, 1571220330) 144 145 self.assertRaises(TypeError, binascii.crc32) 146 147 def test_hqx(self): 148 # Perform binhex4 style RLE-compression 149 # Then calculate the hexbin4 binary-to-ASCII translation 150 rle = binascii.rlecode_hqx(self.data) 151 a = binascii.b2a_hqx(self.type2test(rle)) 152 b, _ = binascii.a2b_hqx(self.type2test(a)) 153 res = binascii.rledecode_hqx(b) 154 155 self.assertEqual(res, self.rawdata) 156 157 def test_hex(self): 158 # test hexlification 159 s = '{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000' 160 t = binascii.b2a_hex(self.type2test(s)) 161 u = binascii.a2b_hex(self.type2test(t)) 162 self.assertEqual(s, u) 163 self.assertRaises(TypeError, binascii.a2b_hex, t[:-1]) 164 self.assertRaises(TypeError, binascii.a2b_hex, t[:-1] + 'q') 165 166 # Verify the treatment of Unicode strings 167 if test_support.have_unicode: 168 self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61') 169 170 def test_qp(self): 171 # A test for SF bug 534347 (segfaults without the proper fix) 172 try: 173 binascii.a2b_qp("", **{1:1}) 174 except TypeError: 175 pass 176 else: 177 self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError") 178 self.assertEqual(binascii.a2b_qp("= "), "= ") 179 self.assertEqual(binascii.a2b_qp("=="), "=") 180 self.assertEqual(binascii.a2b_qp("=AX"), "=AX") 181 self.assertRaises(TypeError, binascii.b2a_qp, foo="bar") 182 self.assertEqual(binascii.a2b_qp("=00\r\n=00"), "\x00\r\n\x00") 183 self.assertEqual( 184 binascii.b2a_qp("\xff\r\n\xff\n\xff"), 185 "=FF\r\n=FF\r\n=FF" 186 ) 187 self.assertEqual( 188 binascii.b2a_qp("0"*75+"\xff\r\n\xff\r\n\xff"), 189 "0"*75+"=\r\n=FF\r\n=FF\r\n=FF" 190 ) 191 192 self.assertEqual(binascii.b2a_qp('\0\n'), '=00\n') 193 self.assertEqual(binascii.b2a_qp('\0\n', quotetabs=True), '=00\n') 194 self.assertEqual(binascii.b2a_qp('foo\tbar\t\n'), 'foo\tbar=09\n') 195 self.assertEqual(binascii.b2a_qp('foo\tbar\t\n', quotetabs=True), 'foo=09bar=09\n') 196 197 self.assertEqual(binascii.b2a_qp('.'), '=2E') 198 self.assertEqual(binascii.b2a_qp('.\n'), '=2E\n') 199 self.assertEqual(binascii.b2a_qp('a.\n'), 'a.\n') 200 201 def test_empty_string(self): 202 # A test for SF bug #1022953. Make sure SystemError is not raised. 203 empty = self.type2test('') 204 for func in all_functions: 205 if func == 'crc_hqx': 206 # crc_hqx needs 2 arguments 207 binascii.crc_hqx(empty, 0) 208 continue 209 f = getattr(binascii, func) 210 try: 211 f(empty) 212 except Exception, err: 213 self.fail("{}({!r}) raises {!r}".format(func, empty, err)) 214 215 216 class ArrayBinASCIITest(BinASCIITest): 217 def type2test(self, s): 218 return array.array('c', s) 219 220 221 class BytearrayBinASCIITest(BinASCIITest): 222 type2test = bytearray 223 224 225 class MemoryviewBinASCIITest(BinASCIITest): 226 type2test = memoryview 227 228 229 def test_main(): 230 test_support.run_unittest(BinASCIITest, 231 ArrayBinASCIITest, 232 BytearrayBinASCIITest, 233 MemoryviewBinASCIITest) 234 235 if __name__ == "__main__": 236 test_main() 237