blob: 0641d9ba45ed4b79126de366a196bf5a2219ccaf [file] [log] [blame]
Barry Warsaw04f357c2002-07-23 19:04:11 +00001from test.test_support import TestFailed, verbose, verify
Barry Warsaw07a0eec1996-12-12 23:34:06 +00002import struct
Barry Warsaw07a0eec1996-12-12 23:34:06 +00003
Tim Peters17e17d42001-06-13 22:45:27 +00004import sys
5ISBIGENDIAN = sys.byteorder == "big"
6del sys
7verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
8 "bigendian determination appears wrong")
9
10def string_reverse(s):
11 chars = list(s)
12 chars.reverse()
13 return "".join(chars)
14
15def bigendian_to_native(value):
16 if ISBIGENDIAN:
17 return value
18 else:
19 return string_reverse(value)
20
Barry Warsaw07a0eec1996-12-12 23:34:06 +000021def simple_err(func, *args):
22 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000023 func(*args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000024 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +000025 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000026 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000027 raise TestFailed, "%s%s did not raise struct.error" % (
28 func.__name__, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000029
Tim Peters7a3bfc32001-06-12 01:22:22 +000030def any_err(func, *args):
31 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000032 func(*args)
Tim Peters7a3bfc32001-06-12 01:22:22 +000033 except (struct.error, OverflowError, TypeError):
34 pass
35 else:
36 raise TestFailed, "%s%s did not raise error" % (
37 func.__name__, args)
Tim Peters7a3bfc32001-06-12 01:22:22 +000038
Tim Peters17e17d42001-06-13 22:45:27 +000039
Tim Peters7b9542a2001-06-10 23:40:19 +000040simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000041
42sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000043if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000044 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000045
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000046fmt = 'cbxxxxxxhhhhiillffd'
47fmt3 = '3c3b18x12h6i6l6f3d'
48sz = struct.calcsize(fmt)
49sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000050if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000051 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
52 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000053
54simple_err(struct.pack, 'iii', 3)
55simple_err(struct.pack, 'i', 3, 3, 3)
56simple_err(struct.pack, 'i', 'foo')
57simple_err(struct.unpack, 'd', 'flap')
58s = struct.pack('ii', 1, 2)
59simple_err(struct.unpack, 'iii', s)
60simple_err(struct.unpack, 'i', s)
61
62c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +000063b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +000064h = 255
65i = 65535
66l = 65536
67f = 3.1415
68d = 3.1415
69
Guido van Rossum420c11c1997-01-03 00:09:46 +000070for prefix in ('', '@', '<', '>', '=', '!'):
71 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +000072 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 Drake132dce22000-12-12 23:11:42 +000077 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 Rossum41360a41998-03-26 19:42:58 +000079 # ^^^ 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 Rossum2a378501996-12-31 17:25:47 +000082
Guido van Rossum420c11c1997-01-03 00:09:46 +000083# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +000084
85# (format, argument, big-endian result, little-endian result, asymmetric)
86tests = [
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 Rossum420c11c1997-01-03 00:09:46 +0000113 ('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 Rossum2a378501996-12-31 17:25:47 +0000119]
120
Guido van Rossum2a378501996-12-31 17:25:47 +0000121for fmt, arg, big, lil, asy in tests:
122 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000123 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000124 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000125 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000126 res = struct.pack(xfmt, arg)
127 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000128 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
129 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000130 n = struct.calcsize(xfmt)
131 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000132 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
133 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000134 rev = struct.unpack(xfmt, res)[0]
135 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000136 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
137 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000138
Tim Peters7a3bfc32001-06-12 01:22:22 +0000139###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000140# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000141
142has_native_qQ = 1
143try:
144 struct.pack("q", 5)
145except struct.error:
146 has_native_qQ = 0
147
148if verbose:
149 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
150
Tim Peters7a3bfc32001-06-12 01:22:22 +0000151any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000152simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
153simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
154
Tim Peters7a3bfc32001-06-12 01:22:22 +0000155def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000156 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 Petersc533edc2001-06-10 23:52:59 +0000168 native_expected = bigendian_to_native(expected)
169 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000170 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000171 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000172 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 Peters7a3bfc32001-06-12 01:22:22 +0000176
177if has_native_qQ:
178 test_native_qQ()
179
Tim Peters17e17d42001-06-13 22:45:27 +0000180###########################################################################
181# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000182
183import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000184
Tim Peters17e17d42001-06-13 22:45:27 +0000185class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000186
Tim Peters17e17d42001-06-13 22:45:27 +0000187 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000188 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000192
Tim Peters17e17d42001-06-13 22:45:27 +0000193 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 Peters7a3bfc32001-06-12 01:22:22 +0000207
Tim Peters17e17d42001-06-13 22:45:27 +0000208 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 Peters7a3bfc32001-06-12 01:22:22 +0000213
Tim Peters17e17d42001-06-13 22:45:27 +0000214 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000227
Tim Peters17e17d42001-06-13 22:45:27 +0000228 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000234
Tim Peters17e17d42001-06-13 22:45:27 +0000235 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000240
Tim Peters17e17d42001-06-13 22:45:27 +0000241 # Adding any byte should cause a "too big" error.
242 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000243
Tim Peters17e17d42001-06-13 22:45:27 +0000244 # Try little-endian.
245 format = "<" + code
246 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000247
Tim Peters17e17d42001-06-13 22:45:27 +0000248 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000253
Tim Peters17e17d42001-06-13 22:45:27 +0000254 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000259
Tim Peters17e17d42001-06-13 22:45:27 +0000260 # Adding any byte should cause a "too big" error.
261 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000262
Tim Peters17e17d42001-06-13 22:45:27 +0000263 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 Peters7a3bfc32001-06-12 01:22:22 +0000271
Tim Peters17e17d42001-06-13 22:45:27 +0000272 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000283
Tim Peters17e17d42001-06-13 22:45:27 +0000284 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000289
Tim Peters17e17d42001-06-13 22:45:27 +0000290 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000295
Tim Peters17e17d42001-06-13 22:45:27 +0000296 # Adding any byte should cause a "too big" error.
297 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000298
Tim Peters17e17d42001-06-13 22:45:27 +0000299 # Try little-endian.
300 format = "<" + code
301 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000302
Tim Peters17e17d42001-06-13 22:45:27 +0000303 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000308
Tim Peters17e17d42001-06-13 22:45:27 +0000309 # 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 Peters7a3bfc32001-06-12 01:22:22 +0000314
Tim Peters17e17d42001-06-13 22:45:27 +0000315 # Adding any byte should cause a "too big" error.
316 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000317
Tim Peters17e17d42001-06-13 22:45:27 +0000318 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 Peters7a3bfc32001-06-12 01:22:22 +0000326
Tim Peters17e17d42001-06-13 22:45:27 +0000327 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
361for args in [("bB", 1),
362 ("hH", 2),
363 ("iI", 4),
364 ("lL", 4),
365 ("qQ", 8)]:
366 t = IntTester(*args)
367 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000368
369
370###########################################################################
371# The p ("Pascal string") code.
372
373def 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
392test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000393
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
400def 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
438test_705836()