blob: e6c8bb24c69ee49eb94c3905f150c6d1bbff0507 [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
5def simple_err(func, *args):
6 try:
Guido van Rossum41360a41998-03-26 19:42:58 +00007 apply(func, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00008 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +00009 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000010 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000011 raise TestFailed, "%s%s did not raise struct.error" % (
12 func.__name__, args)
13## pdb.set_trace()
Barry Warsaw07a0eec1996-12-12 23:34:06 +000014
Tim Peters7a3bfc32001-06-12 01:22:22 +000015def any_err(func, *args):
16 try:
17 apply(func, args)
18 except (struct.error, OverflowError, TypeError):
19 pass
20 else:
21 raise TestFailed, "%s%s did not raise error" % (
22 func.__name__, args)
23## pdb.set_trace()
24
Tim Peters7b9542a2001-06-10 23:40:19 +000025simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000026
27sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000028if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000029 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000030
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000031fmt = 'cbxxxxxxhhhhiillffd'
32fmt3 = '3c3b18x12h6i6l6f3d'
33sz = struct.calcsize(fmt)
34sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000035if sz * 3 != sz3:
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000036 raise TestFailed, 'inconsistent sizes (3*%s -> 3*%d = %d, %s -> %d)' % (
Guido van Rossum41360a41998-03-26 19:42:58 +000037 `fmt`, sz, 3*sz, `fmt3`, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000038
39simple_err(struct.pack, 'iii', 3)
40simple_err(struct.pack, 'i', 3, 3, 3)
41simple_err(struct.pack, 'i', 'foo')
42simple_err(struct.unpack, 'd', 'flap')
43s = struct.pack('ii', 1, 2)
44simple_err(struct.unpack, 'iii', s)
45simple_err(struct.unpack, 'i', s)
46
47c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +000048b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +000049h = 255
50i = 65535
51l = 65536
52f = 3.1415
53d = 3.1415
54
Guido van Rossum420c11c1997-01-03 00:09:46 +000055for prefix in ('', '@', '<', '>', '=', '!'):
56 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +000057 format = prefix + format
58 if verbose:
59 print "trying:", format
60 s = struct.pack(format, c, b, h, i, l, f, d)
61 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +000062 if (cp != c or bp != b or hp != h or ip != i or lp != l or
63 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +000064 # ^^^ calculate only to two decimal places
65 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
66 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +000067
Guido van Rossum420c11c1997-01-03 00:09:46 +000068# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +000069
70# (format, argument, big-endian result, little-endian result, asymmetric)
71tests = [
72 ('c', 'a', 'a', 'a', 0),
73 ('xc', 'a', '\0a', '\0a', 0),
74 ('cx', 'a', 'a\0', 'a\0', 0),
75 ('s', 'a', 'a', 'a', 0),
76 ('0s', 'helloworld', '', '', 1),
77 ('1s', 'helloworld', 'h', 'h', 1),
78 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
79 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
80 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
81 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
82 ('b', 7, '\7', '\7', 0),
83 ('b', -7, '\371', '\371', 0),
84 ('B', 7, '\7', '\7', 0),
85 ('B', 249, '\371', '\371', 0),
86 ('h', 700, '\002\274', '\274\002', 0),
87 ('h', -700, '\375D', 'D\375', 0),
88 ('H', 700, '\002\274', '\274\002', 0),
89 ('H', 0x10000-700, '\375D', 'D\375', 0),
90 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
91 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
92 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
93 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
94 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
95 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
96 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
97 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +000098 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
99 ('d', 2.0, '@\000\000\000\000\000\000\000',
100 '\000\000\000\000\000\000\000@', 0),
101 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
102 ('d', -2.0, '\300\000\000\000\000\000\000\000',
103 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000104]
105
Tim Peters7b9542a2001-06-10 23:40:19 +0000106isbigendian = struct.pack('=i', 1)[0] == chr(0)
Guido van Rossum2a378501996-12-31 17:25:47 +0000107
108for fmt, arg, big, lil, asy in tests:
109 if verbose:
Guido van Rossum41360a41998-03-26 19:42:58 +0000110 print `fmt`, `arg`, `big`, `lil`
Guido van Rossum2a378501996-12-31 17:25:47 +0000111 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Guido van Rossum41360a41998-03-26 19:42:58 +0000112 ('='+fmt, isbigendian and big or lil)]:
113 res = struct.pack(xfmt, arg)
114 if res != exp:
115 raise TestFailed, "pack(%s, %s) -> %s # expected %s" % (
116 `fmt`, `arg`, `res`, `exp`)
117 n = struct.calcsize(xfmt)
118 if n != len(res):
119 raise TestFailed, "calcsize(%s) -> %d # expected %d" % (
120 `xfmt`, n, len(res))
121 rev = struct.unpack(xfmt, res)[0]
122 if rev != arg and not asy:
123 raise TestFailed, "unpack(%s, %s) -> (%s,) # expected (%s,)" % (
124 `fmt`, `res`, `rev`, `arg`)
Tim Peters7b9542a2001-06-10 23:40:19 +0000125
Tim Peters7a3bfc32001-06-12 01:22:22 +0000126###########################################################################
127# q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000128
129has_native_qQ = 1
130try:
131 struct.pack("q", 5)
132except struct.error:
133 has_native_qQ = 0
134
135if verbose:
136 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
137
Tim Peters7a3bfc32001-06-12 01:22:22 +0000138any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000139simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
140simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
141
Tim Peters7a3bfc32001-06-12 01:22:22 +0000142def string_reverse(s):
143 chars = list(s)
144 chars.reverse()
145 return "".join(chars)
146
Tim Petersc533edc2001-06-10 23:52:59 +0000147def bigendian_to_native(value):
Tim Peters7b9542a2001-06-10 23:40:19 +0000148 if isbigendian:
149 return value
Tim Peters7a3bfc32001-06-12 01:22:22 +0000150 else:
151 return string_reverse(value)
Tim Peters7b9542a2001-06-10 23:40:19 +0000152
Tim Peters7a3bfc32001-06-12 01:22:22 +0000153def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000154 bytes = struct.calcsize('q')
155 # The expected values here are in big-endian format, primarily because
156 # I'm on a little-endian machine and so this is the clearest way (for
157 # me) to force the code to get exercised.
158 for format, input, expected in (
159 ('q', -1, '\xff' * bytes),
160 ('q', 0, '\x00' * bytes),
161 ('Q', 0, '\x00' * bytes),
162 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
163 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
164 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
165 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000166 native_expected = bigendian_to_native(expected)
167 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000168 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000169 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000170 retrieved = struct.unpack(format, got)[0]
171 verify(retrieved == input,
172 "%r-unpack of %r gave %r, not %r" %
173 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000174
175if has_native_qQ:
176 test_native_qQ()
177
178# Standard q/Q (8 bytes; should work on all platforms).
179
180MIN_Q, MAX_Q = 0, 2L**64 - 1
181MIN_q, MAX_q = -(2L**63), 2L**63 - 1
182
183import binascii
184def test_one_qQ(x, pack=struct.pack,
185 unpack=struct.unpack,
186 unhexlify=binascii.unhexlify):
187 if verbose:
188 print "trying std q/Q on", x, "==", hex(x)
189
190 # Try 'q'.
191 if MIN_q <= x <= MAX_q:
192 # Try '>q'.
193 expected = long(x)
194 if x < 0:
195 expected += 1L << 64
196 assert expected > 0
197 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
198 if len(expected) & 1:
199 expected = "0" + expected
200 expected = unhexlify(expected)
201 expected = "\x00" * (8 - len(expected)) + expected
202
203 # >q pack work?
204 got = pack(">q", x)
205 verify(got == expected,
206 "'>q'-pack of %r gave %r, not %r" %
207 (x, got, expected))
208
209 # >q unpack work?
210 retrieved = unpack(">q", got)[0]
211 verify(x == retrieved,
212 "'>q'-unpack of %r gave %r, not %r" %
213 (got, retrieved, x))
214
215 # Adding any byte should cause a "too big" error.
216 any_err(unpack, ">q", '\x01' + got)
217
218 # Try '<q'.
219 expected = string_reverse(expected)
220
221 # <q pack work?
222 got = pack("<q", x)
223 verify(got == expected,
224 "'<q'-pack of %r gave %r, not %r" %
225 (x, got, expected))
226
227 # <q unpack work?
228 retrieved = unpack("<q", got)[0]
229 verify(x == retrieved,
230 "'<q'-unpack of %r gave %r, not %r" %
231 (got, retrieved, x))
232
233 # Adding any byte should cause a "too big" error.
234 any_err(unpack, "<q", '\x01' + got)
235
236 else:
237 # x is out of q's range -- verify pack realizes that.
238 any_err(pack, '>q', x)
239 any_err(pack, '<q', x)
240
241 # Much the same for 'Q'.
242 if MIN_Q <= x <= MAX_Q:
243 # Try '>Q'.
244 expected = long(x)
245 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
246 if len(expected) & 1:
247 expected = "0" + expected
248 expected = unhexlify(expected)
249 expected = "\x00" * (8 - len(expected)) + expected
250
251 # >Q pack work?
252 got = pack(">Q", x)
253 verify(got == expected,
254 "'>Q'-pack of %r gave %r, not %r" %
255 (x, got, expected))
256
257 # >Q unpack work?
258 retrieved = unpack(">Q", got)[0]
259 verify(x == retrieved,
260 "'>Q'-unpack of %r gave %r, not %r" %
261 (got, retrieved, x))
262
263 # Adding any byte should cause a "too big" error.
264 any_err(unpack, ">Q", '\x01' + got)
265
266 # Try '<Q'.
267 expected = string_reverse(expected)
268
269 # <Q pack work?
270 got = pack("<Q", x)
271 verify(got == expected,
272 "'<Q'-pack of %r gave %r, not %r" %
273 (x, got, expected))
274
275 # <Q unpack work?
276 retrieved = unpack("<Q", got)[0]
277 verify(x == retrieved,
278 "'<Q'-unpack of %r gave %r, not %r" %
279 (got, retrieved, x))
280
281 # Adding any byte should cause a "too big" error.
282 any_err(unpack, "<Q", '\x01' + got)
283
284 else:
285 # x is out of Q's range -- verify pack realizes that.
286 any_err(pack, '>Q', x)
287 any_err(pack, '<Q', x)
288
289def test_std_qQ():
290 from random import randrange
291
292 # Create all interesting powers of 2.
293 values = []
294 for exp in range(70):
295 values.append(1L << exp)
296
297 # Add some random 64-bit values.
298 for i in range(50):
299 val = 0L
300 for j in range(8):
301 val = (val << 8) | randrange(256)
302 values.append(val)
303
304 # Try all those, and their negations, and +-1 from them. Note
305 # that this tests all power-of-2 boundaries in range, and a few out
306 # of range, plus +-(2**n +- 1).
307 for base in values:
308 for val in -base, base:
309 for incr in -1, 0, 1:
310 x = val + incr
311 try:
312 x = int(x)
313 except OverflowError:
314 pass
315 test_one_qQ(x)
316
317test_std_qQ()