1"""Test the binascii C module.""" 2 3from test import test_support 4import unittest 5import binascii 6import array 7 8# Note: "*_hex" functions are aliases for "(un)hexlify" 9b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu', 10 'hexlify', 'rlecode_hqx'] 11a2b_functions = ['a2b_base64', 'a2b_hex', 'a2b_hqx', 'a2b_qp', 'a2b_uu', 12 'unhexlify', 'rledecode_hqx'] 13all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx'] 14 15 16class 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_crc_hqx(self): 141 crc = binascii.crc_hqx(self.type2test(b"Test the CRC-32 of"), 0) 142 crc = binascii.crc_hqx(self.type2test(b" this string."), crc) 143 self.assertEqual(crc, 14290) 144 145 self.assertRaises(TypeError, binascii.crc_hqx) 146 self.assertRaises(TypeError, binascii.crc_hqx, self.type2test(b'')) 147 148 def test_crc32(self): 149 crc = binascii.crc32(self.type2test("Test the CRC-32 of")) 150 crc = binascii.crc32(self.type2test(" this string."), crc) 151 self.assertEqual(crc, 1571220330) 152 153 self.assertRaises(TypeError, binascii.crc32) 154 155 def test_hqx(self): 156 # Perform binhex4 style RLE-compression 157 # Then calculate the hexbin4 binary-to-ASCII translation 158 rle = binascii.rlecode_hqx(self.data) 159 a = binascii.b2a_hqx(self.type2test(rle)) 160 b, _ = binascii.a2b_hqx(self.type2test(a)) 161 res = binascii.rledecode_hqx(b) 162 163 self.assertEqual(res, self.rawdata) 164 165 def test_hex(self): 166 # test hexlification 167 s = '{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000' 168 t = binascii.b2a_hex(self.type2test(s)) 169 u = binascii.a2b_hex(self.type2test(t)) 170 self.assertEqual(s, u) 171 self.assertRaises(TypeError, binascii.a2b_hex, t[:-1]) 172 self.assertRaises(TypeError, binascii.a2b_hex, t[:-1] + 'q') 173 174 # Verify the treatment of Unicode strings 175 if test_support.have_unicode: 176 self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61') 177 178 def test_qp(self): 179 type2test = self.type2test 180 a2b_qp = binascii.a2b_qp 181 b2a_qp = binascii.b2a_qp 182 183 a2b_qp(data=b"", header=False) # Keyword arguments allowed 184 185 # A test for SF bug 534347 (segfaults without the proper fix) 186 try: 187 a2b_qp(b"", **{1:1}) 188 except TypeError: 189 pass 190 else: 191 self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError") 192 193 self.assertEqual(a2b_qp(type2test(b"=")), b"") 194 self.assertEqual(a2b_qp(type2test(b"= ")), b"= ") 195 self.assertEqual(a2b_qp(type2test(b"==")), b"=") 196 self.assertEqual(a2b_qp(type2test(b"=\nAB")), b"AB") 197 self.assertEqual(a2b_qp(type2test(b"=\r\nAB")), b"AB") 198 self.assertEqual(a2b_qp(type2test(b"=\rAB")), b"") # ? 199 self.assertEqual(a2b_qp(type2test(b"=\rAB\nCD")), b"CD") # ? 200 self.assertEqual(a2b_qp(type2test(b"=AB")), b"\xab") 201 self.assertEqual(a2b_qp(type2test(b"=ab")), b"\xab") 202 self.assertEqual(a2b_qp(type2test(b"=AX")), b"=AX") 203 self.assertEqual(a2b_qp(type2test(b"=XA")), b"=XA") 204 self.assertEqual(a2b_qp(type2test(b"=AB")[:-1]), b"=A") 205 206 self.assertEqual(a2b_qp(type2test(b'_')), b'_') 207 self.assertEqual(a2b_qp(type2test(b'_'), header=True), b' ') 208 209 self.assertRaises(TypeError, b2a_qp, foo="bar") 210 self.assertEqual(a2b_qp(type2test(b"=00\r\n=00")), b"\x00\r\n\x00") 211 self.assertEqual(b2a_qp(type2test(b"\xff\r\n\xff\n\xff")), 212 b"=FF\r\n=FF\r\n=FF") 213 self.assertEqual(b2a_qp(type2test(b"0"*75+b"\xff\r\n\xff\r\n\xff")), 214 b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF") 215 216 self.assertEqual(b2a_qp(type2test(b'\x7f')), b'=7F') 217 self.assertEqual(b2a_qp(type2test(b'=')), b'=3D') 218 219 self.assertEqual(b2a_qp(type2test(b'_')), b'_') 220 self.assertEqual(b2a_qp(type2test(b'_'), header=True), b'=5F') 221 self.assertEqual(b2a_qp(type2test(b'x y'), header=True), b'x_y') 222 self.assertEqual(b2a_qp(type2test(b'x '), header=True), b'x=20') 223 self.assertEqual(b2a_qp(type2test(b'x y'), header=True, quotetabs=True), 224 b'x=20y') 225 self.assertEqual(b2a_qp(type2test(b'x\ty'), header=True), b'x\ty') 226 227 self.assertEqual(b2a_qp(type2test(b' ')), b'=20') 228 self.assertEqual(b2a_qp(type2test(b'\t')), b'=09') 229 self.assertEqual(b2a_qp(type2test(b' x')), b' x') 230 self.assertEqual(b2a_qp(type2test(b'\tx')), b'\tx') 231 self.assertEqual(b2a_qp(type2test(b' x')[:-1]), b'=20') 232 self.assertEqual(b2a_qp(type2test(b'\tx')[:-1]), b'=09') 233 self.assertEqual(b2a_qp(type2test(b'\0')), b'=00') 234 235 self.assertEqual(b2a_qp(type2test(b'\0\n')), b'=00\n') 236 self.assertEqual(b2a_qp(type2test(b'\0\n'), quotetabs=True), b'=00\n') 237 238 self.assertEqual(b2a_qp(type2test(b'x y\tz')), b'x y\tz') 239 self.assertEqual(b2a_qp(type2test(b'x y\tz'), quotetabs=True), 240 b'x=20y=09z') 241 self.assertEqual(b2a_qp(type2test(b'x y\tz'), istext=False), 242 b'x y\tz') 243 self.assertEqual(b2a_qp(type2test(b'x \ny\t\n')), 244 b'x=20\ny=09\n') 245 self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), quotetabs=True), 246 b'x=20\ny=09\n') 247 self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), istext=False), 248 b'x =0Ay\t=0A') 249 self.assertEqual(b2a_qp(type2test(b'x \ry\t\r')), 250 b'x \ry\t\r') 251 self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), quotetabs=True), 252 b'x=20\ry=09\r') 253 self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), istext=False), 254 b'x =0Dy\t=0D') 255 self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n')), 256 b'x=20\r\ny=09\r\n') 257 self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), quotetabs=True), 258 b'x=20\r\ny=09\r\n') 259 self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), istext=False), 260 b'x =0D=0Ay\t=0D=0A') 261 262 self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1]), b'x \r') 263 self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1]), b'x\t\r') 264 self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], quotetabs=True), 265 b'x=20\r') 266 self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], quotetabs=True), 267 b'x=09\r') 268 self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], istext=False), 269 b'x =0D') 270 self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], istext=False), 271 b'x\t=0D') 272 273 self.assertEqual(b2a_qp(type2test(b'.')), b'=2E') 274 self.assertEqual(b2a_qp(type2test(b'.\n')), b'=2E\n') 275 self.assertEqual(b2a_qp(type2test(b'.\r')), b'=2E\r') 276 self.assertEqual(b2a_qp(type2test(b'.\0')), b'=2E=00') 277 self.assertEqual(b2a_qp(type2test(b'a.\n')), b'a.\n') 278 self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E') 279 280 def test_empty_string(self): 281 # A test for SF bug #1022953. Make sure SystemError is not raised. 282 empty = self.type2test('') 283 for func in all_functions: 284 if func == 'crc_hqx': 285 # crc_hqx needs 2 arguments 286 binascii.crc_hqx(empty, 0) 287 continue 288 f = getattr(binascii, func) 289 try: 290 f(empty) 291 except Exception, err: 292 self.fail("{}({!r}) raises {!r}".format(func, empty, err)) 293 294 295class ArrayBinASCIITest(BinASCIITest): 296 def type2test(self, s): 297 return array.array('c', s) 298 299 300class BytearrayBinASCIITest(BinASCIITest): 301 type2test = bytearray 302 303 304class MemoryviewBinASCIITest(BinASCIITest): 305 type2test = memoryview 306 307 308def test_main(): 309 test_support.run_unittest(BinASCIITest, 310 ArrayBinASCIITest, 311 BytearrayBinASCIITest, 312 MemoryviewBinASCIITest) 313 314if __name__ == "__main__": 315 test_main() 316