blob: 0f3ac91a39230211165979b026540a0435918e19 [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()