blob: a6c0b4949f8231fd0a9374e293f9c6ab845137f2 [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
5import unittest
Bob Ippolito2fd39772006-05-29 22:55:48 +00006import warnings
Barry Warsaw07a0eec1996-12-12 23:34:06 +00007
Tim Peters17e17d42001-06-13 22:45:27 +00008import sys
9ISBIGENDIAN = sys.byteorder == "big"
10del sys
11verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
12 "bigendian determination appears wrong")
13
Bob Ippolito2fd39772006-05-29 22:55:48 +000014try:
15 import _struct
16except ImportError:
17 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000018 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolito2fd39772006-05-29 22:55:48 +000019else:
20 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
Bob Ippolito4182a752006-05-30 17:37:54 +000021 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000022
Tim Peters17e17d42001-06-13 22:45:27 +000023def string_reverse(s):
24 chars = list(s)
25 chars.reverse()
26 return "".join(chars)
27
28def bigendian_to_native(value):
29 if ISBIGENDIAN:
30 return value
31 else:
32 return string_reverse(value)
33
Barry Warsaw07a0eec1996-12-12 23:34:06 +000034def simple_err(func, *args):
35 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000036 func(*args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000037 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +000038 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000039 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000040 raise TestFailed, "%s%s did not raise struct.error" % (
41 func.__name__, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000042
Tim Peters7a3bfc32001-06-12 01:22:22 +000043def any_err(func, *args):
44 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000045 func(*args)
Bob Ippolito2fd39772006-05-29 22:55:48 +000046 except (struct.error, TypeError):
Tim Peters7a3bfc32001-06-12 01:22:22 +000047 pass
48 else:
49 raise TestFailed, "%s%s did not raise error" % (
50 func.__name__, args)
Tim Peters7a3bfc32001-06-12 01:22:22 +000051
Bob Ippolito2fd39772006-05-29 22:55:48 +000052def deprecated_err(func, *args):
Tim Petersaba19bc2006-05-30 02:25:25 +000053 # The `warnings` module doesn't have an advertised way to restore
54 # its filter list. Cheat.
55 save_warnings_filters = warnings.filters[:]
Neal Norwitz9f16dd02006-05-31 09:02:44 +000056 # Grrr, we need this function to warn every time. Without removing
57 # the warningregistry, running test_tarfile then test_struct would fail
58 # on 64-bit platforms.
59 globals = func.func_globals
60 if '__warningregistry__' in globals:
61 del globals['__warningregistry__']
Bob Ippolito2fd39772006-05-29 22:55:48 +000062 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
Tim Petersaba19bc2006-05-30 02:25:25 +000063 warnings.filterwarnings("error", r""".*format requires.*""",
64 DeprecationWarning)
Bob Ippolito2fd39772006-05-29 22:55:48 +000065 try:
66 try:
67 func(*args)
68 except (struct.error, TypeError):
69 pass
70 except DeprecationWarning:
Bob Ippolito4182a752006-05-30 17:37:54 +000071 if not PY_STRUCT_OVERFLOW_MASKING:
Bob Ippolito2fd39772006-05-29 22:55:48 +000072 raise TestFailed, "%s%s expected to raise struct.error" % (
73 func.__name__, args)
74 else:
75 raise TestFailed, "%s%s did not raise error" % (
76 func.__name__, args)
77 finally:
Tim Petersaba19bc2006-05-30 02:25:25 +000078 warnings.filters[:] = save_warnings_filters[:]
Tim Peters17e17d42001-06-13 22:45:27 +000079
Tim Peters7b9542a2001-06-10 23:40:19 +000080simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000081
82sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000083if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000084 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000085
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000086fmt = 'cbxxxxxxhhhhiillffd'
87fmt3 = '3c3b18x12h6i6l6f3d'
88sz = struct.calcsize(fmt)
89sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000090if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000091 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
92 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000093
94simple_err(struct.pack, 'iii', 3)
95simple_err(struct.pack, 'i', 3, 3, 3)
96simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +000097simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000098simple_err(struct.unpack, 'd', 'flap')
99s = struct.pack('ii', 1, 2)
100simple_err(struct.unpack, 'iii', s)
101simple_err(struct.unpack, 'i', s)
102
103c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +0000104b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000105h = 255
106i = 65535
107l = 65536
108f = 3.1415
109d = 3.1415
110
Guido van Rossum420c11c1997-01-03 00:09:46 +0000111for prefix in ('', '@', '<', '>', '=', '!'):
112 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000113 format = prefix + format
114 if verbose:
115 print "trying:", format
116 s = struct.pack(format, c, b, h, i, l, f, d)
117 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000118 if (cp != c or bp != b or hp != h or ip != i or lp != l or
119 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +0000120 # ^^^ calculate only to two decimal places
121 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
122 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000123
Guido van Rossum420c11c1997-01-03 00:09:46 +0000124# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000125
126# (format, argument, big-endian result, little-endian result, asymmetric)
127tests = [
128 ('c', 'a', 'a', 'a', 0),
129 ('xc', 'a', '\0a', '\0a', 0),
130 ('cx', 'a', 'a\0', 'a\0', 0),
131 ('s', 'a', 'a', 'a', 0),
132 ('0s', 'helloworld', '', '', 1),
133 ('1s', 'helloworld', 'h', 'h', 1),
134 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
135 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
136 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
137 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
138 ('b', 7, '\7', '\7', 0),
139 ('b', -7, '\371', '\371', 0),
140 ('B', 7, '\7', '\7', 0),
141 ('B', 249, '\371', '\371', 0),
142 ('h', 700, '\002\274', '\274\002', 0),
143 ('h', -700, '\375D', 'D\375', 0),
144 ('H', 700, '\002\274', '\274\002', 0),
145 ('H', 0x10000-700, '\375D', 'D\375', 0),
146 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
147 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
148 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
149 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
150 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
151 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
152 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
153 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000154 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
155 ('d', 2.0, '@\000\000\000\000\000\000\000',
156 '\000\000\000\000\000\000\000@', 0),
157 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
158 ('d', -2.0, '\300\000\000\000\000\000\000\000',
159 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000160]
161
Guido van Rossum2a378501996-12-31 17:25:47 +0000162for fmt, arg, big, lil, asy in tests:
163 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000164 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000165 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000166 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000167 res = struct.pack(xfmt, arg)
168 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000169 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
170 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000171 n = struct.calcsize(xfmt)
172 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000173 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
174 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000175 rev = struct.unpack(xfmt, res)[0]
176 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000177 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
178 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000179
Tim Peters7a3bfc32001-06-12 01:22:22 +0000180###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000181# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000182
183has_native_qQ = 1
184try:
185 struct.pack("q", 5)
186except struct.error:
187 has_native_qQ = 0
188
189if verbose:
190 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
191
Tim Peters7a3bfc32001-06-12 01:22:22 +0000192any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000193simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
194simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
195
Tim Peters7a3bfc32001-06-12 01:22:22 +0000196def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000197 bytes = struct.calcsize('q')
198 # The expected values here are in big-endian format, primarily because
199 # I'm on a little-endian machine and so this is the clearest way (for
200 # me) to force the code to get exercised.
201 for format, input, expected in (
202 ('q', -1, '\xff' * bytes),
203 ('q', 0, '\x00' * bytes),
204 ('Q', 0, '\x00' * bytes),
205 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
206 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
207 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
208 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000209 native_expected = bigendian_to_native(expected)
210 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000211 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000212 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000213 retrieved = struct.unpack(format, got)[0]
214 verify(retrieved == input,
215 "%r-unpack of %r gave %r, not %r" %
216 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000217
218if has_native_qQ:
219 test_native_qQ()
220
Tim Peters17e17d42001-06-13 22:45:27 +0000221###########################################################################
222# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000223
224import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000225
Tim Peters17e17d42001-06-13 22:45:27 +0000226class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000227
Tim Peters17e17d42001-06-13 22:45:27 +0000228 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000229 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
230 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
231 # reported by Mark Favas).
232 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000233
Tim Peters17e17d42001-06-13 22:45:27 +0000234 def __init__(self, formatpair, bytesize):
235 assert len(formatpair) == 2
236 self.formatpair = formatpair
237 for direction in "<>!=":
238 for code in formatpair:
239 format = direction + code
240 verify(struct.calcsize(format) == bytesize)
241 self.bytesize = bytesize
242 self.bitsize = bytesize * 8
243 self.signed_code, self.unsigned_code = formatpair
244 self.unsigned_min = 0
245 self.unsigned_max = 2L**self.bitsize - 1
246 self.signed_min = -(2L**(self.bitsize-1))
247 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000248
Tim Peters17e17d42001-06-13 22:45:27 +0000249 def test_one(self, x, pack=struct.pack,
250 unpack=struct.unpack,
251 unhexlify=binascii.unhexlify):
252 if verbose:
253 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000254
Tim Peters17e17d42001-06-13 22:45:27 +0000255 # Try signed.
256 code = self.signed_code
257 if self.signed_min <= x <= self.signed_max:
258 # Try big-endian.
259 expected = long(x)
260 if x < 0:
261 expected += 1L << self.bitsize
262 assert expected > 0
263 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
264 if len(expected) & 1:
265 expected = "0" + expected
266 expected = unhexlify(expected)
267 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000268
Tim Peters17e17d42001-06-13 22:45:27 +0000269 # Pack work?
270 format = ">" + code
271 got = pack(format, x)
272 verify(got == expected,
273 "'%s'-pack of %r gave %r, not %r" %
274 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000275
Tim Peters17e17d42001-06-13 22:45:27 +0000276 # Unpack work?
277 retrieved = unpack(format, got)[0]
278 verify(x == retrieved,
279 "'%s'-unpack of %r gave %r, not %r" %
280 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000281
Tim Peters17e17d42001-06-13 22:45:27 +0000282 # Adding any byte should cause a "too big" error.
283 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000284
Tim Peters17e17d42001-06-13 22:45:27 +0000285 # Try little-endian.
286 format = "<" + code
287 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000288
Tim Peters17e17d42001-06-13 22:45:27 +0000289 # Pack work?
290 got = pack(format, x)
291 verify(got == expected,
292 "'%s'-pack of %r gave %r, not %r" %
293 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000294
Tim Peters17e17d42001-06-13 22:45:27 +0000295 # Unpack work?
296 retrieved = unpack(format, got)[0]
297 verify(x == retrieved,
298 "'%s'-unpack of %r gave %r, not %r" %
299 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000300
Tim Peters17e17d42001-06-13 22:45:27 +0000301 # Adding any byte should cause a "too big" error.
302 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000303
Tim Peters17e17d42001-06-13 22:45:27 +0000304 else:
305 # x is out of range -- verify pack realizes that.
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000306 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000307 if verbose:
308 print "Skipping buggy range check for code", code
309 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000310 deprecated_err(pack, ">" + code, x)
311 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000312
Tim Peters17e17d42001-06-13 22:45:27 +0000313 # Much the same for unsigned.
314 code = self.unsigned_code
315 if self.unsigned_min <= x <= self.unsigned_max:
316 # Try big-endian.
317 format = ">" + code
318 expected = long(x)
319 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
320 if len(expected) & 1:
321 expected = "0" + expected
322 expected = unhexlify(expected)
323 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000324
Tim Peters17e17d42001-06-13 22:45:27 +0000325 # Pack work?
326 got = pack(format, x)
327 verify(got == expected,
328 "'%s'-pack of %r gave %r, not %r" %
329 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000330
Tim Peters17e17d42001-06-13 22:45:27 +0000331 # Unpack work?
332 retrieved = unpack(format, got)[0]
333 verify(x == retrieved,
334 "'%s'-unpack of %r gave %r, not %r" %
335 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000336
Tim Peters17e17d42001-06-13 22:45:27 +0000337 # Adding any byte should cause a "too big" error.
338 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000339
Tim Peters17e17d42001-06-13 22:45:27 +0000340 # Try little-endian.
341 format = "<" + code
342 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000343
Tim Peters17e17d42001-06-13 22:45:27 +0000344 # Pack work?
345 got = pack(format, x)
346 verify(got == expected,
347 "'%s'-pack of %r gave %r, not %r" %
348 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000349
Tim Peters17e17d42001-06-13 22:45:27 +0000350 # Unpack work?
351 retrieved = unpack(format, got)[0]
352 verify(x == retrieved,
353 "'%s'-unpack of %r gave %r, not %r" %
354 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000355
Tim Peters17e17d42001-06-13 22:45:27 +0000356 # Adding any byte should cause a "too big" error.
357 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000358
Tim Peters17e17d42001-06-13 22:45:27 +0000359 else:
360 # x is out of range -- verify pack realizes that.
Bob Ippolitoaa70a172006-05-26 20:25:23 +0000361 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000362 if verbose:
363 print "Skipping buggy range check for code", code
364 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000365 deprecated_err(pack, ">" + code, x)
366 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000367
Tim Peters17e17d42001-06-13 22:45:27 +0000368 def run(self):
369 from random import randrange
370
371 # Create all interesting powers of 2.
372 values = []
373 for exp in range(self.bitsize + 3):
374 values.append(1L << exp)
375
376 # Add some random values.
377 for i in range(self.bitsize):
378 val = 0L
379 for j in range(self.bytesize):
380 val = (val << 8) | randrange(256)
381 values.append(val)
382
383 # Try all those, and their negations, and +-1 from them. Note
384 # that this tests all power-of-2 boundaries in range, and a few out
385 # of range, plus +-(2**n +- 1).
386 for base in values:
387 for val in -base, base:
388 for incr in -1, 0, 1:
389 x = val + incr
390 try:
391 x = int(x)
392 except OverflowError:
393 pass
394 self.test_one(x)
395
396 # Some error cases.
397 for direction in "<>":
398 for code in self.formatpair:
399 for badobject in "a string", 3+42j, randrange:
400 any_err(struct.pack, direction + code, badobject)
401
402for args in [("bB", 1),
403 ("hH", 2),
404 ("iI", 4),
405 ("lL", 4),
406 ("qQ", 8)]:
407 t = IntTester(*args)
408 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000409
410
411###########################################################################
412# The p ("Pascal string") code.
413
414def test_p_code():
415 for code, input, expected, expectedback in [
416 ('p','abc', '\x00', ''),
417 ('1p', 'abc', '\x00', ''),
418 ('2p', 'abc', '\x01a', 'a'),
419 ('3p', 'abc', '\x02ab', 'ab'),
420 ('4p', 'abc', '\x03abc', 'abc'),
421 ('5p', 'abc', '\x03abc\x00', 'abc'),
422 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
423 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
424 got = struct.pack(code, input)
425 if got != expected:
426 raise TestFailed("pack(%r, %r) == %r but expected %r" %
427 (code, input, got, expected))
428 (got,) = struct.unpack(code, got)
429 if got != expectedback:
430 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
431 (code, input, got, expectedback))
432
433test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000434
435
436###########################################################################
437# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
438# from the low-order discarded bits could propagate into the exponent
439# field, causing the result to be wrong by a factor of 2.
440
441def test_705836():
442 import math
443
444 for base in range(1, 33):
445 # smaller <- largest representable float less than base.
446 delta = 0.5
447 while base - delta / 2.0 != base:
448 delta /= 2.0
449 smaller = base - delta
450 # Packing this rounds away a solid string of trailing 1 bits.
451 packed = struct.pack("<f", smaller)
452 unpacked = struct.unpack("<f", packed)[0]
453 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
454 # 16, respectively.
455 verify(base == unpacked)
456 bigpacked = struct.pack(">f", smaller)
457 verify(bigpacked == string_reverse(packed),
458 ">f pack should be byte-reversal of <f pack")
459 unpacked = struct.unpack(">f", bigpacked)[0]
460 verify(base == unpacked)
461
462 # Largest finite IEEE single.
463 big = (1 << 24) - 1
464 big = math.ldexp(big, 127 - 23)
465 packed = struct.pack(">f", big)
466 unpacked = struct.unpack(">f", packed)[0]
467 verify(big == unpacked)
468
469 # The same, but tack on a 1 bit so it rounds up to infinity.
470 big = (1 << 25) - 1
471 big = math.ldexp(big, 127 - 24)
472 try:
473 packed = struct.pack(">f", big)
474 except OverflowError:
475 pass
476 else:
477 TestFailed("expected OverflowError")
478
479test_705836()
Bob Ippolitoeb621272006-05-24 15:32:06 +0000480
Bob Ippolitoeb621272006-05-24 15:32:06 +0000481def test_1229380():
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000482 import sys
Bob Ippolitoeb621272006-05-24 15:32:06 +0000483 for endian in ('', '>', '<'):
484 for cls in (int, long):
485 for fmt in ('B', 'H', 'I', 'L'):
Bob Ippolito2fd39772006-05-29 22:55:48 +0000486 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000487
Bob Ippolito2fd39772006-05-29 22:55:48 +0000488 deprecated_err(struct.pack, endian + 'B', cls(300))
489 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000490
Bob Ippolito2fd39772006-05-29 22:55:48 +0000491 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
492 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000493
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000494if PY_STRUCT_RANGE_CHECKING:
Bob Ippolitoeb621272006-05-24 15:32:06 +0000495 test_1229380()
Martin Blais2856e5f2006-05-26 12:03:27 +0000496
497class PackBufferTestCase(unittest.TestCase):
498 """
499 Test the packing methods that work on buffers.
500 """
501
502 def test_unpack_from( self ):
503 test_string = 'abcd01234'
504 fmt = '4s'
505 s = struct.Struct(fmt)
506 for cls in (str, buffer):
507 data = cls(test_string)
508 self.assertEquals(s.unpack_from(data), ('abcd',))
509 self.assertEquals(s.unpack_from(data, 2), ('cd01',))
510 self.assertEquals(s.unpack_from(data, 4), ('0123',))
511 for i in xrange(6):
512 self.assertEquals(s.unpack_from(data, i), (data[i:i+4],))
513 for i in xrange(6, len(test_string) + 1):
514 simple_err(s.unpack_from, data, i)
515 for cls in (str, buffer):
516 data = cls(test_string)
517 self.assertEquals(struct.unpack_from(fmt, data), ('abcd',))
518 self.assertEquals(struct.unpack_from(fmt, data, 2), ('cd01',))
519 self.assertEquals(struct.unpack_from(fmt, data, 4), ('0123',))
520 for i in xrange(6):
521 self.assertEquals(struct.unpack_from(fmt, data, i),
522 (data[i:i+4],))
523 for i in xrange(6, len(test_string) + 1):
524 simple_err(struct.unpack_from, fmt, data, i)
525
526 def test_pack_to( self ):
527 test_string = 'Reykjavik rocks, eow!'
528 writable_buf = array.array('c', ' '*100)
529 fmt = '21s'
530 s = struct.Struct(fmt)
531
532 # Test without offset
533 s.pack_to(writable_buf, 0, test_string)
534 from_buf = writable_buf.tostring()[:len(test_string)]
535 self.assertEquals(from_buf, test_string)
536
537 # Test with offset.
538 s.pack_to(writable_buf, 10, test_string)
539 from_buf = writable_buf.tostring()[:len(test_string)+10]
540 self.assertEquals(from_buf, (test_string[:10] + test_string))
541
542 # Go beyond boundaries.
543 small_buf = array.array('c', ' '*10)
544 self.assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
545 self.assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
546
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000547 def test_pack_to_fn( self ):
548 test_string = 'Reykjavik rocks, eow!'
549 writable_buf = array.array('c', ' '*100)
550 fmt = '21s'
551 pack_to = lambda *args: struct.pack_to(fmt, *args)
552
553 # Test without offset
554 pack_to(writable_buf, 0, test_string)
555 from_buf = writable_buf.tostring()[:len(test_string)]
556 self.assertEquals(from_buf, test_string)
557
558 # Test with offset.
559 pack_to(writable_buf, 10, test_string)
560 from_buf = writable_buf.tostring()[:len(test_string)+10]
561 self.assertEquals(from_buf, (test_string[:10] + test_string))
562
563 # Go beyond boundaries.
564 small_buf = array.array('c', ' '*10)
565 self.assertRaises(struct.error, pack_to, small_buf, 0, test_string)
566 self.assertRaises(struct.error, pack_to, small_buf, 2, test_string)
567
568
Martin Blais2856e5f2006-05-26 12:03:27 +0000569def test_main():
570 test.test_support.run_unittest(PackBufferTestCase)
Tim Petersfe98f962006-05-26 12:26:21 +0000571
Martin Blais2856e5f2006-05-26 12:03:27 +0000572if __name__ == "__main__":
573 test_main()