blob: f13515000f8a69b723ed4ec83d1ddd4d663cfdba [file] [log] [blame]
Tim Peters852eae12006-06-05 20:48:49 +00001from test.test_support import TestFailed, verbose, verify, vereq
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
Martin v. Löwis46d41062008-12-13 14:34:06 +00006warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
7 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
11del sys
12verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
13 "bigendian determination appears wrong")
14
Bob Ippolito2fd39772006-05-29 22:55:48 +000015try:
16 import _struct
17except ImportError:
18 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000019 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000020 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000021else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000022 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
23 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
24 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000025
Tim Peters17e17d42001-06-13 22:45:27 +000026def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000027 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000028
29def bigendian_to_native(value):
30 if ISBIGENDIAN:
31 return value
32 else:
33 return string_reverse(value)
34
Barry Warsaw07a0eec1996-12-12 23:34:06 +000035def simple_err(func, *args):
36 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000037 func(*args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000038 except struct.error:
Guido van Rossum41360a41998-03-26 19:42:58 +000039 pass
Barry Warsaw07a0eec1996-12-12 23:34:06 +000040 else:
Guido van Rossum41360a41998-03-26 19:42:58 +000041 raise TestFailed, "%s%s did not raise struct.error" % (
42 func.__name__, args)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000043
Tim Peters7a3bfc32001-06-12 01:22:22 +000044def any_err(func, *args):
45 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +000046 func(*args)
Bob Ippolito2fd39772006-05-29 22:55:48 +000047 except (struct.error, TypeError):
Tim Peters7a3bfc32001-06-12 01:22:22 +000048 pass
49 else:
50 raise TestFailed, "%s%s did not raise error" % (
51 func.__name__, args)
Tim Peters7a3bfc32001-06-12 01:22:22 +000052
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000053def with_warning_restore(func):
54 def _with_warning_restore(*args, **kw):
55 # The `warnings` module doesn't have an advertised way to restore
56 # its filter list. Cheat.
57 save_warnings_filters = warnings.filters[:]
58 # Grrr, we need this function to warn every time. Without removing
59 # the warningregistry, running test_tarfile then test_struct would fail
60 # on 64-bit platforms.
61 globals = func.func_globals
62 if '__warningregistry__' in globals:
63 del globals['__warningregistry__']
64 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
65 warnings.filterwarnings("error", r""".*format requires.*""",
66 DeprecationWarning)
Bob Ippolito2fd39772006-05-29 22:55:48 +000067 try:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000068 return func(*args, **kw)
69 finally:
70 warnings.filters[:] = save_warnings_filters[:]
71 return _with_warning_restore
72
73def deprecated_err(func, *args):
74 try:
75 func(*args)
76 except (struct.error, TypeError):
77 pass
78 except DeprecationWarning:
79 if not PY_STRUCT_OVERFLOW_MASKING:
80 raise TestFailed, "%s%s expected to raise struct.error" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000081 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000082 else:
83 raise TestFailed, "%s%s did not raise error" % (
84 func.__name__, args)
85deprecated_err = with_warning_restore(deprecated_err)
86
Tim Peters17e17d42001-06-13 22:45:27 +000087
Tim Peters7b9542a2001-06-10 23:40:19 +000088simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000089
90sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000091if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000092 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000093
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000094fmt = 'cbxxxxxxhhhhiillffd'
95fmt3 = '3c3b18x12h6i6l6f3d'
96sz = struct.calcsize(fmt)
97sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000098if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000099 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
100 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000101
102simple_err(struct.pack, 'iii', 3)
103simple_err(struct.pack, 'i', 3, 3, 3)
104simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +0000105simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000106simple_err(struct.unpack, 'd', 'flap')
107s = struct.pack('ii', 1, 2)
108simple_err(struct.unpack, 'iii', s)
109simple_err(struct.unpack, 'i', s)
110
111c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +0000112b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000113h = 255
114i = 65535
115l = 65536
116f = 3.1415
117d = 3.1415
118
Guido van Rossum420c11c1997-01-03 00:09:46 +0000119for prefix in ('', '@', '<', '>', '=', '!'):
120 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000121 format = prefix + format
122 if verbose:
123 print "trying:", format
124 s = struct.pack(format, c, b, h, i, l, f, d)
125 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000126 if (cp != c or bp != b or hp != h or ip != i or lp != l or
127 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +0000128 # ^^^ calculate only to two decimal places
129 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
130 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000131
Guido van Rossum420c11c1997-01-03 00:09:46 +0000132# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000133
134# (format, argument, big-endian result, little-endian result, asymmetric)
135tests = [
136 ('c', 'a', 'a', 'a', 0),
137 ('xc', 'a', '\0a', '\0a', 0),
138 ('cx', 'a', 'a\0', 'a\0', 0),
139 ('s', 'a', 'a', 'a', 0),
140 ('0s', 'helloworld', '', '', 1),
141 ('1s', 'helloworld', 'h', 'h', 1),
142 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
143 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
144 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
145 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
146 ('b', 7, '\7', '\7', 0),
147 ('b', -7, '\371', '\371', 0),
148 ('B', 7, '\7', '\7', 0),
149 ('B', 249, '\371', '\371', 0),
150 ('h', 700, '\002\274', '\274\002', 0),
151 ('h', -700, '\375D', 'D\375', 0),
152 ('H', 700, '\002\274', '\274\002', 0),
153 ('H', 0x10000-700, '\375D', 'D\375', 0),
154 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
155 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
156 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
157 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
158 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
159 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
160 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
161 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000162 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
163 ('d', 2.0, '@\000\000\000\000\000\000\000',
164 '\000\000\000\000\000\000\000@', 0),
165 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
166 ('d', -2.0, '\300\000\000\000\000\000\000\000',
167 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000168]
169
Guido van Rossum2a378501996-12-31 17:25:47 +0000170for fmt, arg, big, lil, asy in tests:
171 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000172 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000173 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000174 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000175 res = struct.pack(xfmt, arg)
176 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000177 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
178 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000179 n = struct.calcsize(xfmt)
180 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000181 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
182 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000183 rev = struct.unpack(xfmt, res)[0]
184 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000185 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
186 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000187
Tim Peters7a3bfc32001-06-12 01:22:22 +0000188###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000189# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000190
191has_native_qQ = 1
192try:
193 struct.pack("q", 5)
194except struct.error:
195 has_native_qQ = 0
196
197if verbose:
198 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
199
Tim Peters7a3bfc32001-06-12 01:22:22 +0000200any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000201simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
202simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
203
Tim Peters7a3bfc32001-06-12 01:22:22 +0000204def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000205 bytes = struct.calcsize('q')
206 # The expected values here are in big-endian format, primarily because
207 # I'm on a little-endian machine and so this is the clearest way (for
208 # me) to force the code to get exercised.
209 for format, input, expected in (
210 ('q', -1, '\xff' * bytes),
211 ('q', 0, '\x00' * bytes),
212 ('Q', 0, '\x00' * bytes),
213 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
214 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
215 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
216 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000217 native_expected = bigendian_to_native(expected)
218 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000219 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000220 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000221 retrieved = struct.unpack(format, got)[0]
222 verify(retrieved == input,
223 "%r-unpack of %r gave %r, not %r" %
224 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000225
226if has_native_qQ:
227 test_native_qQ()
228
Tim Peters17e17d42001-06-13 22:45:27 +0000229###########################################################################
230# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000231
232import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000233
Tim Peters17e17d42001-06-13 22:45:27 +0000234class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000235
Tim Peters17e17d42001-06-13 22:45:27 +0000236 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000237 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
238 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
239 # reported by Mark Favas).
240 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000241
Tim Peters17e17d42001-06-13 22:45:27 +0000242 def __init__(self, formatpair, bytesize):
243 assert len(formatpair) == 2
244 self.formatpair = formatpair
245 for direction in "<>!=":
246 for code in formatpair:
247 format = direction + code
248 verify(struct.calcsize(format) == bytesize)
249 self.bytesize = bytesize
250 self.bitsize = bytesize * 8
251 self.signed_code, self.unsigned_code = formatpair
252 self.unsigned_min = 0
253 self.unsigned_max = 2L**self.bitsize - 1
254 self.signed_min = -(2L**(self.bitsize-1))
255 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000256
Tim Peters17e17d42001-06-13 22:45:27 +0000257 def test_one(self, x, pack=struct.pack,
258 unpack=struct.unpack,
259 unhexlify=binascii.unhexlify):
260 if verbose:
261 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000262
Tim Peters17e17d42001-06-13 22:45:27 +0000263 # Try signed.
264 code = self.signed_code
265 if self.signed_min <= x <= self.signed_max:
266 # Try big-endian.
267 expected = long(x)
268 if x < 0:
269 expected += 1L << self.bitsize
270 assert expected > 0
271 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
272 if len(expected) & 1:
273 expected = "0" + expected
274 expected = unhexlify(expected)
275 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000276
Tim Peters17e17d42001-06-13 22:45:27 +0000277 # Pack work?
278 format = ">" + code
279 got = pack(format, x)
280 verify(got == expected,
281 "'%s'-pack of %r gave %r, not %r" %
282 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000283
Tim Peters17e17d42001-06-13 22:45:27 +0000284 # Unpack work?
285 retrieved = unpack(format, got)[0]
286 verify(x == retrieved,
287 "'%s'-unpack of %r gave %r, not %r" %
288 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000289
Tim Peters17e17d42001-06-13 22:45:27 +0000290 # Adding any byte should cause a "too big" error.
291 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000292
Tim Peters17e17d42001-06-13 22:45:27 +0000293 # Try little-endian.
294 format = "<" + code
295 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000296
Tim Peters17e17d42001-06-13 22:45:27 +0000297 # Pack work?
298 got = pack(format, x)
299 verify(got == expected,
300 "'%s'-pack of %r gave %r, not %r" %
301 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000302
Tim Peters17e17d42001-06-13 22:45:27 +0000303 # Unpack work?
304 retrieved = unpack(format, got)[0]
305 verify(x == retrieved,
306 "'%s'-unpack of %r gave %r, not %r" %
307 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000308
Tim Peters17e17d42001-06-13 22:45:27 +0000309 # Adding any byte should cause a "too big" error.
310 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000311
Tim Peters17e17d42001-06-13 22:45:27 +0000312 else:
313 # x is out of range -- verify pack realizes that.
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000314 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000315 if verbose:
316 print "Skipping buggy range check for code", code
317 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000318 deprecated_err(pack, ">" + code, x)
319 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000320
Tim Peters17e17d42001-06-13 22:45:27 +0000321 # Much the same for unsigned.
322 code = self.unsigned_code
323 if self.unsigned_min <= x <= self.unsigned_max:
324 # Try big-endian.
325 format = ">" + code
326 expected = long(x)
327 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
328 if len(expected) & 1:
329 expected = "0" + expected
330 expected = unhexlify(expected)
331 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000332
Tim Peters17e17d42001-06-13 22:45:27 +0000333 # Pack work?
334 got = pack(format, x)
335 verify(got == expected,
336 "'%s'-pack of %r gave %r, not %r" %
337 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000338
Tim Peters17e17d42001-06-13 22:45:27 +0000339 # Unpack work?
340 retrieved = unpack(format, got)[0]
341 verify(x == retrieved,
342 "'%s'-unpack of %r gave %r, not %r" %
343 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000344
Tim Peters17e17d42001-06-13 22:45:27 +0000345 # Adding any byte should cause a "too big" error.
346 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000347
Tim Peters17e17d42001-06-13 22:45:27 +0000348 # Try little-endian.
349 format = "<" + code
350 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000351
Tim Peters17e17d42001-06-13 22:45:27 +0000352 # Pack work?
353 got = pack(format, x)
354 verify(got == expected,
355 "'%s'-pack of %r gave %r, not %r" %
356 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000357
Tim Peters17e17d42001-06-13 22:45:27 +0000358 # Unpack work?
359 retrieved = unpack(format, got)[0]
360 verify(x == retrieved,
361 "'%s'-unpack of %r gave %r, not %r" %
362 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000363
Tim Peters17e17d42001-06-13 22:45:27 +0000364 # Adding any byte should cause a "too big" error.
365 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000366
Tim Peters17e17d42001-06-13 22:45:27 +0000367 else:
368 # x is out of range -- verify pack realizes that.
Bob Ippolitoaa70a172006-05-26 20:25:23 +0000369 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000370 if verbose:
371 print "Skipping buggy range check for code", code
372 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000373 deprecated_err(pack, ">" + code, x)
374 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000375
Tim Peters17e17d42001-06-13 22:45:27 +0000376 def run(self):
377 from random import randrange
378
379 # Create all interesting powers of 2.
380 values = []
381 for exp in range(self.bitsize + 3):
382 values.append(1L << exp)
383
384 # Add some random values.
385 for i in range(self.bitsize):
386 val = 0L
387 for j in range(self.bytesize):
388 val = (val << 8) | randrange(256)
389 values.append(val)
390
391 # Try all those, and their negations, and +-1 from them. Note
392 # that this tests all power-of-2 boundaries in range, and a few out
393 # of range, plus +-(2**n +- 1).
394 for base in values:
395 for val in -base, base:
396 for incr in -1, 0, 1:
397 x = val + incr
398 try:
399 x = int(x)
400 except OverflowError:
401 pass
402 self.test_one(x)
403
404 # Some error cases.
405 for direction in "<>":
406 for code in self.formatpair:
407 for badobject in "a string", 3+42j, randrange:
408 any_err(struct.pack, direction + code, badobject)
409
410for args in [("bB", 1),
411 ("hH", 2),
412 ("iI", 4),
413 ("lL", 4),
414 ("qQ", 8)]:
415 t = IntTester(*args)
416 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000417
418
419###########################################################################
420# The p ("Pascal string") code.
421
422def test_p_code():
423 for code, input, expected, expectedback in [
424 ('p','abc', '\x00', ''),
425 ('1p', 'abc', '\x00', ''),
426 ('2p', 'abc', '\x01a', 'a'),
427 ('3p', 'abc', '\x02ab', 'ab'),
428 ('4p', 'abc', '\x03abc', 'abc'),
429 ('5p', 'abc', '\x03abc\x00', 'abc'),
430 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
431 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
432 got = struct.pack(code, input)
433 if got != expected:
434 raise TestFailed("pack(%r, %r) == %r but expected %r" %
435 (code, input, got, expected))
436 (got,) = struct.unpack(code, got)
437 if got != expectedback:
438 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
439 (code, input, got, expectedback))
440
441test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000442
443
444###########################################################################
445# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
446# from the low-order discarded bits could propagate into the exponent
447# field, causing the result to be wrong by a factor of 2.
448
449def test_705836():
450 import math
451
452 for base in range(1, 33):
453 # smaller <- largest representable float less than base.
454 delta = 0.5
455 while base - delta / 2.0 != base:
456 delta /= 2.0
457 smaller = base - delta
458 # Packing this rounds away a solid string of trailing 1 bits.
459 packed = struct.pack("<f", smaller)
460 unpacked = struct.unpack("<f", packed)[0]
461 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
462 # 16, respectively.
463 verify(base == unpacked)
464 bigpacked = struct.pack(">f", smaller)
465 verify(bigpacked == string_reverse(packed),
466 ">f pack should be byte-reversal of <f pack")
467 unpacked = struct.unpack(">f", bigpacked)[0]
468 verify(base == unpacked)
469
470 # Largest finite IEEE single.
471 big = (1 << 24) - 1
472 big = math.ldexp(big, 127 - 23)
473 packed = struct.pack(">f", big)
474 unpacked = struct.unpack(">f", packed)[0]
475 verify(big == unpacked)
476
477 # The same, but tack on a 1 bit so it rounds up to infinity.
478 big = (1 << 25) - 1
479 big = math.ldexp(big, 127 - 24)
480 try:
481 packed = struct.pack(">f", big)
482 except OverflowError:
483 pass
484 else:
485 TestFailed("expected OverflowError")
486
487test_705836()
Bob Ippolitoeb621272006-05-24 15:32:06 +0000488
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000489###########################################################################
490# SF bug 1229380. No struct.pack exception for some out of range integers
491
Bob Ippolitoeb621272006-05-24 15:32:06 +0000492def test_1229380():
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000493 import sys
Bob Ippolitoeb621272006-05-24 15:32:06 +0000494 for endian in ('', '>', '<'):
495 for cls in (int, long):
496 for fmt in ('B', 'H', 'I', 'L'):
Bob Ippolito2fd39772006-05-29 22:55:48 +0000497 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000498
Bob Ippolito2fd39772006-05-29 22:55:48 +0000499 deprecated_err(struct.pack, endian + 'B', cls(300))
500 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000501
Bob Ippolito2fd39772006-05-29 22:55:48 +0000502 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
503 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000504
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000505if PY_STRUCT_RANGE_CHECKING:
Bob Ippolitoeb621272006-05-24 15:32:06 +0000506 test_1229380()
Martin Blais2856e5f2006-05-26 12:03:27 +0000507
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000508###########################################################################
509# SF bug 1530559. struct.pack raises TypeError where it used to convert.
510
511def check_float_coerce(format, number):
512 if PY_STRUCT_FLOAT_COERCE == 2:
513 # Test for pre-2.5 struct module
514 packed = struct.pack(format, number)
515 floored = struct.unpack(format, packed)[0]
516 if floored != int(number):
517 raise TestFailed("did not correcly coerce float to int")
518 return
519 try:
520 func(*args)
521 except (struct.error, TypeError):
522 if PY_STRUCT_FLOAT_COERCE:
523 raise TestFailed("expected DeprecationWarning for float coerce")
524 except DeprecationWarning:
525 if not PY_STRUCT_FLOAT_COERCE:
526 raise TestFailed("expected to raise struct.error for float coerce")
527 else:
528 raise TestFailed("did not raise error for float coerce")
529
530check_float_coerce = with_warning_restore(deprecated_err)
531
532def test_1530559():
533 for endian in ('', '>', '<'):
534 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
535 check_float_coerce(endian + fmt, 1.0)
536 check_float_coerce(endian + fmt, 1.5)
537
538test_1530559()
Martin Blais2856e5f2006-05-26 12:03:27 +0000539
Martin v. Löwis46d41062008-12-13 14:34:06 +0000540## Issue 4228. Packing a negative unsigned long warns,
541# but then still should give a value with the
542# topmost bit set.
543
544def test_issue4228():
545 # Packing a long may yield either 32 or 64 bits
546 x = struct.pack('L', -1)[:4]
547 vereq(x, '\xff'*4)
548
549test_issue4228()
550
Martin Blais7f7386c2006-06-02 13:03:43 +0000551###########################################################################
552# Packing and unpacking to/from buffers.
Martin Blais2856e5f2006-05-26 12:03:27 +0000553
Martin Blais7f7386c2006-06-02 13:03:43 +0000554# Copied and modified from unittest.
555def assertRaises(excClass, callableObj, *args, **kwargs):
556 try:
557 callableObj(*args, **kwargs)
558 except excClass:
559 return
560 else:
Tim Peters852eae12006-06-05 20:48:49 +0000561 raise TestFailed("%s not raised." % excClass)
Martin Blais2856e5f2006-05-26 12:03:27 +0000562
Martin Blais7f7386c2006-06-02 13:03:43 +0000563def test_unpack_from():
564 test_string = 'abcd01234'
565 fmt = '4s'
566 s = struct.Struct(fmt)
567 for cls in (str, buffer):
568 data = cls(test_string)
Tim Peters852eae12006-06-05 20:48:49 +0000569 vereq(s.unpack_from(data), ('abcd',))
570 vereq(s.unpack_from(data, 2), ('cd01',))
571 vereq(s.unpack_from(data, 4), ('0123',))
Martin Blais7f7386c2006-06-02 13:03:43 +0000572 for i in xrange(6):
Tim Peters852eae12006-06-05 20:48:49 +0000573 vereq(s.unpack_from(data, i), (data[i:i+4],))
Martin Blais7f7386c2006-06-02 13:03:43 +0000574 for i in xrange(6, len(test_string) + 1):
575 simple_err(s.unpack_from, data, i)
576 for cls in (str, buffer):
577 data = cls(test_string)
Tim Peters852eae12006-06-05 20:48:49 +0000578 vereq(struct.unpack_from(fmt, data), ('abcd',))
579 vereq(struct.unpack_from(fmt, data, 2), ('cd01',))
580 vereq(struct.unpack_from(fmt, data, 4), ('0123',))
Martin Blais7f7386c2006-06-02 13:03:43 +0000581 for i in xrange(6):
Tim Peters852eae12006-06-05 20:48:49 +0000582 vereq(struct.unpack_from(fmt, data, i), (data[i:i+4],))
Martin Blais7f7386c2006-06-02 13:03:43 +0000583 for i in xrange(6, len(test_string) + 1):
584 simple_err(struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000585
Martin Blaisaf2ae722006-06-04 13:49:49 +0000586def test_pack_into():
Martin Blais7f7386c2006-06-02 13:03:43 +0000587 test_string = 'Reykjavik rocks, eow!'
588 writable_buf = array.array('c', ' '*100)
589 fmt = '21s'
590 s = struct.Struct(fmt)
Martin Blais2856e5f2006-05-26 12:03:27 +0000591
Martin Blais7f7386c2006-06-02 13:03:43 +0000592 # Test without offset
Martin Blaisaf2ae722006-06-04 13:49:49 +0000593 s.pack_into(writable_buf, 0, test_string)
Martin Blais7f7386c2006-06-02 13:03:43 +0000594 from_buf = writable_buf.tostring()[:len(test_string)]
Tim Peters852eae12006-06-05 20:48:49 +0000595 vereq(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000596
Martin Blais7f7386c2006-06-02 13:03:43 +0000597 # Test with offset.
Martin Blaisaf2ae722006-06-04 13:49:49 +0000598 s.pack_into(writable_buf, 10, test_string)
Martin Blais7f7386c2006-06-02 13:03:43 +0000599 from_buf = writable_buf.tostring()[:len(test_string)+10]
Tim Peters852eae12006-06-05 20:48:49 +0000600 vereq(from_buf, test_string[:10] + test_string)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000601
Martin Blais7f7386c2006-06-02 13:03:43 +0000602 # Go beyond boundaries.
603 small_buf = array.array('c', ' '*10)
Martin Blaisaf2ae722006-06-04 13:49:49 +0000604 assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
605 assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000606
Martin Blaisaf2ae722006-06-04 13:49:49 +0000607def test_pack_into_fn():
Martin Blais7f7386c2006-06-02 13:03:43 +0000608 test_string = 'Reykjavik rocks, eow!'
609 writable_buf = array.array('c', ' '*100)
610 fmt = '21s'
Martin Blaisaf2ae722006-06-04 13:49:49 +0000611 pack_into = lambda *args: struct.pack_into(fmt, *args)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000612
Tim Peters852eae12006-06-05 20:48:49 +0000613 # Test without offset.
Martin Blaisaf2ae722006-06-04 13:49:49 +0000614 pack_into(writable_buf, 0, test_string)
Martin Blais7f7386c2006-06-02 13:03:43 +0000615 from_buf = writable_buf.tostring()[:len(test_string)]
Tim Peters852eae12006-06-05 20:48:49 +0000616 vereq(from_buf, test_string)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000617
Martin Blais7f7386c2006-06-02 13:03:43 +0000618 # Test with offset.
Martin Blaisaf2ae722006-06-04 13:49:49 +0000619 pack_into(writable_buf, 10, test_string)
Martin Blais7f7386c2006-06-02 13:03:43 +0000620 from_buf = writable_buf.tostring()[:len(test_string)+10]
Tim Peters852eae12006-06-05 20:48:49 +0000621 vereq(from_buf, test_string[:10] + test_string)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000622
Martin Blais7f7386c2006-06-02 13:03:43 +0000623 # Go beyond boundaries.
624 small_buf = array.array('c', ' '*10)
Martin Blaisaf2ae722006-06-04 13:49:49 +0000625 assertRaises(struct.error, pack_into, small_buf, 0, test_string)
626 assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Tim Petersfe98f962006-05-26 12:26:21 +0000627
Raymond Hettinger3608f052007-04-04 20:32:03 +0000628def test_unpack_with_buffer():
629 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
630 data = array.array('B', '\x12\x34\x56\x78')
631 value, = struct.unpack('>I', data)
632 vereq(value, 0x12345678)
Tim Petersc65a13f2006-06-04 01:22:53 +0000633
Martin Blais7f7386c2006-06-02 13:03:43 +0000634# Test methods to pack and unpack from buffers rather than strings.
635test_unpack_from()
Martin Blaisaf2ae722006-06-04 13:49:49 +0000636test_pack_into()
637test_pack_into_fn()
Raymond Hettinger3608f052007-04-04 20:32:03 +0000638test_unpack_with_buffer()