blob: 34abad55ea267cfb485903abef5cce0319a3c074 [file] [log] [blame]
Tim Peters7b9542a2001-06-10 23:40:19 +00001from test_support import TestFailed, verbose, verify
Barry Warsaw07a0eec1996-12-12 23:34:06 +00002import struct
3## import pdb
4
Tim Peters17e17d42001-06-13 22:45:27 +00005import sys
6ISBIGENDIAN = sys.byteorder == "big"
7del sys
8verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
9 "bigendian determination appears wrong")
10
11def string_reverse(s):
12 chars = list(s)
13 chars.reverse()
14 return "".join(chars)
15
16def bigendian_to_native(value):
17 if ISBIGENDIAN:
18 return value
19 else:
20 return string_reverse(value)
21
Barry Warsaw07a0eec1996-12-12 23:34:06 +000022def simple_err(func, *args):
23 try:
Guido van Rossum41360a41998-03-26 19:42:58 +000024 apply(func, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000025 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +000026 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000027 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000028 raise TestFailed, "%s%s did not raise struct.error" % (
29 func.__name__, args)
30## pdb.set_trace()
Barry Warsaw07a0eec1996-12-12 23:34:06 +000031
Tim Peters7a3bfc32001-06-12 01:22:22 +000032def any_err(func, *args):
33 try:
34 apply(func, args)
35 except (struct.error, OverflowError, TypeError):
36 pass
37 else:
38 raise TestFailed, "%s%s did not raise error" % (
39 func.__name__, args)
40## pdb.set_trace()
41
Tim Peters17e17d42001-06-13 22:45:27 +000042
Tim Peters7b9542a2001-06-10 23:40:19 +000043simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000044
45sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000046if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000047 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000048
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000049fmt = 'cbxxxxxxhhhhiillffd'
50fmt3 = '3c3b18x12h6i6l6f3d'
51sz = struct.calcsize(fmt)
52sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000053if sz * 3 != sz3:
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000054 raise TestFailed, 'inconsistent sizes (3*%s -> 3*%d = %d, %s -> %d)' % (
Guido van Rossum41360a41998-03-26 19:42:58 +000055 `fmt`, sz, 3*sz, `fmt3`, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000056
57simple_err(struct.pack, 'iii', 3)
58simple_err(struct.pack, 'i', 3, 3, 3)
59simple_err(struct.pack, 'i', 'foo')
60simple_err(struct.unpack, 'd', 'flap')
61s = struct.pack('ii', 1, 2)
62simple_err(struct.unpack, 'iii', s)
63simple_err(struct.unpack, 'i', s)
64
65c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +000066b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +000067h = 255
68i = 65535
69l = 65536
70f = 3.1415
71d = 3.1415
72
Guido van Rossum420c11c1997-01-03 00:09:46 +000073for prefix in ('', '@', '<', '>', '=', '!'):
74 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +000075 format = prefix + format
76 if verbose:
77 print "trying:", format
78 s = struct.pack(format, c, b, h, i, l, f, d)
79 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +000080 if (cp != c or bp != b or hp != h or ip != i or lp != l or
81 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +000082 # ^^^ calculate only to two decimal places
83 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
84 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +000085
Guido van Rossum420c11c1997-01-03 00:09:46 +000086# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +000087
88# (format, argument, big-endian result, little-endian result, asymmetric)
89tests = [
90 ('c', 'a', 'a', 'a', 0),
91 ('xc', 'a', '\0a', '\0a', 0),
92 ('cx', 'a', 'a\0', 'a\0', 0),
93 ('s', 'a', 'a', 'a', 0),
94 ('0s', 'helloworld', '', '', 1),
95 ('1s', 'helloworld', 'h', 'h', 1),
96 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
97 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
98 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
99 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
100 ('b', 7, '\7', '\7', 0),
101 ('b', -7, '\371', '\371', 0),
102 ('B', 7, '\7', '\7', 0),
103 ('B', 249, '\371', '\371', 0),
104 ('h', 700, '\002\274', '\274\002', 0),
105 ('h', -700, '\375D', 'D\375', 0),
106 ('H', 700, '\002\274', '\274\002', 0),
107 ('H', 0x10000-700, '\375D', 'D\375', 0),
108 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
109 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
110 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
111 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
112 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
113 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
114 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
115 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000116 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
117 ('d', 2.0, '@\000\000\000\000\000\000\000',
118 '\000\000\000\000\000\000\000@', 0),
119 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
120 ('d', -2.0, '\300\000\000\000\000\000\000\000',
121 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000122]
123
Guido van Rossum2a378501996-12-31 17:25:47 +0000124for fmt, arg, big, lil, asy in tests:
125 if verbose:
Guido van Rossum41360a41998-03-26 19:42:58 +0000126 print `fmt`, `arg`, `big`, `lil`
Guido van Rossum2a378501996-12-31 17:25:47 +0000127 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000128 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000129 res = struct.pack(xfmt, arg)
130 if res != exp:
131 raise TestFailed, "pack(%s, %s) -> %s # expected %s" % (
132 `fmt`, `arg`, `res`, `exp`)
133 n = struct.calcsize(xfmt)
134 if n != len(res):
135 raise TestFailed, "calcsize(%s) -> %d # expected %d" % (
136 `xfmt`, n, len(res))
137 rev = struct.unpack(xfmt, res)[0]
138 if rev != arg and not asy:
139 raise TestFailed, "unpack(%s, %s) -> (%s,) # expected (%s,)" % (
140 `fmt`, `res`, `rev`, `arg`)
Tim Peters7b9542a2001-06-10 23:40:19 +0000141
Tim Peters7a3bfc32001-06-12 01:22:22 +0000142###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000143# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000144
145has_native_qQ = 1
146try:
147 struct.pack("q", 5)
148except struct.error:
149 has_native_qQ = 0
150
151if verbose:
152 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
153
Tim Peters7a3bfc32001-06-12 01:22:22 +0000154any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000155simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
156simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
157
Tim Peters7a3bfc32001-06-12 01:22:22 +0000158def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000159 bytes = struct.calcsize('q')
160 # The expected values here are in big-endian format, primarily because
161 # I'm on a little-endian machine and so this is the clearest way (for
162 # me) to force the code to get exercised.
163 for format, input, expected in (
164 ('q', -1, '\xff' * bytes),
165 ('q', 0, '\x00' * bytes),
166 ('Q', 0, '\x00' * bytes),
167 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
168 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
169 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
170 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000171 native_expected = bigendian_to_native(expected)
172 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000173 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000174 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000175 retrieved = struct.unpack(format, got)[0]
176 verify(retrieved == input,
177 "%r-unpack of %r gave %r, not %r" %
178 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000179
180if has_native_qQ:
181 test_native_qQ()
182
Tim Peters17e17d42001-06-13 22:45:27 +0000183###########################################################################
184# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000185
186import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000187
Tim Peters17e17d42001-06-13 22:45:27 +0000188class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000189
Tim Peters17e17d42001-06-13 22:45:27 +0000190 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000191 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
192 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
193 # reported by Mark Favas).
194 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000195
Tim Peters17e17d42001-06-13 22:45:27 +0000196 def __init__(self, formatpair, bytesize):
197 assert len(formatpair) == 2
198 self.formatpair = formatpair
199 for direction in "<>!=":
200 for code in formatpair:
201 format = direction + code
202 verify(struct.calcsize(format) == bytesize)
203 self.bytesize = bytesize
204 self.bitsize = bytesize * 8
205 self.signed_code, self.unsigned_code = formatpair
206 self.unsigned_min = 0
207 self.unsigned_max = 2L**self.bitsize - 1
208 self.signed_min = -(2L**(self.bitsize-1))
209 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000210
Tim Peters17e17d42001-06-13 22:45:27 +0000211 def test_one(self, x, pack=struct.pack,
212 unpack=struct.unpack,
213 unhexlify=binascii.unhexlify):
214 if verbose:
215 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000216
Tim Peters17e17d42001-06-13 22:45:27 +0000217 # Try signed.
218 code = self.signed_code
219 if self.signed_min <= x <= self.signed_max:
220 # Try big-endian.
221 expected = long(x)
222 if x < 0:
223 expected += 1L << self.bitsize
224 assert expected > 0
225 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
226 if len(expected) & 1:
227 expected = "0" + expected
228 expected = unhexlify(expected)
229 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000230
Tim Peters17e17d42001-06-13 22:45:27 +0000231 # Pack work?
232 format = ">" + code
233 got = pack(format, x)
234 verify(got == expected,
235 "'%s'-pack of %r gave %r, not %r" %
236 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000237
Tim Peters17e17d42001-06-13 22:45:27 +0000238 # Unpack work?
239 retrieved = unpack(format, got)[0]
240 verify(x == retrieved,
241 "'%s'-unpack of %r gave %r, not %r" %
242 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000243
Tim Peters17e17d42001-06-13 22:45:27 +0000244 # Adding any byte should cause a "too big" error.
245 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000246
Tim Peters17e17d42001-06-13 22:45:27 +0000247 # Try little-endian.
248 format = "<" + code
249 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000250
Tim Peters17e17d42001-06-13 22:45:27 +0000251 # Pack work?
252 got = pack(format, x)
253 verify(got == expected,
254 "'%s'-pack of %r gave %r, not %r" %
255 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000256
Tim Peters17e17d42001-06-13 22:45:27 +0000257 # Unpack work?
258 retrieved = unpack(format, got)[0]
259 verify(x == retrieved,
260 "'%s'-unpack of %r gave %r, not %r" %
261 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000262
Tim Peters17e17d42001-06-13 22:45:27 +0000263 # Adding any byte should cause a "too big" error.
264 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000265
Tim Peters17e17d42001-06-13 22:45:27 +0000266 else:
267 # x is out of range -- verify pack realizes that.
268 if code in self.BUGGY_RANGE_CHECK:
269 if verbose:
270 print "Skipping buggy range check for code", code
271 else:
272 any_err(pack, ">" + code, x)
273 any_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000274
Tim Peters17e17d42001-06-13 22:45:27 +0000275 # Much the same for unsigned.
276 code = self.unsigned_code
277 if self.unsigned_min <= x <= self.unsigned_max:
278 # Try big-endian.
279 format = ">" + code
280 expected = long(x)
281 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
282 if len(expected) & 1:
283 expected = "0" + expected
284 expected = unhexlify(expected)
285 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000286
Tim Peters17e17d42001-06-13 22:45:27 +0000287 # Pack work?
288 got = pack(format, x)
289 verify(got == expected,
290 "'%s'-pack of %r gave %r, not %r" %
291 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000292
Tim Peters17e17d42001-06-13 22:45:27 +0000293 # Unpack work?
294 retrieved = unpack(format, got)[0]
295 verify(x == retrieved,
296 "'%s'-unpack of %r gave %r, not %r" %
297 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000298
Tim Peters17e17d42001-06-13 22:45:27 +0000299 # Adding any byte should cause a "too big" error.
300 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000301
Tim Peters17e17d42001-06-13 22:45:27 +0000302 # Try little-endian.
303 format = "<" + code
304 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000305
Tim Peters17e17d42001-06-13 22:45:27 +0000306 # Pack work?
307 got = pack(format, x)
308 verify(got == expected,
309 "'%s'-pack of %r gave %r, not %r" %
310 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000311
Tim Peters17e17d42001-06-13 22:45:27 +0000312 # Unpack work?
313 retrieved = unpack(format, got)[0]
314 verify(x == retrieved,
315 "'%s'-unpack of %r gave %r, not %r" %
316 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000317
Tim Peters17e17d42001-06-13 22:45:27 +0000318 # Adding any byte should cause a "too big" error.
319 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000320
Tim Peters17e17d42001-06-13 22:45:27 +0000321 else:
322 # x is out of range -- verify pack realizes that.
323 if code in self.BUGGY_RANGE_CHECK:
324 if verbose:
325 print "Skipping buggy range check for code", code
326 else:
327 any_err(pack, ">" + code, x)
328 any_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000329
Tim Peters17e17d42001-06-13 22:45:27 +0000330 def run(self):
331 from random import randrange
332
333 # Create all interesting powers of 2.
334 values = []
335 for exp in range(self.bitsize + 3):
336 values.append(1L << exp)
337
338 # Add some random values.
339 for i in range(self.bitsize):
340 val = 0L
341 for j in range(self.bytesize):
342 val = (val << 8) | randrange(256)
343 values.append(val)
344
345 # Try all those, and their negations, and +-1 from them. Note
346 # that this tests all power-of-2 boundaries in range, and a few out
347 # of range, plus +-(2**n +- 1).
348 for base in values:
349 for val in -base, base:
350 for incr in -1, 0, 1:
351 x = val + incr
352 try:
353 x = int(x)
354 except OverflowError:
355 pass
356 self.test_one(x)
357
358 # Some error cases.
359 for direction in "<>":
360 for code in self.formatpair:
361 for badobject in "a string", 3+42j, randrange:
362 any_err(struct.pack, direction + code, badobject)
363
364for args in [("bB", 1),
365 ("hH", 2),
366 ("iI", 4),
367 ("lL", 4),
368 ("qQ", 8)]:
369 t = IntTester(*args)
370 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000371
372
373###########################################################################
374# The p ("Pascal string") code.
375
376def test_p_code():
377 for code, input, expected, expectedback in [
378 ('p','abc', '\x00', ''),
379 ('1p', 'abc', '\x00', ''),
380 ('2p', 'abc', '\x01a', 'a'),
381 ('3p', 'abc', '\x02ab', 'ab'),
382 ('4p', 'abc', '\x03abc', 'abc'),
383 ('5p', 'abc', '\x03abc\x00', 'abc'),
384 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
385 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
386 got = struct.pack(code, input)
387 if got != expected:
388 raise TestFailed("pack(%r, %r) == %r but expected %r" %
389 (code, input, got, expected))
390 (got,) = struct.unpack(code, got)
391 if got != expectedback:
392 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
393 (code, input, got, expectedback))
394
395test_p_code()