blob: da7f40c6bbc00a4aba52ef9c6696d0183b13c4b0 [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[:]
Bob Ippolito2fd39772006-05-29 22:55:48 +000056 warnings.filterwarnings("error", r"""^struct.*""", DeprecationWarning)
Tim Petersaba19bc2006-05-30 02:25:25 +000057 warnings.filterwarnings("error", r""".*format requires.*""",
58 DeprecationWarning)
Bob Ippolito2fd39772006-05-29 22:55:48 +000059 try:
60 try:
61 func(*args)
62 except (struct.error, TypeError):
63 pass
64 except DeprecationWarning:
Bob Ippolito4182a752006-05-30 17:37:54 +000065 if not PY_STRUCT_OVERFLOW_MASKING:
Bob Ippolito2fd39772006-05-29 22:55:48 +000066 raise TestFailed, "%s%s expected to raise struct.error" % (
67 func.__name__, args)
68 else:
69 raise TestFailed, "%s%s did not raise error" % (
70 func.__name__, args)
71 finally:
Tim Petersaba19bc2006-05-30 02:25:25 +000072 warnings.filters[:] = save_warnings_filters[:]
Tim Peters17e17d42001-06-13 22:45:27 +000073
Tim Peters7b9542a2001-06-10 23:40:19 +000074simple_err(struct.calcsize, 'Z')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000075
76sz = struct.calcsize('i')
Fred Drake132dce22000-12-12 23:11:42 +000077if sz * 3 != struct.calcsize('iii'):
Guido van Rossum2a378501996-12-31 17:25:47 +000078 raise TestFailed, 'inconsistent sizes'
Barry Warsaw07a0eec1996-12-12 23:34:06 +000079
Guido van Rossum04ebf5c1997-01-03 19:00:37 +000080fmt = 'cbxxxxxxhhhhiillffd'
81fmt3 = '3c3b18x12h6i6l6f3d'
82sz = struct.calcsize(fmt)
83sz3 = struct.calcsize(fmt3)
Fred Drake132dce22000-12-12 23:11:42 +000084if sz * 3 != sz3:
Walter Dörwald70a6b492004-02-12 17:35:32 +000085 raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
86 fmt, sz, 3*sz, fmt3, sz3)
Barry Warsaw07a0eec1996-12-12 23:34:06 +000087
88simple_err(struct.pack, 'iii', 3)
89simple_err(struct.pack, 'i', 3, 3, 3)
90simple_err(struct.pack, 'i', 'foo')
Armin Rigo9f904392004-09-27 19:27:51 +000091simple_err(struct.pack, 'P', 'foo')
Barry Warsaw07a0eec1996-12-12 23:34:06 +000092simple_err(struct.unpack, 'd', 'flap')
93s = struct.pack('ii', 1, 2)
94simple_err(struct.unpack, 'iii', s)
95simple_err(struct.unpack, 'i', s)
96
97c = 'a'
Guido van Rossum2a378501996-12-31 17:25:47 +000098b = 1
Barry Warsaw07a0eec1996-12-12 23:34:06 +000099h = 255
100i = 65535
101l = 65536
102f = 3.1415
103d = 3.1415
104
Guido van Rossum420c11c1997-01-03 00:09:46 +0000105for prefix in ('', '@', '<', '>', '=', '!'):
106 for format in ('xcbhilfd', 'xcBHILfd'):
Guido van Rossum41360a41998-03-26 19:42:58 +0000107 format = prefix + format
108 if verbose:
109 print "trying:", format
110 s = struct.pack(format, c, b, h, i, l, f, d)
111 cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
Fred Drake132dce22000-12-12 23:11:42 +0000112 if (cp != c or bp != b or hp != h or ip != i or lp != l or
113 int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
Guido van Rossum41360a41998-03-26 19:42:58 +0000114 # ^^^ calculate only to two decimal places
115 raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
116 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
Guido van Rossum2a378501996-12-31 17:25:47 +0000117
Guido van Rossum420c11c1997-01-03 00:09:46 +0000118# Test some of the new features in detail
Guido van Rossum2a378501996-12-31 17:25:47 +0000119
120# (format, argument, big-endian result, little-endian result, asymmetric)
121tests = [
122 ('c', 'a', 'a', 'a', 0),
123 ('xc', 'a', '\0a', '\0a', 0),
124 ('cx', 'a', 'a\0', 'a\0', 0),
125 ('s', 'a', 'a', 'a', 0),
126 ('0s', 'helloworld', '', '', 1),
127 ('1s', 'helloworld', 'h', 'h', 1),
128 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
129 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
130 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
131 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
132 ('b', 7, '\7', '\7', 0),
133 ('b', -7, '\371', '\371', 0),
134 ('B', 7, '\7', '\7', 0),
135 ('B', 249, '\371', '\371', 0),
136 ('h', 700, '\002\274', '\274\002', 0),
137 ('h', -700, '\375D', 'D\375', 0),
138 ('H', 700, '\002\274', '\274\002', 0),
139 ('H', 0x10000-700, '\375D', 'D\375', 0),
140 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
141 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
142 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
143 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
144 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
145 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
146 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
147 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
Guido van Rossum420c11c1997-01-03 00:09:46 +0000148 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
149 ('d', 2.0, '@\000\000\000\000\000\000\000',
150 '\000\000\000\000\000\000\000@', 0),
151 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
152 ('d', -2.0, '\300\000\000\000\000\000\000\000',
153 '\000\000\000\000\000\000\000\300', 0),
Guido van Rossum2a378501996-12-31 17:25:47 +0000154]
155
Guido van Rossum2a378501996-12-31 17:25:47 +0000156for fmt, arg, big, lil, asy in tests:
157 if verbose:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000158 print "%r %r %r %r" % (fmt, arg, big, lil)
Guido van Rossum2a378501996-12-31 17:25:47 +0000159 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
Tim Peters17e17d42001-06-13 22:45:27 +0000160 ('='+fmt, ISBIGENDIAN and big or lil)]:
Guido van Rossum41360a41998-03-26 19:42:58 +0000161 res = struct.pack(xfmt, arg)
162 if res != exp:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000163 raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
164 fmt, arg, res, exp)
Guido van Rossum41360a41998-03-26 19:42:58 +0000165 n = struct.calcsize(xfmt)
166 if n != len(res):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000167 raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
168 xfmt, n, len(res))
Guido van Rossum41360a41998-03-26 19:42:58 +0000169 rev = struct.unpack(xfmt, res)[0]
170 if rev != arg and not asy:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000171 raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
172 fmt, res, rev, arg)
Tim Peters7b9542a2001-06-10 23:40:19 +0000173
Tim Peters7a3bfc32001-06-12 01:22:22 +0000174###########################################################################
Tim Peters17e17d42001-06-13 22:45:27 +0000175# Simple native q/Q tests.
Tim Peters7b9542a2001-06-10 23:40:19 +0000176
177has_native_qQ = 1
178try:
179 struct.pack("q", 5)
180except struct.error:
181 has_native_qQ = 0
182
183if verbose:
184 print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
185
Tim Peters7a3bfc32001-06-12 01:22:22 +0000186any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless
Tim Peters7b9542a2001-06-10 23:40:19 +0000187simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless
188simple_err(struct.pack, "Q", "a") # ditto, but 'Q'
189
Tim Peters7a3bfc32001-06-12 01:22:22 +0000190def test_native_qQ():
Tim Peters7b9542a2001-06-10 23:40:19 +0000191 bytes = struct.calcsize('q')
192 # The expected values here are in big-endian format, primarily because
193 # I'm on a little-endian machine and so this is the clearest way (for
194 # me) to force the code to get exercised.
195 for format, input, expected in (
196 ('q', -1, '\xff' * bytes),
197 ('q', 0, '\x00' * bytes),
198 ('Q', 0, '\x00' * bytes),
199 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
200 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
201 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
202 got = struct.pack(format, input)
Tim Petersc533edc2001-06-10 23:52:59 +0000203 native_expected = bigendian_to_native(expected)
204 verify(got == native_expected,
Tim Peters7b9542a2001-06-10 23:40:19 +0000205 "%r-pack of %r gave %r, not %r" %
Tim Petersc533edc2001-06-10 23:52:59 +0000206 (format, input, got, native_expected))
Tim Peters7b9542a2001-06-10 23:40:19 +0000207 retrieved = struct.unpack(format, got)[0]
208 verify(retrieved == input,
209 "%r-unpack of %r gave %r, not %r" %
210 (format, got, retrieved, input))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000211
212if has_native_qQ:
213 test_native_qQ()
214
Tim Peters17e17d42001-06-13 22:45:27 +0000215###########################################################################
216# Standard integer tests (bBhHiIlLqQ).
Tim Peters7a3bfc32001-06-12 01:22:22 +0000217
218import binascii
Tim Peters7a3bfc32001-06-12 01:22:22 +0000219
Tim Peters17e17d42001-06-13 22:45:27 +0000220class IntTester:
Tim Peters7a3bfc32001-06-12 01:22:22 +0000221
Tim Peters17e17d42001-06-13 22:45:27 +0000222 # XXX Most std integer modes fail to test for out-of-range.
Tim Peters3eec38a2001-06-18 22:27:39 +0000223 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
224 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
225 # reported by Mark Favas).
226 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters7a3bfc32001-06-12 01:22:22 +0000227
Tim Peters17e17d42001-06-13 22:45:27 +0000228 def __init__(self, formatpair, bytesize):
229 assert len(formatpair) == 2
230 self.formatpair = formatpair
231 for direction in "<>!=":
232 for code in formatpair:
233 format = direction + code
234 verify(struct.calcsize(format) == bytesize)
235 self.bytesize = bytesize
236 self.bitsize = bytesize * 8
237 self.signed_code, self.unsigned_code = formatpair
238 self.unsigned_min = 0
239 self.unsigned_max = 2L**self.bitsize - 1
240 self.signed_min = -(2L**(self.bitsize-1))
241 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters7a3bfc32001-06-12 01:22:22 +0000242
Tim Peters17e17d42001-06-13 22:45:27 +0000243 def test_one(self, x, pack=struct.pack,
244 unpack=struct.unpack,
245 unhexlify=binascii.unhexlify):
246 if verbose:
247 print "trying std", self.formatpair, "on", x, "==", hex(x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000248
Tim Peters17e17d42001-06-13 22:45:27 +0000249 # Try signed.
250 code = self.signed_code
251 if self.signed_min <= x <= self.signed_max:
252 # Try big-endian.
253 expected = long(x)
254 if x < 0:
255 expected += 1L << self.bitsize
256 assert expected > 0
257 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
258 if len(expected) & 1:
259 expected = "0" + expected
260 expected = unhexlify(expected)
261 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000262
Tim Peters17e17d42001-06-13 22:45:27 +0000263 # Pack work?
264 format = ">" + code
265 got = pack(format, x)
266 verify(got == expected,
267 "'%s'-pack of %r gave %r, not %r" %
268 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000269
Tim Peters17e17d42001-06-13 22:45:27 +0000270 # Unpack work?
271 retrieved = unpack(format, got)[0]
272 verify(x == retrieved,
273 "'%s'-unpack of %r gave %r, not %r" %
274 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000275
Tim Peters17e17d42001-06-13 22:45:27 +0000276 # Adding any byte should cause a "too big" error.
277 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000278
Tim Peters17e17d42001-06-13 22:45:27 +0000279 # Try little-endian.
280 format = "<" + code
281 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000282
Tim Peters17e17d42001-06-13 22:45:27 +0000283 # Pack work?
284 got = pack(format, x)
285 verify(got == expected,
286 "'%s'-pack of %r gave %r, not %r" %
287 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000288
Tim Peters17e17d42001-06-13 22:45:27 +0000289 # Unpack work?
290 retrieved = unpack(format, got)[0]
291 verify(x == retrieved,
292 "'%s'-unpack of %r gave %r, not %r" %
293 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000294
Tim Peters17e17d42001-06-13 22:45:27 +0000295 # Adding any byte should cause a "too big" error.
296 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000297
Tim Peters17e17d42001-06-13 22:45:27 +0000298 else:
299 # x is out of range -- verify pack realizes that.
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000300 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000301 if verbose:
302 print "Skipping buggy range check for code", code
303 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000304 deprecated_err(pack, ">" + code, x)
305 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000306
Tim Peters17e17d42001-06-13 22:45:27 +0000307 # Much the same for unsigned.
308 code = self.unsigned_code
309 if self.unsigned_min <= x <= self.unsigned_max:
310 # Try big-endian.
311 format = ">" + code
312 expected = long(x)
313 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
314 if len(expected) & 1:
315 expected = "0" + expected
316 expected = unhexlify(expected)
317 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters7a3bfc32001-06-12 01:22:22 +0000318
Tim Peters17e17d42001-06-13 22:45:27 +0000319 # Pack work?
320 got = pack(format, x)
321 verify(got == expected,
322 "'%s'-pack of %r gave %r, not %r" %
323 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000324
Tim Peters17e17d42001-06-13 22:45:27 +0000325 # Unpack work?
326 retrieved = unpack(format, got)[0]
327 verify(x == retrieved,
328 "'%s'-unpack of %r gave %r, not %r" %
329 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000330
Tim Peters17e17d42001-06-13 22:45:27 +0000331 # Adding any byte should cause a "too big" error.
332 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000333
Tim Peters17e17d42001-06-13 22:45:27 +0000334 # Try little-endian.
335 format = "<" + code
336 expected = string_reverse(expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000337
Tim Peters17e17d42001-06-13 22:45:27 +0000338 # Pack work?
339 got = pack(format, x)
340 verify(got == expected,
341 "'%s'-pack of %r gave %r, not %r" %
342 (format, x, got, expected))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000343
Tim Peters17e17d42001-06-13 22:45:27 +0000344 # Unpack work?
345 retrieved = unpack(format, got)[0]
346 verify(x == retrieved,
347 "'%s'-unpack of %r gave %r, not %r" %
348 (format, got, retrieved, x))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000349
Tim Peters17e17d42001-06-13 22:45:27 +0000350 # Adding any byte should cause a "too big" error.
351 any_err(unpack, format, '\x01' + got)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000352
Tim Peters17e17d42001-06-13 22:45:27 +0000353 else:
354 # x is out of range -- verify pack realizes that.
Bob Ippolitoaa70a172006-05-26 20:25:23 +0000355 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
Tim Peters17e17d42001-06-13 22:45:27 +0000356 if verbose:
357 print "Skipping buggy range check for code", code
358 else:
Bob Ippolito2fd39772006-05-29 22:55:48 +0000359 deprecated_err(pack, ">" + code, x)
360 deprecated_err(pack, "<" + code, x)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000361
Tim Peters17e17d42001-06-13 22:45:27 +0000362 def run(self):
363 from random import randrange
364
365 # Create all interesting powers of 2.
366 values = []
367 for exp in range(self.bitsize + 3):
368 values.append(1L << exp)
369
370 # Add some random values.
371 for i in range(self.bitsize):
372 val = 0L
373 for j in range(self.bytesize):
374 val = (val << 8) | randrange(256)
375 values.append(val)
376
377 # Try all those, and their negations, and +-1 from them. Note
378 # that this tests all power-of-2 boundaries in range, and a few out
379 # of range, plus +-(2**n +- 1).
380 for base in values:
381 for val in -base, base:
382 for incr in -1, 0, 1:
383 x = val + incr
384 try:
385 x = int(x)
386 except OverflowError:
387 pass
388 self.test_one(x)
389
390 # Some error cases.
391 for direction in "<>":
392 for code in self.formatpair:
393 for badobject in "a string", 3+42j, randrange:
394 any_err(struct.pack, direction + code, badobject)
395
396for args in [("bB", 1),
397 ("hH", 2),
398 ("iI", 4),
399 ("lL", 4),
400 ("qQ", 8)]:
401 t = IntTester(*args)
402 t.run()
Tim Peters0891ac02001-09-15 02:35:15 +0000403
404
405###########################################################################
406# The p ("Pascal string") code.
407
408def test_p_code():
409 for code, input, expected, expectedback in [
410 ('p','abc', '\x00', ''),
411 ('1p', 'abc', '\x00', ''),
412 ('2p', 'abc', '\x01a', 'a'),
413 ('3p', 'abc', '\x02ab', 'ab'),
414 ('4p', 'abc', '\x03abc', 'abc'),
415 ('5p', 'abc', '\x03abc\x00', 'abc'),
416 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
417 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
418 got = struct.pack(code, input)
419 if got != expected:
420 raise TestFailed("pack(%r, %r) == %r but expected %r" %
421 (code, input, got, expected))
422 (got,) = struct.unpack(code, got)
423 if got != expectedback:
424 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
425 (code, input, got, expectedback))
426
427test_p_code()
Tim Petersd50ade62003-03-20 18:32:13 +0000428
429
430###########################################################################
431# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
432# from the low-order discarded bits could propagate into the exponent
433# field, causing the result to be wrong by a factor of 2.
434
435def test_705836():
436 import math
437
438 for base in range(1, 33):
439 # smaller <- largest representable float less than base.
440 delta = 0.5
441 while base - delta / 2.0 != base:
442 delta /= 2.0
443 smaller = base - delta
444 # Packing this rounds away a solid string of trailing 1 bits.
445 packed = struct.pack("<f", smaller)
446 unpacked = struct.unpack("<f", packed)[0]
447 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
448 # 16, respectively.
449 verify(base == unpacked)
450 bigpacked = struct.pack(">f", smaller)
451 verify(bigpacked == string_reverse(packed),
452 ">f pack should be byte-reversal of <f pack")
453 unpacked = struct.unpack(">f", bigpacked)[0]
454 verify(base == unpacked)
455
456 # Largest finite IEEE single.
457 big = (1 << 24) - 1
458 big = math.ldexp(big, 127 - 23)
459 packed = struct.pack(">f", big)
460 unpacked = struct.unpack(">f", packed)[0]
461 verify(big == unpacked)
462
463 # The same, but tack on a 1 bit so it rounds up to infinity.
464 big = (1 << 25) - 1
465 big = math.ldexp(big, 127 - 24)
466 try:
467 packed = struct.pack(">f", big)
468 except OverflowError:
469 pass
470 else:
471 TestFailed("expected OverflowError")
472
473test_705836()
Bob Ippolitoeb621272006-05-24 15:32:06 +0000474
Bob Ippolitoeb621272006-05-24 15:32:06 +0000475def test_1229380():
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000476 import sys
Bob Ippolitoeb621272006-05-24 15:32:06 +0000477 for endian in ('', '>', '<'):
478 for cls in (int, long):
479 for fmt in ('B', 'H', 'I', 'L'):
Bob Ippolito2fd39772006-05-29 22:55:48 +0000480 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000481
Bob Ippolito2fd39772006-05-29 22:55:48 +0000482 deprecated_err(struct.pack, endian + 'B', cls(300))
483 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000484
Bob Ippolito2fd39772006-05-29 22:55:48 +0000485 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
486 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000487
Bob Ippolitoe27337b2006-05-26 13:15:44 +0000488if PY_STRUCT_RANGE_CHECKING:
Bob Ippolitoeb621272006-05-24 15:32:06 +0000489 test_1229380()
Martin Blais2856e5f2006-05-26 12:03:27 +0000490
491class PackBufferTestCase(unittest.TestCase):
492 """
493 Test the packing methods that work on buffers.
494 """
495
496 def test_unpack_from( self ):
497 test_string = 'abcd01234'
498 fmt = '4s'
499 s = struct.Struct(fmt)
500 for cls in (str, buffer):
501 data = cls(test_string)
502 self.assertEquals(s.unpack_from(data), ('abcd',))
503 self.assertEquals(s.unpack_from(data, 2), ('cd01',))
504 self.assertEquals(s.unpack_from(data, 4), ('0123',))
505 for i in xrange(6):
506 self.assertEquals(s.unpack_from(data, i), (data[i:i+4],))
507 for i in xrange(6, len(test_string) + 1):
508 simple_err(s.unpack_from, data, i)
509 for cls in (str, buffer):
510 data = cls(test_string)
511 self.assertEquals(struct.unpack_from(fmt, data), ('abcd',))
512 self.assertEquals(struct.unpack_from(fmt, data, 2), ('cd01',))
513 self.assertEquals(struct.unpack_from(fmt, data, 4), ('0123',))
514 for i in xrange(6):
515 self.assertEquals(struct.unpack_from(fmt, data, i),
516 (data[i:i+4],))
517 for i in xrange(6, len(test_string) + 1):
518 simple_err(struct.unpack_from, fmt, data, i)
519
520 def test_pack_to( self ):
521 test_string = 'Reykjavik rocks, eow!'
522 writable_buf = array.array('c', ' '*100)
523 fmt = '21s'
524 s = struct.Struct(fmt)
525
526 # Test without offset
527 s.pack_to(writable_buf, 0, test_string)
528 from_buf = writable_buf.tostring()[:len(test_string)]
529 self.assertEquals(from_buf, test_string)
530
531 # Test with offset.
532 s.pack_to(writable_buf, 10, test_string)
533 from_buf = writable_buf.tostring()[:len(test_string)+10]
534 self.assertEquals(from_buf, (test_string[:10] + test_string))
535
536 # Go beyond boundaries.
537 small_buf = array.array('c', ' '*10)
538 self.assertRaises(struct.error, s.pack_to, small_buf, 0, test_string)
539 self.assertRaises(struct.error, s.pack_to, small_buf, 2, test_string)
540
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000541 def test_pack_to_fn( self ):
542 test_string = 'Reykjavik rocks, eow!'
543 writable_buf = array.array('c', ' '*100)
544 fmt = '21s'
545 pack_to = lambda *args: struct.pack_to(fmt, *args)
546
547 # Test without offset
548 pack_to(writable_buf, 0, test_string)
549 from_buf = writable_buf.tostring()[:len(test_string)]
550 self.assertEquals(from_buf, test_string)
551
552 # Test with offset.
553 pack_to(writable_buf, 10, test_string)
554 from_buf = writable_buf.tostring()[:len(test_string)+10]
555 self.assertEquals(from_buf, (test_string[:10] + test_string))
556
557 # Go beyond boundaries.
558 small_buf = array.array('c', ' '*10)
559 self.assertRaises(struct.error, pack_to, small_buf, 0, test_string)
560 self.assertRaises(struct.error, pack_to, small_buf, 2, test_string)
561
562
Martin Blais2856e5f2006-05-26 12:03:27 +0000563def test_main():
564 test.test_support.run_unittest(PackBufferTestCase)
Tim Petersfe98f962006-05-26 12:26:21 +0000565
Martin Blais2856e5f2006-05-26 12:03:27 +0000566if __name__ == "__main__":
567 test_main()