| Barry Warsaw | 04f357c | 2002-07-23 19:04:11 +0000 | [diff] [blame] | 1 | from test.test_support import TestFailed, verbose, verify | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 2 | import struct | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 3 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 4 | import sys | 
 | 5 | ISBIGENDIAN = sys.byteorder == "big" | 
 | 6 | del sys | 
 | 7 | verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN, | 
 | 8 |        "bigendian determination appears wrong") | 
 | 9 |  | 
 | 10 | def string_reverse(s): | 
 | 11 |     chars = list(s) | 
 | 12 |     chars.reverse() | 
 | 13 |     return "".join(chars) | 
 | 14 |  | 
 | 15 | def bigendian_to_native(value): | 
 | 16 |     if ISBIGENDIAN: | 
 | 17 |         return value | 
 | 18 |     else: | 
 | 19 |         return string_reverse(value) | 
 | 20 |  | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 21 | def simple_err(func, *args): | 
 | 22 |     try: | 
| Guido van Rossum | 68468eb | 2003-02-27 20:14:51 +0000 | [diff] [blame] | 23 |         func(*args) | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 24 |     except struct.error: | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 25 |         pass | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 26 |     else: | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 27 |         raise TestFailed, "%s%s did not raise struct.error" % ( | 
 | 28 |             func.__name__, args) | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 29 |  | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 30 | def any_err(func, *args): | 
 | 31 |     try: | 
| Guido van Rossum | 68468eb | 2003-02-27 20:14:51 +0000 | [diff] [blame] | 32 |         func(*args) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 33 |     except (struct.error, OverflowError, TypeError): | 
 | 34 |         pass | 
 | 35 |     else: | 
 | 36 |         raise TestFailed, "%s%s did not raise error" % ( | 
 | 37 |             func.__name__, args) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 38 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 39 |  | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 40 | simple_err(struct.calcsize, 'Z') | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 41 |  | 
 | 42 | sz = struct.calcsize('i') | 
| Fred Drake | 132dce2 | 2000-12-12 23:11:42 +0000 | [diff] [blame] | 43 | if sz * 3 != struct.calcsize('iii'): | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 44 |     raise TestFailed, 'inconsistent sizes' | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 45 |  | 
| Guido van Rossum | 04ebf5c | 1997-01-03 19:00:37 +0000 | [diff] [blame] | 46 | fmt = 'cbxxxxxxhhhhiillffd' | 
 | 47 | fmt3 = '3c3b18x12h6i6l6f3d' | 
 | 48 | sz = struct.calcsize(fmt) | 
 | 49 | sz3 = struct.calcsize(fmt3) | 
| Fred Drake | 132dce2 | 2000-12-12 23:11:42 +0000 | [diff] [blame] | 50 | if sz * 3 != sz3: | 
| Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame^] | 51 |     raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % ( | 
 | 52 |         fmt, sz, 3*sz, fmt3, sz3) | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 53 |  | 
 | 54 | simple_err(struct.pack, 'iii', 3) | 
 | 55 | simple_err(struct.pack, 'i', 3, 3, 3) | 
 | 56 | simple_err(struct.pack, 'i', 'foo') | 
 | 57 | simple_err(struct.unpack, 'd', 'flap') | 
 | 58 | s = struct.pack('ii', 1, 2) | 
 | 59 | simple_err(struct.unpack, 'iii', s) | 
 | 60 | simple_err(struct.unpack, 'i', s) | 
 | 61 |  | 
 | 62 | c = 'a' | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 63 | b = 1 | 
| Barry Warsaw | 07a0eec | 1996-12-12 23:34:06 +0000 | [diff] [blame] | 64 | h = 255 | 
 | 65 | i = 65535 | 
 | 66 | l = 65536 | 
 | 67 | f = 3.1415 | 
 | 68 | d = 3.1415 | 
 | 69 |  | 
| Guido van Rossum | 420c11c | 1997-01-03 00:09:46 +0000 | [diff] [blame] | 70 | for prefix in ('', '@', '<', '>', '=', '!'): | 
 | 71 |     for format in ('xcbhilfd', 'xcBHILfd'): | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 72 |         format = prefix + format | 
 | 73 |         if verbose: | 
 | 74 |             print "trying:", format | 
 | 75 |         s = struct.pack(format, c, b, h, i, l, f, d) | 
 | 76 |         cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s) | 
