blob: af835f7a6fbec3c91fc1a48d3685ab7c1942a2c8 [file] [log] [blame]
Barry Warsaw04f357c2002-07-23 19:04:11 +00001from test.test_support import TestFailed, verbose, verify
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
18else:
19 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
20 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000021
Tim Peters17e17d42001-06-13 22:45:27 +000022def string_reverse(s):
23 chars = list(s)
24 chars.reverse()
25 return "".join(chars)
26
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 Wouters4d70c3d2006-06-08 14:42:34 +000051def deprecated_err(func, *args):
52 # The `warnings` module doesn't have an advertised way to restore
53 # its filter list. Cheat.
54 save_warnings_filters = warnings.filters[:]
55 # Grrr, we need this function to warn every time. Without removing
56 # the warningregistry, running test_tarfile then test_struct would fail
57 # on 64-bit platforms.
58 globals = func.func_globals
59 if '__warningregistry__' in globals:
60 del globals['__warningregistry__']
61 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
62 warnings.filterwarnings("error", r""".*format requires.*""",
63 DeprecationWarning)
64 try:
65 try:
66 func(*args)
67 except (struct.error, TypeError):
68 pass
69 except DeprecationWarning:
70 if not PY_STRUCT_OVERFLOW_MASKING:
71 raise TestFailed, "%s%s expected to raise struct.error" % (
72 func.__name__, args)
73 else:
74 raise TestFailed, "%s%s did not raise error" % (
75 func.__name__, args)
76 finally:
77 warnings.filters[:] = save_warnings_filters[:]
Tim Peters17e17d42001-06-13 22:45:27 +000078
Tim Peters7b9542a2001-06-10 23:40:19 +000079simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000080
81sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000082if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000083 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000084
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000085fmt = 'cbxxxxxxhhhhiillffd'
86fmt3 = '3c3b18x12h6i6l6f3d'
87sz = struct.calcsize(fmt)
88sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000089if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000090 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
91 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000092
93simple_err(struct.pack, 'iii', 3)
94simple_err(struct.pack, 'i', 3, 3, 3)
95simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +000096simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000097simple_err(struct.unpack, 'd', 'flap')
98s = struct.pack('ii', 1, 2)
99simple_err(struct.unpack, 'iii', s)
100simple_err(struct.unpack, 'i', s)
101
102c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +0000103b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000104h = 255
105i = 65535
106l = 65536
107f = 3.1415
108d = 3.1415
109
Guido van Rossum420c11c1997-01-03 00:09:46 +0000110for prefix in ('', '@', '<', '>', '=', '!'):
111 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000112 format = prefix + format
113 if verbose:
114 print "trying:", format
115 s = struct.pack(format, c, b, h, i, l, f, d)
116 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000117 if (cp != c or bp != b or hp != h or ip != i or lp != l or
118 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +0000119 # ^^^ calculate only to two decimal places
120 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
121 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000122
Guido van Rossum420c11c1997-01-03 00:09:46 +0000123# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000124
125# (format, argument, big-endian result, little-endian result, asymmetric)
126tests = [
127 ('c', 'a', 'a', 'a', 0),
128 ('xc', 'a', '\0a', '\0a', 0),
129 ('cx', 'a', 'a\0', 'a\0', 0),
130 ('s', 'a', 'a', 'a', 0),
131 ('0s', 'helloworld', '', '', 1),
132 ('1s', 'helloworld', 'h', 'h', 1),
133 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
134 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
135 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
136 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
137 ('b', 7, '\7', '\7', 0),
138 ('b', -7, '\371', '\371', 0),
139 ('B', 7, '\7', '\7', 0),
140 ('B', 249, '\371', '\371', 0),
141 ('h', 700, '\002\274', '\274\002', 0),
142 ('h', -700, '\375D', 'D\375', 0),
143 ('H', 700, '\002\274', '\274\002', 0),
144 ('H', 0x10000-700, '\375D', 'D\375', 0),
145 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
146 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
147 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
148 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
149 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
150 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
151 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
152 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000153 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
154 ('d', 2.0, '@\000\000\000\000\000\000\000',
155 '\000\000\000\000\000\000\000@', 0),
156 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
157 ('d', -2.0, '\300\000\000\000\000\000\000\000',
158 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000159]
160
Guido van Rossum2a378501996-12-31 17:25:47 +0000161for fmt, arg, big, lil, asy in tests:
162 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000163 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000164 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000165 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000166 res = struct.pack(xfmt, arg)
167 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000168 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
169 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000170 n = struct.calcsize(xfmt)
171 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000172 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
173 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000174 rev = struct.unpack(xfmt, res)[0]
175 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000176 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
177 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000178
Tim Peters7a3bfc32001-06-12 01:22:22 +0000179###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000180# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000181
182has_native_qQ = 1
183try:
184 struct.pack("q", 5)
185except struct.error:
186 has_native_qQ = 0
187
188if verbose:
189 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
190
Tim Peters7a3bfc32001-06-12 01:22:22 +0000191any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000192simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
193simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
194
Tim Peters7a3bfc32001-06-12 01:22:22 +0000195def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000196 bytes = struct.calcsize('q')
197 # The expected values here are in big-endian format, primarily because
198 # I'm on a little-endian machine and so this is the clearest way (for
199 # me) to force the code to get exercised.
200 for format, input, expected in (
201 ('q', -1, '\xff' * bytes),
202 ('q', 0, '\x00' * bytes),
203 ('Q', 0, '\x00' * bytes),
204 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
205 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
206 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
207 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000208 native_expected = bigendian_to_native(expected)
209 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000210 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000211 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000212 retrieved = struct.unpack(format, got)[0]
213 verify(retrieved == input,
214 "%r-unpack of %r gave %r, not %r" %
215 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000216
217if has_native_qQ:
218 test_native_qQ()
219
Tim Peters17e17d42001-06-13 22:45:27 +0000220###########################################################################
221# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000222
223import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000224
Tim Peters17e17d42001-06-13 22:45:27 +0000225class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000226
Tim Peters17e17d42001-06-13 22:45:27 +0000227 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000228 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
229 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
230 # reported by Mark Favas).
231 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000232
Tim Peters17e17d42001-06-13 22:45:27 +0000233 def __init__(self, formatpair, bytesize):
234 assert len(formatpair) == 2
235 self.formatpair = formatpair
236 for direction in "<>!=":
237 for code in formatpair:
238 format = direction + code
239 verify(struct.calcsize(format) == bytesize)
240 self.bytesize = bytesize
241 self.bitsize = bytesize * 8
242 self.signed_code, self.unsigned_code = formatpair
243 self.unsigned_min = 0
244 self.unsigned_max = 2L**self.bitsize - 1
245 self.signed_min = -(2L**(self.bitsize-1))
246 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000247
Tim Peters17e17d42001-06-13 22:45:27 +0000248 def test_one(self, x, pack=struct.pack,
249 unpack=struct.unpack,
250 unhexlify=binascii.unhexlify):
251 if verbose:
252 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000253
Tim Peters17e17d42001-06-13 22:45:27 +0000254 # Try signed.
255 code = self.signed_code
256 if self.signed_min <= x <= self.signed_max:
257 # Try big-endian.
258 expected = long(x)
259 if x < 0:
260 expected += 1L << self.bitsize
261 assert expected > 0
262 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
263 if len(expected) & 1:
264 expected = "0" + expected
265 expected = unhexlify(expected)
266 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000267
Tim Peters17e17d42001-06-13 22:45:27 +0000268 # Pack work?
269 format = ">" + code
270 got = pack(format, x)
271 verify(got == expected,
272 "'%s'-pack of %r gave %r, not %r" %
273 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000274
Tim Peters17e17d42001-06-13 22:45:27 +0000275 # Unpack work?
276 retrieved = unpack(format, got)[0]
277 verify(x == retrieved,
278 "'%s'-unpack of %r gave %r, not %r" %
279 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000280
Tim Peters17e17d42001-06-13 22:45:27 +0000281 # Adding any byte should cause a "too big" error.
282 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000283
Tim Peters17e17d42001-06-13 22:45:27 +0000284 # Try little-endian.
285 format = "<" + code
286 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000287
Tim Peters17e17d42001-06-13 22:45:27 +0000288 # Pack work?
289 got = pack(format, x)
290 verify(got == expected,
291 "'%s'-pack of %r gave %r, not %r" %
292 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000293
Tim Peters17e17d42001-06-13 22:45:27 +0000294 # Unpack work?
295 retrieved = unpack(format, got)[0]
296 verify(x == retrieved,
297 "'%s'-unpack of %r gave %r, not %r" %
298 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000299
Tim Peters17e17d42001-06-13 22:45:27 +0000300 # Adding any byte should cause a "too big" error.
301 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000302
Tim Peters17e17d42001-06-13 22:45:27 +0000303 else:
304 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000305 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000306 if verbose:
307 print "Skipping buggy range check for code", code
308 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000309 deprecated_err(pack, ">" + code, x)
310 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000311
Tim Peters17e17d42001-06-13 22:45:27 +0000312 # Much the same for unsigned.
313 code = self.unsigned_code
314 if self.unsigned_min <= x <= self.unsigned_max:
315 # Try big-endian.
316 format = ">" + code
317 expected = long(x)
318 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
319 if len(expected) & 1:
320 expected = "0" + expected
321 expected = unhexlify(expected)
322 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000323
Tim Peters17e17d42001-06-13 22:45:27 +0000324 # Pack work?
325 got = pack(format, x)
326 verify(got == expected,
327 "'%s'-pack of %r gave %r, not %r" %
328 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000329
Tim Peters17e17d42001-06-13 22:45:27 +0000330 # Unpack work?
331 retrieved = unpack(format, got)[0]
332 verify(x == retrieved,
333 "'%s'-unpack of %r gave %r, not %r" %
334 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000335
Tim Peters17e17d42001-06-13 22:45:27 +0000336 # Adding any byte should cause a "too big" error.
337 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000338
Tim Peters17e17d42001-06-13 22:45:27 +0000339 # Try little-endian.
340 format = "<" + code
341 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000342
Tim Peters17e17d42001-06-13 22:45:27 +0000343 # Pack work?
344 got = pack(format, x)
345 verify(got == expected,
346 "'%s'-pack of %r gave %r, not %r" %
347 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000348
Tim Peters17e17d42001-06-13 22:45:27 +0000349 # Unpack work?
350 retrieved = unpack(format, got)[0]
351 verify(x == retrieved,
352 "'%s'-unpack of %r gave %r, not %r" %
353 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000354
Tim Peters17e17d42001-06-13 22:45:27 +0000355 # Adding any byte should cause a "too big" error.
356 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000357
Tim Peters17e17d42001-06-13 22:45:27 +0000358 else:
359 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000360 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000361 if verbose:
362 print "Skipping buggy range check for code", code
363 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000364 deprecated_err(pack, ">" + code, x)
365 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000366
Tim Peters17e17d42001-06-13 22:45:27 +0000367 def run(self):
368 from random import randrange
369
370 # Create all interesting powers of 2.
371 values = []
372 for exp in range(self.bitsize + 3):
373 values.append(1L << exp)
374
375 # Add some random values.
376 for i in range(self.bitsize):
377 val = 0L
378 for j in range(self.bytesize):
379 val = (val << 8) | randrange(256)
380 values.append(val)
381
382 # Try all those, and their negations, and +-1 from them. Note
383 # that this tests all power-of-2 boundaries in range, and a few out
384 # of range, plus +-(2**n +- 1).
385 for base in values:
386 for val in -base, base:
387 for incr in -1, 0, 1:
388 x = val + incr
389 try:
390 x = int(x)
391 except OverflowError:
392 pass
393 self.test_one(x)
394
395 # Some error cases.
396 for direction in "<>":
397 for code in self.formatpair:
398 for badobject in "a string", 3+42j, randrange:
399 any_err(struct.pack, direction + code, badobject)
400
401for args in [("bB", 1),
402 ("hH", 2),
403 ("iI", 4),
404 ("lL", 4),
405 ("qQ", 8)]:
406 t = IntTester(*args)
407 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000408
409
410###########################################################################
411# The p ("Pascal string") code.
412
413def test_p_code():
414 for code, input, expected, expectedback in [
415 ('p','abc', '\x00', ''),
416 ('1p', 'abc', '\x00', ''),
417 ('2p', 'abc', '\x01a', 'a'),
418 ('3p', 'abc', '\x02ab', 'ab'),
419 ('4p', 'abc', '\x03abc', 'abc'),
420 ('5p', 'abc', '\x03abc\x00', 'abc'),
421 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
422 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
423 got = struct.pack(code, input)
424 if got != expected:
425 raise TestFailed("pack(%r, %r) == %r but expected %r" %
426 (code, input, got, expected))
427 (got,) = struct.unpack(code, got)
428 if got != expectedback:
429 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
430 (code, input, got, expectedback))
431
432test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000433
434
435###########################################################################
436# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
437# from the low-order discarded bits could propagate into the exponent
438# field, causing the result to be wrong by a factor of 2.
439
440def test_705836():
441 import math
442
443 for base in range(1, 33):
444 # smaller <- largest representable float less than base.
445 delta = 0.5
446 while base - delta / 2.0 != base:
447 delta /= 2.0
448 smaller = base - delta
449 # Packing this rounds away a solid string of trailing 1 bits.
450 packed = struct.pack("<f", smaller)
451 unpacked = struct.unpack("<f", packed)[0]
452 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
453 # 16, respectively.
454 verify(base == unpacked)
455 bigpacked = struct.pack(">f", smaller)
456 verify(bigpacked == string_reverse(packed),
457 ">f pack should be byte-reversal of <f pack")
458 unpacked = struct.unpack(">f", bigpacked)[0]
459 verify(base == unpacked)
460
461 # Largest finite IEEE single.
462 big = (1 << 24) - 1
463 big = math.ldexp(big, 127 - 23)
464 packed = struct.pack(">f", big)
465 unpacked = struct.unpack(">f", packed)[0]
466 verify(big == unpacked)
467
468 # The same, but tack on a 1 bit so it rounds up to infinity.
469 big = (1 << 25) - 1
470 big = math.ldexp(big, 127 - 24)
471 try:
472 packed = struct.pack(">f", big)
473 except OverflowError:
474 pass
475 else:
476 TestFailed("expected OverflowError")
477
478test_705836()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000479
480def test_1229380():
481 import sys
482 for endian in ('', '>', '<'):
483 for cls in (int, long):
484 for fmt in ('B', 'H', 'I', 'L'):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000485 deprecated_err(struct.pack, endian + fmt, cls(-1))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000486
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000487 deprecated_err(struct.pack, endian + 'B', cls(300))
488 deprecated_err(struct.pack, endian + 'H', cls(70000))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000489
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000490 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
491 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492
493if PY_STRUCT_RANGE_CHECKING:
494 test_1229380()
495
Thomas Wouters477c8d52006-05-27 19:21:47 +0000496
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000497###########################################################################
498# Packing and unpacking to/from buffers.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000500# Copied and modified from unittest.
501def assertRaises(excClass, callableObj, *args, **kwargs):
502 try:
503 callableObj(*args, **kwargs)
504 except excClass:
505 return
506 else:
507 raise RuntimeError("%s not raised." % excClass)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000508
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000509def test_unpack_from():
510 test_string = 'abcd01234'
511 fmt = '4s'
512 s = struct.Struct(fmt)
513 for cls in (str, buffer):
514 data = cls(test_string)
515 assert s.unpack_from(data) == ('abcd',)
516 assert s.unpack_from(data, 2) == ('cd01',)
517 assert s.unpack_from(data, 4) == ('0123',)
518 for i in xrange(6):
519 assert s.unpack_from(data, i) == (data[i:i+4],)
520 for i in xrange(6, len(test_string) + 1):
521 simple_err(s.unpack_from, data, i)
522 for cls in (str, buffer):
523 data = cls(test_string)
524 assert struct.unpack_from(fmt, data) == ('abcd',)
525 assert struct.unpack_from(fmt, data, 2) == ('cd01',)
526 assert struct.unpack_from(fmt, data, 4) == ('0123',)
527 for i in xrange(6):
528 assert (struct.unpack_from(fmt, data, i) == (data[i:i+4],))
529 for i in xrange(6, len(test_string) + 1):
530 simple_err(struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000531
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000532def test_pack_to():
533 test_string = 'Reykjavik rocks, eow!'
534 writable_buf = array.array('c', ' '*100)
535 fmt = '21s'
536 s = struct.Struct(fmt)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000538 # Test without offset
539 s.pack_to(writable_buf, 0, test_string)
540 from_buf = writable_buf.tostring()[:len(test_string)]
541 assert from_buf == test_string
Thomas Wouters477c8d52006-05-27 19:21:47 +0000542
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000543 # Test with offset.
544 s.pack_to(writable_buf, 10, test_string)
545 from_buf = writable_buf.tostring()[:len(test_string)+10]
546 assert from_buf == (test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000547
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000548 # Go beyond boundaries.
549 small_buf = array.array('c', ' '*10)
550 assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
551 assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000552
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000553def test_pack_to_fn():
554 test_string = 'Reykjavik rocks, eow!'
555 writable_buf = array.array('c', ' '*100)
556 fmt = '21s'
557 pack_to = lambda *args: struct.pack_to(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000558
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000559 # Test without offset
560 pack_to(writable_buf, 0, test_string)
561 from_buf = writable_buf.tostring()[:len(test_string)]
562 assert from_buf == test_string
Thomas Wouters477c8d52006-05-27 19:21:47 +0000563
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000564 # Test with offset.
565 pack_to(writable_buf, 10, test_string)
566 from_buf = writable_buf.tostring()[:len(test_string)+10]
567 assert from_buf == (test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000568
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000569 # Go beyond boundaries.
570 small_buf = array.array('c', ' '*10)
571 assertRaises(struct.error, pack_to, small_buf, 0, test_string)
572 assertRaises(struct.error, pack_to, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000573
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000574
575# Test methods to pack and unpack from buffers rather than strings.
576test_unpack_from()
577test_pack_to()
578test_pack_to_fn()
579