blob: 302698ba3a1f4fbcd7d15c9def71429c8064f0f3 [file] [log] [blame]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +00001from test.test_support import TestFailed, verbose, verify, vereq
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
Thomas Wouters0e3f5912006-08-11 14:57:12 +000018 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000019else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
21 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
22 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000023
Tim Peters17e17d42001-06-13 22:45:27 +000024def string_reverse(s):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000025 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000026
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 Wouters0e3f5912006-08-11 14:57:12 +000051def with_warning_restore(func):
52 def _with_warning_restore(*args, **kw):
53 # The `warnings` module doesn't have an advertised way to restore
54 # its filter list. Cheat.
55 save_warnings_filters = warnings.filters[:]
56 # 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__']
62 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
63 warnings.filterwarnings("error", r""".*format requires.*""",
64 DeprecationWarning)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000065 try:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000066 return func(*args, **kw)
67 finally:
68 warnings.filters[:] = save_warnings_filters[:]
69 return _with_warning_restore
70
71def deprecated_err(func, *args):
72 try:
73 func(*args)
74 except (struct.error, TypeError):
75 pass
76 except DeprecationWarning:
77 if not PY_STRUCT_OVERFLOW_MASKING:
78 raise TestFailed, "%s%s expected to raise struct.error" % (
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000079 func.__name__, args)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000080 else:
81 raise TestFailed, "%s%s did not raise error" % (
82 func.__name__, args)
83deprecated_err = with_warning_restore(deprecated_err)
84
Tim Peters17e17d42001-06-13 22:45:27 +000085
Tim Peters7b9542a2001-06-10 23:40:19 +000086simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000087
88sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000089if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000090 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000091
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000092fmt = 'cbxxxxxxhhhhiillffd'
93fmt3 = '3c3b18x12h6i6l6f3d'
94sz = struct.calcsize(fmt)
95sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000096if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000097 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
98 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000099
100simple_err(struct.pack, 'iii', 3)
101simple_err(struct.pack, 'i', 3, 3, 3)
102simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +0000103simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000104simple_err(struct.unpack, 'd', 'flap')
105s = struct.pack('ii', 1, 2)
106simple_err(struct.unpack, 'iii', s)
107simple_err(struct.unpack, 'i', s)
108
109c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +0000110b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +0000111h = 255
112i = 65535
113l = 65536
114f = 3.1415
115d = 3.1415
116
Guido van Rossum420c11c1997-01-03 00:09:46 +0000117for prefix in ('', '@', '<', '>', '=', '!'):
118 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000119 format = prefix + format
120 if verbose:
121 print "trying:", format
122 s = struct.pack(format, c, b, h, i, l, f, d)
123 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000124 if (cp != c or bp != b or hp != h or ip != i or lp != l or
125 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +0000126 # ^^^ calculate only to two decimal places
127 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
128 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000129
Guido van Rossum420c11c1997-01-03 00:09:46 +0000130# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000131
132# (format, argument, big-endian result, little-endian result, asymmetric)
133tests = [
134 ('c', 'a', 'a', 'a', 0),
135 ('xc', 'a', '\0a', '\0a', 0),
136 ('cx', 'a', 'a\0', 'a\0', 0),
137 ('s', 'a', 'a', 'a', 0),
138 ('0s', 'helloworld', '', '', 1),
139 ('1s', 'helloworld', 'h', 'h', 1),
140 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
141 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
142 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
143 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
144 ('b', 7, '\7', '\7', 0),
145 ('b', -7, '\371', '\371', 0),
146 ('B', 7, '\7', '\7', 0),
147 ('B', 249, '\371', '\371', 0),
148 ('h', 700, '\002\274', '\274\002', 0),
149 ('h', -700, '\375D', 'D\375', 0),
150 ('H', 700, '\002\274', '\274\002', 0),
151 ('H', 0x10000-700, '\375D', 'D\375', 0),
152 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
153 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
154 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
155 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
156 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
157 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
158 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
159 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000160 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
161 ('d', 2.0, '@\000\000\000\000\000\000\000',
162 '\000\000\000\000\000\000\000@', 0),
163 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
164 ('d', -2.0, '\300\000\000\000\000\000\000\000',
165 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000166]
167
Guido van Rossum2a378501996-12-31 17:25:47 +0000168for fmt, arg, big, lil, asy in tests:
169 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000170 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000171 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000172 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000173 res = struct.pack(xfmt, arg)
174 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000175 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
176 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000177 n = struct.calcsize(xfmt)
178 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000179 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
180 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000181 rev = struct.unpack(xfmt, res)[0]
182 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000183 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
184 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000185
Tim Peters7a3bfc32001-06-12 01:22:22 +0000186###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000187# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000188
189has_native_qQ = 1
190try:
191 struct.pack("q", 5)
192except struct.error:
193 has_native_qQ = 0
194
195if verbose:
196 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
197
Tim Peters7a3bfc32001-06-12 01:22:22 +0000198any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000199simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
200simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
201
Tim Peters7a3bfc32001-06-12 01:22:22 +0000202def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000203 bytes = struct.calcsize('q')
204 # The expected values here are in big-endian format, primarily because
205 # I'm on a little-endian machine and so this is the clearest way (for
206 # me) to force the code to get exercised.
207 for format, input, expected in (
208 ('q', -1, '\xff' * bytes),
209 ('q', 0, '\x00' * bytes),
210 ('Q', 0, '\x00' * bytes),
211 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
212 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
213 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
214 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000215 native_expected = bigendian_to_native(expected)
216 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000217 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000218 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000219 retrieved = struct.unpack(format, got)[0]
220 verify(retrieved == input,
221 "%r-unpack of %r gave %r, not %r" %
222 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000223
224if has_native_qQ:
225 test_native_qQ()
226
Tim Peters17e17d42001-06-13 22:45:27 +0000227###########################################################################
228# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000229
230import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000231
Tim Peters17e17d42001-06-13 22:45:27 +0000232class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000233
Tim Peters17e17d42001-06-13 22:45:27 +0000234 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000235 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
236 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
237 # reported by Mark Favas).
238 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000239
Tim Peters17e17d42001-06-13 22:45:27 +0000240 def __init__(self, formatpair, bytesize):
241 assert len(formatpair) == 2
242 self.formatpair = formatpair
243 for direction in "<>!=":
244 for code in formatpair:
245 format = direction + code
246 verify(struct.calcsize(format) == bytesize)
247 self.bytesize = bytesize
248 self.bitsize = bytesize * 8
249 self.signed_code, self.unsigned_code = formatpair
250 self.unsigned_min = 0
251 self.unsigned_max = 2L**self.bitsize - 1
252 self.signed_min = -(2L**(self.bitsize-1))
253 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000254
Tim Peters17e17d42001-06-13 22:45:27 +0000255 def test_one(self, x, pack=struct.pack,
256 unpack=struct.unpack,
257 unhexlify=binascii.unhexlify):
258 if verbose:
259 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000260
Tim Peters17e17d42001-06-13 22:45:27 +0000261 # Try signed.
262 code = self.signed_code
263 if self.signed_min <= x <= self.signed_max:
264 # Try big-endian.
265 expected = long(x)
266 if x < 0:
267 expected += 1L << self.bitsize
268 assert expected > 0
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000269 expected = hex(expected)[2:] # chop "0x"
Tim Peters17e17d42001-06-13 22:45:27 +0000270 if len(expected) & 1:
271 expected = "0" + expected
272 expected = unhexlify(expected)
273 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000274
Tim Peters17e17d42001-06-13 22:45:27 +0000275 # Pack work?
276 format = ">" + code
277 got = pack(format, x)
278 verify(got == expected,
279 "'%s'-pack of %r gave %r, not %r" %
280 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000281
Tim Peters17e17d42001-06-13 22:45:27 +0000282 # Unpack work?
283 retrieved = unpack(format, got)[0]
284 verify(x == retrieved,
285 "'%s'-unpack of %r gave %r, not %r" %
286 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000287
Tim Peters17e17d42001-06-13 22:45:27 +0000288 # Adding any byte should cause a "too big" error.
289 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000290
Tim Peters17e17d42001-06-13 22:45:27 +0000291 # Try little-endian.
292 format = "<" + code
293 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000294
Tim Peters17e17d42001-06-13 22:45:27 +0000295 # Pack work?
296 got = pack(format, x)
297 verify(got == expected,
298 "'%s'-pack of %r gave %r, not %r" %
299 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000300
Tim Peters17e17d42001-06-13 22:45:27 +0000301 # Unpack work?
302 retrieved = unpack(format, got)[0]
303 verify(x == retrieved,
304 "'%s'-unpack of %r gave %r, not %r" %
305 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000306
Tim Peters17e17d42001-06-13 22:45:27 +0000307 # Adding any byte should cause a "too big" error.
308 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000309
Tim Peters17e17d42001-06-13 22:45:27 +0000310 else:
311 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000312 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000313 if verbose:
314 print "Skipping buggy range check for code", code
315 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000316 deprecated_err(pack, ">" + code, x)
317 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000318
Tim Peters17e17d42001-06-13 22:45:27 +0000319 # Much the same for unsigned.
320 code = self.unsigned_code
321 if self.unsigned_min <= x <= self.unsigned_max:
322 # Try big-endian.
323 format = ">" + code
324 expected = long(x)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000325 expected = hex(expected)[2:] # chop "0x"
Tim Peters17e17d42001-06-13 22:45:27 +0000326 if len(expected) & 1:
327 expected = "0" + expected
328 expected = unhexlify(expected)
329 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000330
Tim Peters17e17d42001-06-13 22:45:27 +0000331 # Pack work?
332 got = pack(format, x)
333 verify(got == expected,
334 "'%s'-pack of %r gave %r, not %r" %
335 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000336
Tim Peters17e17d42001-06-13 22:45:27 +0000337 # Unpack work?
338 retrieved = unpack(format, got)[0]
339 verify(x == retrieved,
340 "'%s'-unpack of %r gave %r, not %r" %
341 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000342
Tim Peters17e17d42001-06-13 22:45:27 +0000343 # Adding any byte should cause a "too big" error.
344 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000345
Tim Peters17e17d42001-06-13 22:45:27 +0000346 # Try little-endian.
347 format = "<" + code
348 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000349
Tim Peters17e17d42001-06-13 22:45:27 +0000350 # Pack work?
351 got = pack(format, x)
352 verify(got == expected,
353 "'%s'-pack of %r gave %r, not %r" %
354 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000355
Tim Peters17e17d42001-06-13 22:45:27 +0000356 # Unpack work?
357 retrieved = unpack(format, got)[0]
358 verify(x == retrieved,
359 "'%s'-unpack of %r gave %r, not %r" %
360 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000361
Tim Peters17e17d42001-06-13 22:45:27 +0000362 # Adding any byte should cause a "too big" error.
363 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000364
Tim Peters17e17d42001-06-13 22:45:27 +0000365 else:
366 # x is out of range -- verify pack realizes that.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000367 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000368 if verbose:
369 print "Skipping buggy range check for code", code
370 else:
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000371 deprecated_err(pack, ">" + code, x)
372 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000373
Tim Peters17e17d42001-06-13 22:45:27 +0000374 def run(self):
375 from random import randrange
376
377 # Create all interesting powers of 2.
378 values = []
379 for exp in range(self.bitsize + 3):
380 values.append(1L << exp)
381
382 # Add some random values.
383 for i in range(self.bitsize):
384 val = 0L
385 for j in range(self.bytesize):
386 val = (val << 8) | randrange(256)
387 values.append(val)
388
389 # Try all those, and their negations, and +-1 from them. Note
390 # that this tests all power-of-2 boundaries in range, and a few out
391 # of range, plus +-(2**n +- 1).
392 for base in values:
393 for val in -base, base:
394 for incr in -1, 0, 1:
395 x = val + incr
396 try:
397 x = int(x)
398 except OverflowError:
399 pass
400 self.test_one(x)
401
402 # Some error cases.
403 for direction in "<>":
404 for code in self.formatpair:
405 for badobject in "a string", 3+42j, randrange:
406 any_err(struct.pack, direction + code, badobject)
407
408for args in [("bB", 1),
409 ("hH", 2),
410 ("iI", 4),
411 ("lL", 4),
412 ("qQ", 8)]:
413 t = IntTester(*args)
414 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000415
416
417###########################################################################
418# The p ("Pascal string") code.
419
420def test_p_code():
421 for code, input, expected, expectedback in [
422 ('p','abc', '\x00', ''),
423 ('1p', 'abc', '\x00', ''),
424 ('2p', 'abc', '\x01a', 'a'),
425 ('3p', 'abc', '\x02ab', 'ab'),
426 ('4p', 'abc', '\x03abc', 'abc'),
427 ('5p', 'abc', '\x03abc\x00', 'abc'),
428 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
429 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
430 got = struct.pack(code, input)
431 if got != expected:
432 raise TestFailed("pack(%r, %r) == %r but expected %r" %
433 (code, input, got, expected))
434 (got,) = struct.unpack(code, got)
435 if got != expectedback:
436 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
437 (code, input, got, expectedback))
438
439test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000440
441
442###########################################################################
443# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
444# from the low-order discarded bits could propagate into the exponent
445# field, causing the result to be wrong by a factor of 2.
446
447def test_705836():
448 import math
449
450 for base in range(1, 33):
451 # smaller <- largest representable float less than base.
452 delta = 0.5
453 while base - delta / 2.0 != base:
454 delta /= 2.0
455 smaller = base - delta
456 # Packing this rounds away a solid string of trailing 1 bits.
457 packed = struct.pack("<f", smaller)
458 unpacked = struct.unpack("<f", packed)[0]
459 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
460 # 16, respectively.
461 verify(base == unpacked)
462 bigpacked = struct.pack(">f", smaller)
463 verify(bigpacked == string_reverse(packed),
464 ">f pack should be byte-reversal of <f pack")
465 unpacked = struct.unpack(">f", bigpacked)[0]
466 verify(base == unpacked)
467
468 # Largest finite IEEE single.
469 big = (1 << 24) - 1
470 big = math.ldexp(big, 127 - 23)
471 packed = struct.pack(">f", big)
472 unpacked = struct.unpack(">f", packed)[0]
473 verify(big == unpacked)
474
475 # The same, but tack on a 1 bit so it rounds up to infinity.
476 big = (1 << 25) - 1
477 big = math.ldexp(big, 127 - 24)
478 try:
479 packed = struct.pack(">f", big)
480 except OverflowError:
481 pass
482 else:
483 TestFailed("expected OverflowError")
484
485test_705836()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000486
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000487###########################################################################
488# SF bug 1229380. No struct.pack exception for some out of range integers
489
Thomas Wouters477c8d52006-05-27 19:21:47 +0000490def test_1229380():
491 import sys
492 for endian in ('', '>', '<'):
493 for cls in (int, long):
494 for fmt in ('B', 'H', 'I', 'L'):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000495 deprecated_err(struct.pack, endian + fmt, cls(-1))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000496
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000497 deprecated_err(struct.pack, endian + 'B', cls(300))
498 deprecated_err(struct.pack, endian + 'H', cls(70000))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000500 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
501 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000502
503if PY_STRUCT_RANGE_CHECKING:
504 test_1229380()
505
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000506###########################################################################
507# SF bug 1530559. struct.pack raises TypeError where it used to convert.
508
509def check_float_coerce(format, number):
510 if PY_STRUCT_FLOAT_COERCE == 2:
511 # Test for pre-2.5 struct module
512 packed = struct.pack(format, number)
513 floored = struct.unpack(format, packed)[0]
514 if floored != int(number):
515 raise TestFailed("did not correcly coerce float to int")
516 return
517 try:
518 func(*args)
519 except (struct.error, TypeError):
520 if PY_STRUCT_FLOAT_COERCE:
521 raise TestFailed("expected DeprecationWarning for float coerce")
522 except DeprecationWarning:
523 if not PY_STRUCT_FLOAT_COERCE:
524 raise TestFailed("expected to raise struct.error for float coerce")
525 else:
526 raise TestFailed("did not raise error for float coerce")
527
528check_float_coerce = with_warning_restore(deprecated_err)
529
530def test_1530559():
531 for endian in ('', '>', '<'):
532 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
533 check_float_coerce(endian + fmt, 1.0)
534 check_float_coerce(endian + fmt, 1.5)
535
536test_1530559()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000538###########################################################################
539# Packing and unpacking to/from buffers.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000540
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000541# Copied and modified from unittest.
542def assertRaises(excClass, callableObj, *args, **kwargs):
543 try:
544 callableObj(*args, **kwargs)
545 except excClass:
546 return
547 else:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000548 raise TestFailed("%s not raised." % excClass)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000549
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000550def test_unpack_from():
551 test_string = 'abcd01234'
552 fmt = '4s'
553 s = struct.Struct(fmt)
554 for cls in (str, buffer):
555 data = cls(test_string)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000556 vereq(s.unpack_from(data), ('abcd',))
557 vereq(s.unpack_from(data, 2), ('cd01',))
558 vereq(s.unpack_from(data, 4), ('0123',))
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000559 for i in xrange(6):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000560 vereq(s.unpack_from(data, i), (data[i:i+4],))
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000561 for i in xrange(6, len(test_string) + 1):
562 simple_err(s.unpack_from, data, i)
563 for cls in (str, buffer):
564 data = cls(test_string)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000565 vereq(struct.unpack_from(fmt, data), ('abcd',))
566 vereq(struct.unpack_from(fmt, data, 2), ('cd01',))
567 vereq(struct.unpack_from(fmt, data, 4), ('0123',))
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000568 for i in xrange(6):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000569 vereq(struct.unpack_from(fmt, data, i), (data[i:i+4],))
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000570 for i in xrange(6, len(test_string) + 1):
571 simple_err(struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000572
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000573def test_pack_into():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000574 test_string = 'Reykjavik rocks, eow!'
575 writable_buf = array.array('c', ' '*100)
576 fmt = '21s'
577 s = struct.Struct(fmt)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000578
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000579 # Test without offset
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000580 s.pack_into(writable_buf, 0, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000581 from_buf = writable_buf.tostring()[:len(test_string)]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000582 vereq(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000583
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000584 # Test with offset.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000585 s.pack_into(writable_buf, 10, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000586 from_buf = writable_buf.tostring()[:len(test_string)+10]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000587 vereq(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000588
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000589 # Go beyond boundaries.
590 small_buf = array.array('c', ' '*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000591 assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
592 assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000593
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000594def test_pack_into_fn():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000595 test_string = 'Reykjavik rocks, eow!'
596 writable_buf = array.array('c', ' '*100)
597 fmt = '21s'
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000598 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000599
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000600 # Test without offset.
601 pack_into(writable_buf, 0, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000602 from_buf = writable_buf.tostring()[:len(test_string)]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000603 vereq(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000604
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000605 # Test with offset.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000606 pack_into(writable_buf, 10, test_string)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000607 from_buf = writable_buf.tostring()[:len(test_string)+10]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000608 vereq(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000609
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000610 # Go beyond boundaries.
611 small_buf = array.array('c', ' '*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000612 assertRaises(struct.error, pack_into, small_buf, 0, test_string)
613 assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000614
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000615
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000616# Test methods to pack and unpack from buffers rather than strings.
617test_unpack_from()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000618test_pack_into()
619test_pack_into_fn()