| Fred Drake | 132dce2 | 2000-12-12 23:11:42 +0000 | [diff] [blame] | 77 |         if (cp != c or bp != b or hp != h or ip != i or lp != l or | 
 | 78 |             int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)): | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 79 |             # ^^^ calculate only to two decimal places | 
 | 80 |             raise TestFailed, "unpack/pack not transitive (%s, %s)" % ( | 
 | 81 |                 str(format), str((cp, bp, hp, ip, lp, fp, dp))) | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 82 |  | 
| Guido van Rossum | 420c11c | 1997-01-03 00:09:46 +0000 | [diff] [blame] | 83 | # Test some of the new features in detail | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 84 |  | 
 | 85 | # (format, argument, big-endian result, little-endian result, asymmetric) | 
 | 86 | tests = [ | 
 | 87 |     ('c', 'a', 'a', 'a', 0), | 
 | 88 |     ('xc', 'a', '\0a', '\0a', 0), | 
 | 89 |     ('cx', 'a', 'a\0', 'a\0', 0), | 
 | 90 |     ('s', 'a', 'a', 'a', 0), | 
 | 91 |     ('0s', 'helloworld', '', '', 1), | 
 | 92 |     ('1s', 'helloworld', 'h', 'h', 1), | 
 | 93 |     ('9s', 'helloworld', 'helloworl', 'helloworl', 1), | 
 | 94 |     ('10s', 'helloworld', 'helloworld', 'helloworld', 0), | 
 | 95 |     ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1), | 
 | 96 |     ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1), | 
 | 97 |     ('b', 7, '\7', '\7', 0), | 
 | 98 |     ('b', -7, '\371', '\371', 0), | 
 | 99 |     ('B', 7, '\7', '\7', 0), | 
 | 100 |     ('B', 249, '\371', '\371', 0), | 
 | 101 |     ('h', 700, '\002\274', '\274\002', 0), | 
 | 102 |     ('h', -700, '\375D', 'D\375', 0), | 
 | 103 |     ('H', 700, '\002\274', '\274\002', 0), | 
 | 104 |     ('H', 0x10000-700, '\375D', 'D\375', 0), | 
 | 105 |     ('i', 70000000, '\004,\035\200', '\200\035,\004', 0), | 
 | 106 |     ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0), | 
 | 107 |     ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0), | 
 | 108 |     ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), | 
 | 109 |     ('l', 70000000, '\004,\035\200', '\200\035,\004', 0), | 
 | 110 |     ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0), | 
 | 111 |     ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0), | 
 | 112 |     ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), | 
| Guido van Rossum | 420c11c | 1997-01-03 00:09:46 +0000 | [diff] [blame] | 113 |     ('f', 2.0, '@\000\000\000', '\000\000\000@', 0), | 
 | 114 |     ('d', 2.0, '@\000\000\000\000\000\000\000', | 
 | 115 |                '\000\000\000\000\000\000\000@', 0), | 
 | 116 |     ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), | 
 | 117 |     ('d', -2.0, '\300\000\000\000\000\000\000\000', | 
 | 118 |                '\000\000\000\000\000\000\000\300', 0), | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 119 | ] | 
 | 120 |  | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 121 | for fmt, arg, big, lil, asy in tests: | 
 | 122 |     if verbose: | 
| Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame^] | 123 |         print "%r %r %r %r" % (fmt, arg, big, lil) | 
| Guido van Rossum | 2a37850 | 1996-12-31 17:25:47 +0000 | [diff] [blame] | 124 |     for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 125 |                         ('='+fmt, ISBIGENDIAN and big or lil)]: | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 126 |         res = struct.pack(xfmt, arg) | 
 | 127 |         if res != exp: | 
| Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame^] | 128 |             raise TestFailed, "pack(%r, %r) -> %r # expected %r" % ( | 
 | 129 |                 fmt, arg, res, exp) | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 130 |         n = struct.calcsize(xfmt) | 
 | 131 |         if n != len(res): | 
| Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame^] | 132 |             raise TestFailed, "calcsize(%r) -> %d # expected %d" % ( | 
 | 133 |                 xfmt, n, len(res)) | 
| Guido van Rossum | 41360a4 | 1998-03-26 19:42:58 +0000 | [diff] [blame] | 134 |         rev = struct.unpack(xfmt, res)[0] | 
 | 135 |         if rev != arg and not asy: | 
| Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame^] | 136 |             raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % ( | 
 | 137 |                 fmt, res, rev, arg) | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 138 |  | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 139 | ########################################################################### | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 140 | # Simple native q/Q tests. | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 141 |  | 
 | 142 | has_native_qQ = 1 | 
 | 143 | try: | 
 | 144 |     struct.pack("q", 5) | 
 | 145 | except struct.error: | 
 | 146 |     has_native_qQ = 0 | 
 | 147 |  | 
 | 148 | if verbose: | 
 | 149 |     print "Platform has native q/Q?", has_native_qQ and "Yes." or "No." | 
 | 150 |  | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 151 | any_err(struct.pack, "Q", -1)   # can't pack -1 as unsigned regardless | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 152 | simple_err(struct.pack, "q", "a")  # can't pack string as 'q' regardless | 
 | 153 | simple_err(struct.pack, "Q", "a")  # ditto, but 'Q' | 
 | 154 |  | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 155 | def test_native_qQ(): | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 156 |     bytes = struct.calcsize('q') | 
 | 157 |     # The expected values here are in big-endian format, primarily because | 
 | 158 |     # I'm on a little-endian machine and so this is the clearest way (for | 
 | 159 |     # me) to force the code to get exercised. | 
 | 160 |     for format, input, expected in ( | 
 | 161 |             ('q', -1, '\xff' * bytes), | 
 | 162 |             ('q', 0, '\x00' * bytes), | 
 | 163 |             ('Q', 0, '\x00' * bytes), | 
 | 164 |             ('q', 1L, '\x00' * (bytes-1) + '\x01'), | 
 | 165 |             ('Q', (1L << (8*bytes))-1, '\xff' * bytes), | 
 | 166 |             ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))): | 
 | 167 |         got = struct.pack(format, input) | 
