blob: 28759fb866fde30e0bc531c9cdc90a1b99638af0 [file] [log] [blame]
Barry Warsaw04f357c2002-07-23 19:04:11 +00001from test.test_support import TestFailed, verbose, verify
Martin Blais2856e5f2006-05-26 12:03:27 +00002import test.test_support
Barry Warsaw07a0eec1996-12-12 23:34:06 +00003import struct
Martin Blais2856e5f2006-05-26 12:03:27 +00004import array
Bob Ippolito2fd39772006-05-29 22:55:48 +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
Bob Ippolito2fd39772006-05-29 22:55:48 +000013try:
14 import _struct
15except ImportError:
16 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000017 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolito2fd39772006-05-29 22:55:48 +000018else:
19 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
Bob Ippolito4182a752006-05-30 17:37:54 +000020 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +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)
Bob Ippolito2fd39772006-05-29 22:55:48 +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
Bob Ippolito2fd39772006-05-29 22:55:48 +000051def deprecated_err(func, *args):
Tim Petersaba19bc2006-05-30 02:25:25 +000052 # The `warnings` module doesn't have an advertised way to restore
53 # its filter list. Cheat.
54 save_warnings_filters = warnings.filters[:]
Neal Norwitz9f16dd02006-05-31 09:02:44 +000055 # 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__']
Bob Ippolito2fd39772006-05-29 22:55:48 +000061 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
Tim Petersaba19bc2006-05-30 02:25:25 +000062 warnings.filterwarnings("error", r""".*format requires.*""",
63 DeprecationWarning)
Bob Ippolito2fd39772006-05-29 22:55:48 +000064 try:
65 try:
66 func(*args)
67 except (struct.error, TypeError):
68 pass
69 except DeprecationWarning:
Bob Ippolito4182a752006-05-30 17:37:54 +000070 if not PY_STRUCT_OVERFLOW_MASKING:
Bob Ippolito2fd39772006-05-29 22:55:48 +000071 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:
Tim Petersaba19bc2006-05-30 02:25:25 +000077 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.
Bob Ippolitoe27337b2006-05-26 13:15:44 +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:
Bob Ippolito2fd39772006-05-29 22:55:48 +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.
Bob Ippolitoaa70a172006-05-26 20:25:23 +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:
Bob Ippolito2fd39772006-05-29 22:55:48 +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()
Bob Ippolitoeb621272006-05-24 15:32:06 +0000479
Bob Ippolitoeb621272006-05-24 15:32:06 +0000480def test_1229380():
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000481 import sys
Bob Ippolitoeb621272006-05-24 15:32:06 +0000482 for endian in ('', '>', '<'):
483 for cls in (int, long):
484 for fmt in ('B', 'H', 'I', 'L'):
Bob Ippolito2fd39772006-05-29 22:55:48 +0000485 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000486
Bob Ippolito2fd39772006-05-29 22:55:48 +0000487 deprecated_err(struct.pack, endian + 'B', cls(300))
488 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000489
Bob Ippolito2fd39772006-05-29 22:55:48 +0000490 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
491 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000492
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000493if PY_STRUCT_RANGE_CHECKING:
Bob Ippolitoeb621272006-05-24 15:32:06 +0000494 test_1229380()
Martin Blais2856e5f2006-05-26 12:03:27 +0000495
Martin Blais2856e5f2006-05-26 12:03:27 +0000496
Martin Blais7f7386c2006-06-02 13:03:43 +0000497###########################################################################
498# Packing and unpacking to/from buffers.
Martin Blais2856e5f2006-05-26 12:03:27 +0000499
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000508
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000531
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000537
Martin Blais7f7386c2006-06-02 13:03:43 +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
Martin Blais2856e5f2006-05-26 12:03:27 +0000542
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000547
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000552
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000558
Martin Blais7f7386c2006-06-02 13:03:43 +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
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000563
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000568
Martin Blais7f7386c2006-06-02 13:03:43 +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)
Tim Petersfe98f962006-05-26 12:26:21 +0000573
Tim Petersc65a13f2006-06-04 01:22:53 +0000574
Martin Blais7f7386c2006-06-02 13:03:43 +0000575# Test methods to pack and unpack from buffers rather than strings.
576test_unpack_from()
577test_pack_to()
578test_pack_to_fn()