blob: 29c555facf94b137f39c7c695c2f790de39a8f2e [file] [log] [blame]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +00001from test.test_support import TestFailed, verbose, verify, vereq
Thomas Wouters477c8d52006-05-27 19:21:47 +00002import test.test_support
Barry Warsaw07a0eec1996-12-12 23:34:06 +00003import struct
Thomas Wouters477c8d52006-05-27 19:21:47 +00004import array
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00005import warnings
Barry Warsaw07a0eec1996-12-12 23:34:06 +00006
Tim Peters17e17d42001-06-13 22:45:27 +00007import sys
8ISBIGENDIAN = sys.byteorder == "big"
9del sys
10verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
11 "bigendian determination appears wrong")
12
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000013try:
14 import _struct
15except ImportError:
16 PY_STRUCT_RANGE_CHECKING = 0
17 PY_STRUCT_OVERFLOW_MASKING = 1
Thomas Wouters0e3f5912006-08-11 14:57:12 +000018 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000019else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
21 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
22 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000023
Tim Peters17e17d42001-06-13 22:45:27 +000024def string_reverse(s):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000025 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000026
27def bigendian_to_native(value):
28 if ISBIGENDIAN:
29 return value
30 else:
31 return string_reverse(value)
32
Barry Warsaw07a0eec1996-12-12 23:34:06 +000033def simple_err(func, *args):
34 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000035 func(*args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000036 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +000037 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000038 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000039 raise TestFailed, "%s%s did not raise struct.error" % (
40 func.__name__, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000041
Tim Peters7a3bfc32001-06-12 01:22:22 +000042def any_err(func, *args):
43 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000044 func(*args)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000045 except (struct.error, TypeError):
Tim Peters7a3bfc32001-06-12 01:22:22 +000046 pass
47 else:
48 raise TestFailed, "%s%s did not raise error" % (
49 func.__name__, args)
Tim Peters7a3bfc32001-06-12 01:22:22 +000050
Thomas Wouters0e3f5912006-08-11 14:57:12 +000051def with_warning_restore(func):
52 def _with_warning_restore(*args, **kw):
Thomas Wouters902d6eb2007-01-09 23:18:33 +000053 with test.test_support.guard_warnings_filter():
54 # Grrr, we need this function to warn every time. Without removing
55 # the warningregistry, running test_tarfile then test_struct would fail
56 # on 64-bit platforms.
Neal Norwitz221085d2007-02-25 20:55:47 +000057 globals = func.__globals__
Thomas Wouters902d6eb2007-01-09 23:18:33 +000058 if '__warningregistry__' in globals:
59 del globals['__warningregistry__']
60 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
61 warnings.filterwarnings("error", r""".*format requires.*""",
62 DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000063 return func(*args, **kw)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000064 return _with_warning_restore
65
66def deprecated_err(func, *args):
67 try:
68 func(*args)
69 except (struct.error, TypeError):
70 pass
71 except DeprecationWarning:
72 if not PY_STRUCT_OVERFLOW_MASKING:
73 raise TestFailed, "%s%s expected to raise struct.error" % (
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000074 func.__name__, args)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000075 else:
76 raise TestFailed, "%s%s did not raise error" % (
77 func.__name__, args)
78deprecated_err = with_warning_restore(deprecated_err)
79
Tim Peters17e17d42001-06-13 22:45:27 +000080
Tim Peters7b9542a2001-06-10 23:40:19 +000081simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000082
83sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000084if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000085 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000086
Thomas Woutersb2137042007-02-01 18:02:27 +000087fmt = 'cbxxxxxxhhhhiillffdt'
88fmt3 = '3c3b18x12h6i6l6f3d3t'
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000089sz = struct.calcsize(fmt)
90sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000091if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000092 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
93 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000094
95simple_err(struct.pack, 'iii', 3)
96simple_err(struct.pack, 'i', 3, 3, 3)
97simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +000098simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000099simple_err(struct.unpack, 'd', 'flap')
100s = struct.pack('ii', 1, 2)
101simple_err(struct.unpack, 'iii', s)
102simple_err(struct.unpack, 'i', s)
103
104c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +0000105b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000106h = 255
107i = 65535
108l = 65536
109f = 3.1415
110d = 3.1415
Thomas Woutersb2137042007-02-01 18:02:27 +0000111t = True
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000112
Guido van Rossum420c11c1997-01-03 00:09:46 +0000113for prefix in ('', '@', '<', '>', '=', '!'):
Thomas Woutersb2137042007-02-01 18:02:27 +0000114 for format in ('xcbhilfdt', 'xcBHILfdt'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000115 format = prefix + format
116 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000117 print("trying:", format)
Thomas Woutersb2137042007-02-01 18:02:27 +0000118 s = struct.pack(format, c, b, h, i, l, f, d, t)
119 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000120 if (cp != c or bp != b or hp != h or ip != i or lp != l or
Thomas Woutersb2137042007-02-01 18:02:27 +0000121 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d) or
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000122 tp != t):
Guido van Rossum41360a41998-03-26 19:42:58 +0000123 # ^^^ calculate only to two decimal places
124 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
Thomas Woutersb2137042007-02-01 18:02:27 +0000125 str(format), str((cp, bp, hp, ip, lp, fp, dp, tp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000126
Guido van Rossum420c11c1997-01-03 00:09:46 +0000127# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000128
129# (format, argument, big-endian result, little-endian result, asymmetric)
130tests = [
131 ('c', 'a', 'a', 'a', 0),
132 ('xc', 'a', '\0a', '\0a', 0),
133 ('cx', 'a', 'a\0', 'a\0', 0),
134 ('s', 'a', 'a', 'a', 0),
135 ('0s', 'helloworld', '', '', 1),
136 ('1s', 'helloworld', 'h', 'h', 1),
137 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
138 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
139 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
140 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
141 ('b', 7, '\7', '\7', 0),
142 ('b', -7, '\371', '\371', 0),
143 ('B', 7, '\7', '\7', 0),
144 ('B', 249, '\371', '\371', 0),
145 ('h', 700, '\002\274', '\274\002', 0),
146 ('h', -700, '\375D', 'D\375', 0),
147 ('H', 700, '\002\274', '\274\002', 0),
148 ('H', 0x10000-700, '\375D', 'D\375', 0),
149 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
150 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossume2a383d2007-01-15 16:59:06 +0000151 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
152 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000153 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
154 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossume2a383d2007-01-15 16:59:06 +0000155 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
156 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000157 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
158 ('d', 2.0, '@\000\000\000\000\000\000\000',
159 '\000\000\000\000\000\000\000@', 0),
160 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
161 ('d', -2.0, '\300\000\000\000\000\000\000\000',
162 '\000\000\000\000\000\000\000\300', 0),
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000163 ('t', 0, '\0', '\0', 0),
164 ('t', 3, '\1', '\1', 1),
165 ('t', True, '\1', '\1', 0),
166 ('t', [], '\0', '\0', 1),
167 ('t', (1,), '\1', '\1', 1),
Guido van Rossum2a378501996-12-31 17:25:47 +0000168]
169
Guido van Rossum2a378501996-12-31 17:25:47 +0000170for fmt, arg, big, lil, asy in tests:
171 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000172 print("%r %r %r %r" % (fmt, arg, big, lil))
Guido van Rossum2a378501996-12-31 17:25:47 +0000173 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000174 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000175 res = struct.pack(xfmt, arg)
176 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000177 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
178 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000179 n = struct.calcsize(xfmt)
180 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000181 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
182 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000183 rev = struct.unpack(xfmt, res)[0]
184 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000185 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
186 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000187
Tim Peters7a3bfc32001-06-12 01:22:22 +0000188###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000189# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000190
191has_native_qQ = 1
192try:
193 struct.pack("q", 5)
194except struct.error:
195 has_native_qQ = 0
196
197if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000198 print("Platform has native q/Q?", has_native_qQ and "Yes." or "No.")
Tim Peters7b9542a2001-06-10 23:40:19 +0000199
Tim Peters7a3bfc32001-06-12 01:22:22 +0000200any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000201simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
202simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
203
Tim Peters7a3bfc32001-06-12 01:22:22 +0000204def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000205 bytes = struct.calcsize('q')
206 # The expected values here are in big-endian format, primarily because
207 # I'm on a little-endian machine and so this is the clearest way (for
208 # me) to force the code to get exercised.
209 for format, input, expected in (
210 ('q', -1, '\xff' * bytes),
211 ('q', 0, '\x00' * bytes),
212 ('Q', 0, '\x00' * bytes),
Guido van Rossume2a383d2007-01-15 16:59:06 +0000213 ('q', 1, '\x00' * (bytes-1) + '\x01'),
214 ('Q', (1 << (8*bytes))-1, '\xff' * bytes),
215 ('q', (1 << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
Tim Peters7b9542a2001-06-10 23:40:19 +0000216 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000217 native_expected = bigendian_to_native(expected)
218 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000219 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000220 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000221 retrieved = struct.unpack(format, got)[0]
222 verify(retrieved == input,
223 "%r-unpack of %r gave %r, not %r" %
224 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000225
226if has_native_qQ:
227 test_native_qQ()
228
Tim Peters17e17d42001-06-13 22:45:27 +0000229###########################################################################
230# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000231
232import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000233
Tim Peters17e17d42001-06-13 22:45:27 +0000234class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000235
Tim Peters17e17d42001-06-13 22:45:27 +0000236 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000237 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
238 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
239 # reported by Mark Favas).
240 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000241
Tim Peters17e17d42001-06-13 22:45:27 +0000242 def __init__(self, formatpair, bytesize):
243 assert len(formatpair) == 2
244 self.formatpair = formatpair
245 for direction in "<>!=":
246 for code in formatpair:
247 format = direction + code
248 verify(struct.calcsize(format) == bytesize)
249 self.bytesize = bytesize
250 self.bitsize = bytesize * 8
251 self.signed_code, self.unsigned_code = formatpair
252 self.unsigned_min = 0
Guido van Rossume2a383d2007-01-15 16:59:06 +0000253 self.unsigned_max = 2**self.bitsize - 1
254 self.signed_min = -(2**(self.bitsize-1))
255 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000256
Tim Peters17e17d42001-06-13 22:45:27 +0000257 def test_one(self, x, pack=struct.pack,
258 unpack=struct.unpack,
259 unhexlify=binascii.unhexlify):
260 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000261 print("trying std", self.formatpair, "on", x, "==", hex(x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000262
Tim Peters17e17d42001-06-13 22:45:27 +0000263 # Try signed.
264 code = self.signed_code
265 if self.signed_min <= x <= self.signed_max:
266 # Try big-endian.
Guido van Rossume2a383d2007-01-15 16:59:06 +0000267 expected = int(x)
Tim Peters17e17d42001-06-13 22:45:27 +0000268 if x < 0:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000269 expected += 1 << self.bitsize
Tim Peters17e17d42001-06-13 22:45:27 +0000270 assert expected > 0
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000271 expected = hex(expected)[2:] # chop "0x"
Tim Peters17e17d42001-06-13 22:45:27 +0000272 if len(expected) & 1:
273 expected = "0" + expected
274 expected = unhexlify(expected)
275 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000276
Tim Peters17e17d42001-06-13 22:45:27 +0000277 # Pack work?
278 format = ">" + code
279 got = pack(format, x)
280 verify(got == expected,
281 "'%s'-pack of %r gave %r, not %r" %
282 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000283
Tim Peters17e17d42001-06-13 22:45:27 +0000284 # Unpack work?
285 retrieved = unpack(format, got)[0]
286 verify(x == retrieved,
287 "'%s'-unpack of %r gave %r, not %r" %
288 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000289
Tim Peters17e17d42001-06-13 22:45:27 +0000290 # Adding any byte should cause a "too big" error.
291 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000292
Tim Peters17e17d42001-06-13 22:45:27 +0000293 # Try little-endian.
294 format = "<" + code
295 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000296
Tim Peters17e17d42001-06-13 22:45:27 +0000297 # Pack work?
298 got = pack(format, x)
299 verify(got == expected,
300 "'%s'-pack of %r gave %r, not %r" %
301 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000302
Tim Peters17e17d42001-06-13 22:45:27 +0000303 # Unpack work?
304 retrieved = unpack(format, got)[0]
305 verify(x == retrieved,
306 "'%s'-unpack of %r gave %r, not %r" %
307 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000308
Tim Peters17e17d42001-06-13 22:45:27 +0000309 # Adding any byte should cause a "too big" error.
310 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000311
Tim Peters17e17d42001-06-13 22:45:27 +0000312 else:
313 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000314 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000315 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000316 print("Skipping buggy range check for code", code)
Tim Peters17e17d42001-06-13 22:45:27 +0000317 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000318 deprecated_err(pack, ">" + code, x)
319 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000320
Tim Peters17e17d42001-06-13 22:45:27 +0000321 # Much the same for unsigned.
322 code = self.unsigned_code
323 if self.unsigned_min <= x <= self.unsigned_max:
324 # Try big-endian.
325 format = ">" + code
Guido van Rossume2a383d2007-01-15 16:59:06 +0000326 expected = int(x)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000327 expected = hex(expected)[2:] # chop "0x"
Tim Peters17e17d42001-06-13 22:45:27 +0000328 if len(expected) & 1:
329 expected = "0" + expected
330 expected = unhexlify(expected)
331 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000332
Tim Peters17e17d42001-06-13 22:45:27 +0000333 # Pack work?
334 got = pack(format, x)
335 verify(got == expected,
336 "'%s'-pack of %r gave %r, not %r" %
337 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000338
Tim Peters17e17d42001-06-13 22:45:27 +0000339 # Unpack work?
340 retrieved = unpack(format, got)[0]
341 verify(x == retrieved,
342 "'%s'-unpack of %r gave %r, not %r" %
343 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000344
Tim Peters17e17d42001-06-13 22:45:27 +0000345 # Adding any byte should cause a "too big" error.
346 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000347
Tim Peters17e17d42001-06-13 22:45:27 +0000348 # Try little-endian.
349 format = "<" + code
350 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000351
Tim Peters17e17d42001-06-13 22:45:27 +0000352 # Pack work?
353 got = pack(format, x)
354 verify(got == expected,
355 "'%s'-pack of %r gave %r, not %r" %
356 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000357
Tim Peters17e17d42001-06-13 22:45:27 +0000358 # Unpack work?
359 retrieved = unpack(format, got)[0]
360 verify(x == retrieved,
361 "'%s'-unpack of %r gave %r, not %r" %
362 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000363
Tim Peters17e17d42001-06-13 22:45:27 +0000364 # Adding any byte should cause a "too big" error.
365 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000366
Tim Peters17e17d42001-06-13 22:45:27 +0000367 else:
368 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000369 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000370 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000371 print("Skipping buggy range check for code", code)
Tim Peters17e17d42001-06-13 22:45:27 +0000372 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000373 deprecated_err(pack, ">" + code, x)
374 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000375
Tim Peters17e17d42001-06-13 22:45:27 +0000376 def run(self):
377 from random import randrange
378
379 # Create all interesting powers of 2.
380 values = []
381 for exp in range(self.bitsize + 3):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000382 values.append(1 << exp)
Tim Peters17e17d42001-06-13 22:45:27 +0000383
384 # Add some random values.
385 for i in range(self.bitsize):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000386 val = 0
Tim Peters17e17d42001-06-13 22:45:27 +0000387 for j in range(self.bytesize):
388 val = (val << 8) | randrange(256)
389 values.append(val)
390
391 # Try all those, and their negations, and +-1 from them. Note
392 # that this tests all power-of-2 boundaries in range, and a few out
393 # of range, plus +-(2**n +- 1).
394 for base in values:
395 for val in -base, base:
396 for incr in -1, 0, 1:
397 x = val + incr
398 try:
399 x = int(x)
400 except OverflowError:
401 pass
402 self.test_one(x)
403
404 # Some error cases.
405 for direction in "<>":
406 for code in self.formatpair:
407 for badobject in "a string", 3+42j, randrange:
408 any_err(struct.pack, direction + code, badobject)
409
410for args in [("bB", 1),
411 ("hH", 2),
412 ("iI", 4),
413 ("lL", 4),
414 ("qQ", 8)]:
415 t = IntTester(*args)
416 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000417
418
419###########################################################################
420# The p ("Pascal string") code.
421
422def test_p_code():
423 for code, input, expected, expectedback in [
424 ('p','abc', '\x00', ''),
425 ('1p', 'abc', '\x00', ''),
426 ('2p', 'abc', '\x01a', 'a'),
427 ('3p', 'abc', '\x02ab', 'ab'),
428 ('4p', 'abc', '\x03abc', 'abc'),
429 ('5p', 'abc', '\x03abc\x00', 'abc'),
430 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
431 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
432 got = struct.pack(code, input)
433 if got != expected:
434 raise TestFailed("pack(%r, %r) == %r but expected %r" %
435 (code, input, got, expected))
436 (got,) = struct.unpack(code, got)
437 if got != expectedback:
438 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
439 (code, input, got, expectedback))
440
441test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000442
443
444###########################################################################
445# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
446# from the low-order discarded bits could propagate into the exponent
447# field, causing the result to be wrong by a factor of 2.
448
449def test_705836():
450 import math
451
452 for base in range(1, 33):
453 # smaller <- largest representable float less than base.
454 delta = 0.5
455 while base - delta / 2.0 != base:
456 delta /= 2.0
457 smaller = base - delta
458 # Packing this rounds away a solid string of trailing 1 bits.
459 packed = struct.pack("<f", smaller)
460 unpacked = struct.unpack("<f", packed)[0]
461 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
462 # 16, respectively.
463 verify(base == unpacked)
464 bigpacked = struct.pack(">f", smaller)
465 verify(bigpacked == string_reverse(packed),
466 ">f pack should be byte-reversal of <f pack")
467 unpacked = struct.unpack(">f", bigpacked)[0]
468 verify(base == unpacked)
469
470 # Largest finite IEEE single.
471 big = (1 << 24) - 1
472 big = math.ldexp(big, 127 - 23)
473 packed = struct.pack(">f", big)
474 unpacked = struct.unpack(">f", packed)[0]
475 verify(big == unpacked)
476
477 # The same, but tack on a 1 bit so it rounds up to infinity.
478 big = (1 << 25) - 1
479 big = math.ldexp(big, 127 - 24)
480 try:
481 packed = struct.pack(">f", big)
482 except OverflowError:
483 pass
484 else:
485 TestFailed("expected OverflowError")
486
487test_705836()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000488
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000489###########################################################################
490# SF bug 1229380. No struct.pack exception for some out of range integers
491
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492def test_1229380():
493 import sys
494 for endian in ('', '>', '<'):
Walter Dörwaldaa97f042007-05-03 21:05:51 +0000495 for fmt in ('B', 'H', 'I', 'L'):
496 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000497
Walter Dörwaldaa97f042007-05-03 21:05:51 +0000498 deprecated_err(struct.pack, endian + 'B', 300)
499 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500
Guido van Rossume2a383d2007-01-15 16:59:06 +0000501 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4)
502 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000503
504if PY_STRUCT_RANGE_CHECKING:
505 test_1229380()
506
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000507###########################################################################
508# SF bug 1530559. struct.pack raises TypeError where it used to convert.
509
510def check_float_coerce(format, number):
511 if PY_STRUCT_FLOAT_COERCE == 2:
512 # Test for pre-2.5 struct module
513 packed = struct.pack(format, number)
514 floored = struct.unpack(format, packed)[0]
515 if floored != int(number):
516 raise TestFailed("did not correcly coerce float to int")
517 return
518 try:
519 func(*args)
520 except (struct.error, TypeError):
521 if PY_STRUCT_FLOAT_COERCE:
522 raise TestFailed("expected DeprecationWarning for float coerce")
523 except DeprecationWarning:
524 if not PY_STRUCT_FLOAT_COERCE:
525 raise TestFailed("expected to raise struct.error for float coerce")
526 else:
527 raise TestFailed("did not raise error for float coerce")
528
529check_float_coerce = with_warning_restore(deprecated_err)
530
531def test_1530559():
532 for endian in ('', '>', '<'):
533 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
534 check_float_coerce(endian + fmt, 1.0)
535 check_float_coerce(endian + fmt, 1.5)
536
537test_1530559()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000538
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000539###########################################################################
540# Packing and unpacking to/from buffers.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000541
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000542# Copied and modified from unittest.
543def assertRaises(excClass, callableObj, *args, **kwargs):
544 try:
545 callableObj(*args, **kwargs)
546 except excClass:
547 return
548 else:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000549 raise TestFailed("%s not raised." % excClass)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000550
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000551def test_unpack_from():
552 test_string = 'abcd01234'
553 fmt = '4s'
554 s = struct.Struct(fmt)
555 for cls in (str, buffer):
556 data = cls(test_string)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000557 vereq(s.unpack_from(data), ('abcd',))
558 vereq(s.unpack_from(data, 2), ('cd01',))
559 vereq(s.unpack_from(data, 4), ('0123',))
Guido van Rossum805365e2007-05-07 22:24:25 +0000560 for i in range(6):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000561 vereq(s.unpack_from(data, i), (data[i:i+4],))
Guido van Rossum805365e2007-05-07 22:24:25 +0000562 for i in range(6, len(test_string) + 1):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000563 simple_err(s.unpack_from, data, i)
564 for cls in (str, buffer):
565 data = cls(test_string)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000566 vereq(struct.unpack_from(fmt, data), ('abcd',))
567 vereq(struct.unpack_from(fmt, data, 2), ('cd01',))
568 vereq(struct.unpack_from(fmt, data, 4), ('0123',))
Guido van Rossum805365e2007-05-07 22:24:25 +0000569 for i in range(6):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000570 vereq(struct.unpack_from(fmt, data, i), (data[i:i+4],))
Guido van Rossum805365e2007-05-07 22:24:25 +0000571 for i in range(6, len(test_string) + 1):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000572 simple_err(struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000573
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000574def test_pack_into():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000575 test_string = 'Reykjavik rocks, eow!'
576 writable_buf = array.array('c', ' '*100)
577 fmt = '21s'
578 s = struct.Struct(fmt)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000579
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000580 # Test without offset
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000581 s.pack_into(writable_buf, 0, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000582 from_buf = writable_buf.tostring()[:len(test_string)]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000583 vereq(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000584
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000585 # Test with offset.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000586 s.pack_into(writable_buf, 10, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000587 from_buf = writable_buf.tostring()[:len(test_string)+10]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000588 vereq(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000589
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000590 # Go beyond boundaries.
591 small_buf = array.array('c', ' '*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000592 assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
593 assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000594
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000595def test_pack_into_fn():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000596 test_string = 'Reykjavik rocks, eow!'
597 writable_buf = array.array('c', ' '*100)
598 fmt = '21s'
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000599 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000600
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000601 # Test without offset.
602 pack_into(writable_buf, 0, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000603 from_buf = writable_buf.tostring()[:len(test_string)]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000604 vereq(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000605
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000606 # Test with offset.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000607 pack_into(writable_buf, 10, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000608 from_buf = writable_buf.tostring()[:len(test_string)+10]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000609 vereq(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000610
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000611 # Go beyond boundaries.
612 small_buf = array.array('c', ' '*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000613 assertRaises(struct.error, pack_into, small_buf, 0, test_string)
614 assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000615
Guido van Rossumd8faa362007-04-27 19:54:29 +0000616def test_unpack_with_buffer():
617 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
618 data1 = array.array('B', '\x12\x34\x56\x78')
619 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
620 for data in [data1, data2]:
621 value, = struct.unpack('>I', data)
622 vereq(value, 0x12345678)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000623
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000624# Test methods to pack and unpack from buffers rather than strings.
625test_unpack_from()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000626test_pack_into()
627test_pack_into_fn()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000628test_unpack_with_buffer()
Thomas Woutersb2137042007-02-01 18:02:27 +0000629
630def test_bool():
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000631 for prefix in tuple("<>!=")+('',):
632 false = (), [], [], '', 0
633 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Guido van Rossumd8faa362007-04-27 19:54:29 +0000634
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000635 falseFormat = prefix + 't' * len(false)
636 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000637 print('trying bool pack/unpack on', false, 'using format', falseFormat)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000638 packedFalse = struct.pack(falseFormat, *false)
639 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000640
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000641 trueFormat = prefix + 't' * len(true)
642 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000643 print('trying bool pack/unpack on', true, 'using format', trueFormat)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000644 packedTrue = struct.pack(trueFormat, *true)
645 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000646
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000647 if len(true) != len(unpackedTrue):
648 raise TestFailed('unpacked true array is not of same size as input')
649 if len(false) != len(unpackedFalse):
650 raise TestFailed('unpacked false array is not of same size as input')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000651
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000652 for t in unpackedFalse:
653 if t is not False:
654 raise TestFailed('%r did not unpack as False' % t)
655 for t in unpackedTrue:
656 if t is not True:
657 raise TestFailed('%r did not unpack as false' % t)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000658
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000659 if prefix and verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000660 print('trying size of bool with format %r' % (prefix+'t'))
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000661 packed = struct.pack(prefix+'t', 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000662
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000663 if len(packed) != struct.calcsize(prefix+'t'):
664 raise TestFailed('packed length is not equal to calculated size')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000665
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000666 if len(packed) != 1 and prefix:
667 raise TestFailed('encoded bool is not one byte: %r' % packed)
668 elif not prefix and verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000669 print('size of bool in native format is %i' % (len(packed)))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000670
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000671 for c in '\x01\x7f\xff\x0f\xf0':
672 if struct.unpack('>t', c)[0] is not True:
673 raise TestFailed('%c did not unpack as True' % c)
Thomas Woutersb2137042007-02-01 18:02:27 +0000674
675test_bool()