| Tim Peters | c533edc | 2001-06-10 23:52:59 +0000 | [diff] [blame] | 168 |         native_expected = bigendian_to_native(expected) | 
 | 169 |         verify(got == native_expected, | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 170 |                "%r-pack of %r gave %r, not %r" % | 
| Tim Peters | c533edc | 2001-06-10 23:52:59 +0000 | [diff] [blame] | 171 |                     (format, input, got, native_expected)) | 
| Tim Peters | 7b9542a | 2001-06-10 23:40:19 +0000 | [diff] [blame] | 172 |         retrieved = struct.unpack(format, got)[0] | 
 | 173 |         verify(retrieved == input, | 
 | 174 |                "%r-unpack of %r gave %r, not %r" % | 
 | 175 |                     (format, got, retrieved, input)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 176 |  | 
 | 177 | if has_native_qQ: | 
 | 178 |     test_native_qQ() | 
 | 179 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 180 | ########################################################################### | 
 | 181 | # Standard integer tests (bBhHiIlLqQ). | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 182 |  | 
 | 183 | import binascii | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 184 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 185 | class IntTester: | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 186 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 187 |     # XXX Most std integer modes fail to test for out-of-range. | 
| Tim Peters | 3eec38a | 2001-06-18 22:27:39 +0000 | [diff] [blame] | 188 |     # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but | 
 | 189 |     # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C | 
 | 190 |     # reported by Mark Favas). | 
 | 191 |     BUGGY_RANGE_CHECK = "bBhHiIlL" | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 192 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 193 |     def __init__(self, formatpair, bytesize): | 
 | 194 |         assert len(formatpair) == 2 | 
 | 195 |         self.formatpair = formatpair | 
 | 196 |         for direction in "<>!=": | 
 | 197 |             for code in formatpair: | 
 | 198 |                 format = direction + code | 
 | 199 |                 verify(struct.calcsize(format) == bytesize) | 
 | 200 |         self.bytesize = bytesize | 
 | 201 |         self.bitsize = bytesize * 8 | 
 | 202 |         self.signed_code, self.unsigned_code = formatpair | 
 | 203 |         self.unsigned_min = 0 | 
 | 204 |         self.unsigned_max = 2L**self.bitsize - 1 | 
 | 205 |         self.signed_min = -(2L**(self.bitsize-1)) | 
 | 206 |         self.signed_max = 2L**(self.bitsize-1) - 1 | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 207 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 208 |     def test_one(self, x, pack=struct.pack, | 
 | 209 |                           unpack=struct.unpack, | 
 | 210 |                           unhexlify=binascii.unhexlify): | 
 | 211 |         if verbose: | 
 | 212 |             print "trying std", self.formatpair, "on", x, "==", hex(x) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 213 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 214 |         # Try signed. | 
 | 215 |         code = self.signed_code | 
 | 216 |         if self.signed_min <= x <= self.signed_max: | 
 | 217 |             # Try big-endian. | 
 | 218 |             expected = long(x) | 
 | 219 |             if x < 0: | 
 | 220 |                 expected += 1L << self.bitsize | 
 | 221 |                 assert expected > 0 | 
 | 222 |             expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' | 
 | 223 |             if len(expected) & 1: | 
 | 224 |                 expected = "0" + expected | 
 | 225 |             expected = unhexlify(expected) | 
 | 226 |             expected = "\x00" * (self.bytesize - len(expected)) + expected | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 227 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 228 |             # Pack work? | 
 | 229 |             format = ">" + code | 
 | 230 |             got = pack(format, x) | 
 | 231 |             verify(got == expected, | 
 | 232 |                    "'%s'-pack of %r gave %r, not %r" % | 
 | 233 |                     (format, x, got, expected)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 234 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 235 |             # Unpack work? | 
 | 236 |             retrieved = unpack(format, got)[0] | 
 | 237 |             verify(x == retrieved, | 
 | 238 |                    "'%s'-unpack of %r gave %r, not %r" % | 
 | 239 |                     (format, got, retrieved, x)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 240 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 241 |             # Adding any byte should cause a "too big" error. | 
 | 242 |             any_err(unpack, format, '\x01' + got) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 243 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 244 |             # Try little-endian. | 
 | 245 |             format = "<" + code | 
 | 246 |             expected = string_reverse(expected) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 247 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 248 |             # Pack work? | 
 | 249 |             got = pack(format, x) | 
 | 250 |             verify(got == expected, | 
 | 251 |                    "'%s'-pack of %r gave %r, not %r" % | 
 | 252 |                     (format, x, got, expected)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 253 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 254 |             # Unpack work? | 
 | 255 |             retrieved = unpack(format, got)[0] | 
 | 256 |             verify(x == retrieved, | 
 | 257 |                    "'%s'-unpack of %r gave %r, not %r" % | 
 | 258 |                     (format, got, retrieved, x)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 259 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 260 |             # Adding any byte should cause a "too big" error. | 
 | 261 |             any_err(unpack, format, '\x01' + got) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 262 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 263 |         else: | 
 | 264 |             # x is out of range -- verify pack realizes that. | 
 | 265 |             if code in self.BUGGY_RANGE_CHECK: | 
 | 266 |                 if verbose: | 
 | 267 |                     print "Skipping buggy range check for code", code | 
 | 268 |             else: | 
 | 269 |                 any_err(pack, ">" + code, x) | 
 | 270 |                 any_err(pack, "<" + code, x) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 271 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 272 |         # Much the same for unsigned. | 
 | 273 |         code = self.unsigned_code | 
 | 274 |         if self.unsigned_min <= x <= self.unsigned_max: | 
 | 275 |             # Try big-endian. | 
 | 276 |             format = ">" + code | 
 | 277 |             expected = long(x) | 
 | 278 |             expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' | 
 | 279 |             if len(expected) & 1: | 
 | 280 |                 expected = "0" + expected | 
 | 281 |             expected = unhexlify(expected) | 
 | 282 |             expected = "\x00" * (self.bytesize - len(expected)) + expected | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 283 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 284 |             # Pack work? | 
 | 285 |             got = pack(format, x) | 
 | 286 |             verify(got == expected, | 
 | 287 |                    "'%s'-pack of %r gave %r, not %r" % | 
 | 288 |                     (format, x, got, expected)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 289 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 290 |             # Unpack work? | 
 | 291 |             retrieved = unpack(format, got)[0] | 
 | 292 |             verify(x == retrieved, | 
 | 293 |                    "'%s'-unpack of %r gave %r, not %r" % | 
 | 294 |                     (format, got, retrieved, x)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 295 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 296 |             # Adding any byte should cause a "too big" error. | 
 | 297 |             any_err(unpack, format, '\x01' + got) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 298 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 299 |             # Try little-endian. | 
 | 300 |             format = "<" + code | 
 | 301 |             expected = string_reverse(expected) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 302 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 303 |             # Pack work? | 
 | 304 |             got = pack(format, x) | 
 | 305 |             verify(got == expected, | 
 | 306 |                    "'%s'-pack of %r gave %r, not %r" % | 
 | 307 |                     (format, x, got, expected)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 308 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 309 |             # Unpack work? | 
 | 310 |             retrieved = unpack(format, got)[0] | 
 | 311 |             verify(x == retrieved, | 
 | 312 |                    "'%s'-unpack of %r gave %r, not %r" % | 
 | 313 |                     (format, got, retrieved, x)) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 314 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 315 |             # Adding any byte should cause a "too big" error. | 
 | 316 |             any_err(unpack, format, '\x01' + got) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 317 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 318 |         else: | 
 | 319 |             # x is out of range -- verify pack realizes that. | 
 | 320 |             if code in self.BUGGY_RANGE_CHECK: | 
 | 321 |                 if verbose: | 
 | 322 |                     print "Skipping buggy range check for code", code | 
 | 323 |             else: | 
 | 324 |                 any_err(pack, ">" + code, x) | 
 | 325 |                 any_err(pack, "<" + code, x) | 
| Tim Peters | 7a3bfc3 | 2001-06-12 01:22:22 +0000 | [diff] [blame] | 326 |  | 
| Tim Peters | 17e17d4 | 2001-06-13 22:45:27 +0000 | [diff] [blame] | 327 |     def run(self): | 
 | 328 |         from random import randrange | 
 | 329 |  | 
 | 330 |         # Create all interesting powers of 2. | 
 | 331 |         values = [] | 
 | 332 |         for exp in range(self.bitsize + 3): | 
 | 333 |             values.append(1L << exp) | 
 | 334 |  | 
 | 335 |         # Add some random values. | 
 | 336 |         for i in range(self.bitsize): | 
 | 337 |             val = 0L | 
 | 338 |             for j in range(self.bytesize): | 
 | 339 |                 val = (val << 8) | randrange(256) | 
 | 340 |             values.append(val) | 
 | 341 |  | 
 | 342 |         # Try all those, and their negations, and +-1 from them.  Note | 
 | 343 |         # that this tests all power-of-2 boundaries in range, and a few out | 
 | 344 |         # of range, plus +-(2**n +- 1). | 
 | 345 |         for base in values: | 
 | 346 |             for val in -base, base: | 
 | 347 |                 for incr in -1, 0, 1: | 
 | 348 |                     x = val + incr | 
 | 349 |                     try: | 
 | 350 |                         x = int(x) | 
 | 351 |                     except OverflowError: | 
 | 352 |                         pass | 
 | 353 |                     self.test_one(x) | 
 | 354 |  | 
 | 355 |         # Some error cases. | 
 | 356 |         for direction in "<>": | 
 | 357 |             for code in self.formatpair: | 
 | 358 |                 for badobject in "a string", 3+42j, randrange: | 
 | 359 |                     any_err(struct.pack, direction + code, badobject) | 
 | 360 |  | 
 | 361 | for args in [("bB", 1), | 
 | 362 |              ("hH", 2), | 
 | 363 |              ("iI", 4), | 
 | 364 |              ("lL", 4), | 
 | 365 |              ("qQ", 8)]: | 
 | 366 |     t = IntTester(*args) | 
 | 367 |     t.run() | 
| Tim Peters | 0891ac0 | 2001-09-15 02:35:15 +0000 | [diff] [blame] | 368 |  | 
 | 369 |  | 
 | 370 | ########################################################################### | 
 | 371 | # The p ("Pascal string") code. | 
 | 372 |  | 
 | 373 | def test_p_code(): | 
 | 374 |     for code, input, expected, expectedback in [ | 
 | 375 |             ('p','abc', '\x00', ''), | 
 | 376 |             ('1p', 'abc', '\x00', ''), | 
 | 377 |             ('2p', 'abc', '\x01a', 'a'), | 
 | 378 |             ('3p', 'abc', '\x02ab', 'ab'), | 
 | 379 |             ('4p', 'abc', '\x03abc', 'abc'), | 
 | 380 |             ('5p', 'abc', '\x03abc\x00', 'abc'), | 
 | 381 |             ('6p', 'abc', '\x03abc\x00\x00', 'abc'), | 
 | 382 |             ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]: | 
 | 383 |         got = struct.pack(code, input) | 
 | 384 |         if got != expected: | 
 | 385 |             raise TestFailed("pack(%r, %r) == %r but expected %r" % | 
 | 386 |                              (code, input, got, expected)) | 
 | 387 |         (got,) = struct.unpack(code, got) | 
 | 388 |         if got != expectedback: | 
 | 389 |             raise TestFailed("unpack(%r, %r) == %r but expected %r" % | 
 | 390 |                              (code, input, got, expectedback)) | 
 | 391 |  | 
 | 392 | test_p_code() | 
| Tim Peters | d50ade6 | 2003-03-20 18:32:13 +0000 | [diff] [blame] | 393 |  | 
 | 394 |  | 
 | 395 | ########################################################################### | 
 | 396 | # SF bug 705836.  "<f" and ">f" had a severe rounding bug, where a carry | 
 | 397 | # from the low-order discarded bits could propagate into the exponent | 
 | 398 | # field, causing the result to be wrong by a factor of 2. | 
 | 399 |  | 
 | 400 | def test_705836(): | 
 | 401 |     import math | 
 | 402 |  | 
 | 403 |     for base in range(1, 33): | 
 | 404 |         # smaller <- largest representable float less than base. | 
 | 405 |         delta = 0.5 | 
 | 406 |         while base - delta / 2.0 != base: | 
 | 407 |             delta /= 2.0 | 
 | 408 |         smaller = base - delta | 
 | 409 |         # Packing this rounds away a solid string of trailing 1 bits. | 
 | 410 |         packed = struct.pack("<f", smaller) | 
 | 411 |         unpacked = struct.unpack("<f", packed)[0] | 
 | 412 |         # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and | 
 | 413 |         # 16, respectively. | 
 | 414 |         verify(base == unpacked) | 
 | 415 |         bigpacked = struct.pack(">f", smaller) | 
 | 416 |         verify(bigpacked == string_reverse(packed), | 
 | 417 |                ">f pack should be byte-reversal of <f pack") | 
 | 418 |         unpacked = struct.unpack(">f", bigpacked)[0] | 
 | 419 |         verify(base == unpacked) | 
 | 420 |  | 
 | 421 |     # Largest finite IEEE single. | 
 | 422 |     big = (1 << 24) - 1 | 
 | 423 |     big = math.ldexp(big, 127 - 23) | 
 | 424 |     packed = struct.pack(">f", big) | 
 | 425 |     unpacked = struct.unpack(">f", packed)[0] | 
 | 426 |     verify(big == unpacked) | 
 | 427 |  | 
 | 428 |     # The same, but tack on a 1 bit so it rounds up to infinity. | 
 | 429 |     big = (1 << 25) - 1 | 
 | 430 |     big = math.ldexp(big, 127 - 24) | 
 | 431 |     try: | 
 | 432 |         packed = struct.pack(">f", big) | 
 | 433 |     except OverflowError: | 
 | 434 |         pass | 
 | 435 |     else: | 
 | 436 |         TestFailed("expected OverflowError") | 
 | 437 |  | 
 | 438 | test_705836() |