1 from test
.test_support
import TestFailed
, verbose
, verify
5 ISBIGENDIAN
= sys
.byteorder
== "big"
7 verify((struct
.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN
,
8 "bigendian determination appears wrong")
10 def string_reverse(s
):
15 def bigendian_to_native(value
):
19 return string_reverse(value
)
21 def simple_err(func
, *args
):
27 raise TestFailed
, "%s%s did not raise struct.error" % (
30 def any_err(func
, *args
):
33 except (struct
.error
, OverflowError, TypeError):
36 raise TestFailed
, "%s%s did not raise error" % (
40 simple_err(struct
.calcsize
, 'Z')
42 sz
= struct
.calcsize('i')
43 if sz
* 3 != struct
.calcsize('iii'):
44 raise TestFailed
, 'inconsistent sizes'
46 fmt
= 'cbxxxxxxhhhhiillffd'
47 fmt3
= '3c3b18x12h6i6l6f3d'
48 sz
= struct
.calcsize(fmt
)
49 sz3
= struct
.calcsize(fmt3
)
51 raise TestFailed
, 'inconsistent sizes (3*%s -> 3*%d = %d, %s -> %d)' % (
52 `fmt`
, sz
, 3*sz
, `fmt3`
, sz3
)
54 simple_err(struct
.pack
, 'iii', 3)
55 simple_err(struct
.pack
, 'i', 3, 3, 3)
56 simple_err(struct
.pack
, 'i', 'foo')
57 simple_err(struct
.unpack
, 'd', 'flap')
58 s
= struct
.pack('ii', 1, 2)
59 simple_err(struct
.unpack
, 'iii', s
)
60 simple_err(struct
.unpack
, 'i', s
)
70 for prefix
in ('', '@', '<', '>', '=', '!'):
71 for format
in ('xcbhilfd', 'xcBHILfd'):
72 format
= prefix
+ format
74 print "trying:", format
75 s
= struct
.pack(format
, c
, b
, h
, i
, l
, f
, d
)
76 cp
, bp
, hp
, ip
, lp
, fp
, dp
= struct
.unpack(format
, s
)
77 if (cp
!= c
or bp
!= b
or hp
!= h
or ip
!= i
or lp
!= l
or
78 int(100 * fp
) != int(100 * f
) or int(100 * dp
) != int(100 * d
)):
79 # ^^^ calculate only to two decimal places
80 raise TestFailed
, "unpack/pack not transitive (%s, %s)" % (
81 str(format
), str((cp
, bp
, hp
, ip
, lp
, fp
, dp
)))
83 # Test some of the new features in detail
85 # (format, argument, big-endian result, little-endian result, asymmetric)
87 ('c', 'a', 'a', 'a', 0),
88 ('xc', 'a', '\0a', '\0a', 0),
89 ('cx', 'a', 'a\0', 'a\0', 0),
90 ('s', 'a', 'a', 'a', 0),
91 ('0s', 'helloworld', '', '', 1),
92 ('1s', 'helloworld', 'h', 'h', 1),
93 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
94 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
95 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
96 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
97 ('b', 7, '\7', '\7', 0),
98 ('b', -7, '\371', '\371', 0),
99 ('B', 7, '\7', '\7', 0),
100 ('B', 249, '\371', '\371', 0),
101 ('h', 700, '\002\274', '\274\002', 0),
102 ('h', -700, '\375D', 'D\375', 0),
103 ('H', 700, '\002\274', '\274\002', 0),
104 ('H', 0x10000-700, '\375D', 'D\375', 0),
105 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
106 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
107 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
108 ('I', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
109 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
110 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
111 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
112 ('L', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
113 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
114 ('d', 2.0, '@\000\000\000\000\000\000\000',
115 '\000\000\000\000\000\000\000@', 0),
116 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
117 ('d', -2.0, '\300\000\000\000\000\000\000\000',
118 '\000\000\000\000\000\000\000\300', 0),
121 for fmt
, arg
, big
, lil
, asy
in tests
:
123 print `fmt`
, `arg`
, `big`
, `lil`
124 for (xfmt
, exp
) in [('>'+fmt
, big
), ('!'+fmt
, big
), ('<'+fmt
, lil
),
125 ('='+fmt
, ISBIGENDIAN
and big
or lil
)]:
126 res
= struct
.pack(xfmt
, arg
)
128 raise TestFailed
, "pack(%s, %s) -> %s # expected %s" % (
129 `fmt`
, `arg`
, `res`
, `exp`
)
130 n
= struct
.calcsize(xfmt
)
132 raise TestFailed
, "calcsize(%s) -> %d # expected %d" % (
134 rev
= struct
.unpack(xfmt
, res
)[0]
135 if rev
!= arg
and not asy
:
136 raise TestFailed
, "unpack(%s, %s) -> (%s,) # expected (%s,)" % (
137 `fmt`
, `res`
, `rev`
, `arg`
)
139 ###########################################################################
140 # Simple native q/Q tests.
149 print "Platform has native q/Q?", has_native_qQ
and "Yes." or "No."
151 any_err(struct
.pack
, "Q", -1) # can't pack -1 as unsigned regardless
152 simple_err(struct
.pack
, "q", "a") # can't pack string as 'q' regardless
153 simple_err(struct
.pack
, "Q", "a") # ditto, but 'Q'
155 def test_native_qQ():
156 bytes
= struct
.calcsize('q')
157 # The expected values here are in big-endian format, primarily because
158 # I'm on a little-endian machine and so this is the clearest way (for
159 # me) to force the code to get exercised.
160 for format
, input, expected
in (
161 ('q', -1, '\xff' * bytes
),
162 ('q', 0, '\x00' * bytes
),
163 ('Q', 0, '\x00' * bytes
),
164 ('q', 1L, '\x00' * (bytes
-1) + '\x01'),
165 ('Q', (1L << (8*bytes
))-1, '\xff' * bytes
),
166 ('q', (1L << (8*bytes
-1))-1, '\x7f' + '\xff' * (bytes
- 1))):
167 got
= struct
.pack(format
, input)
168 native_expected
= bigendian_to_native(expected
)
169 verify(got
== native_expected
,
170 "%r-pack of %r gave %r, not %r" %
171 (format
, input, got
, native_expected
))
172 retrieved
= struct
.unpack(format
, got
)[0]
173 verify(retrieved
== input,
174 "%r-unpack of %r gave %r, not %r" %
175 (format
, got
, retrieved
, input))
180 ###########################################################################
181 # Standard integer tests (bBhHiIlLqQ).
187 # XXX Most std integer modes fail to test for out-of-range.
188 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
189 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
190 # reported by Mark Favas).
191 BUGGY_RANGE_CHECK
= "bBhHiIlL"
193 def __init__(self
, formatpair
, bytesize
):
194 assert len(formatpair
) == 2
195 self
.formatpair
= formatpair
196 for direction
in "<>!=":
197 for code
in formatpair
:
198 format
= direction
+ code
199 verify(struct
.calcsize(format
) == bytesize
)
200 self
.bytesize
= bytesize
201 self
.bitsize
= bytesize
* 8
202 self
.signed_code
, self
.unsigned_code
= formatpair
203 self
.unsigned_min
= 0
204 self
.unsigned_max
= 2L**self
.bitsize
- 1
205 self
.signed_min
= -(2L**(self
.bitsize
-1))
206 self
.signed_max
= 2L**(self
.bitsize
-1) - 1
208 def test_one(self
, x
, pack
=struct
.pack
,
209 unpack
=struct
.unpack
,
210 unhexlify
=binascii
.unhexlify
):
212 print "trying std", self
.formatpair
, "on", x
, "==", hex(x
)
215 code
= self
.signed_code
216 if self
.signed_min
<= x
<= self
.signed_max
:
220 expected
+= 1L << self
.bitsize
222 expected
= hex(expected
)[2:-1] # chop "0x" and trailing 'L'
223 if len(expected
) & 1:
224 expected
= "0" + expected
225 expected
= unhexlify(expected
)
226 expected
= "\x00" * (self
.bytesize
- len(expected
)) + expected
230 got
= pack(format
, x
)
231 verify(got
== expected
,
232 "'%s'-pack of %r gave %r, not %r" %
233 (format
, x
, got
, expected
))
236 retrieved
= unpack(format
, got
)[0]
237 verify(x
== retrieved
,
238 "'%s'-unpack of %r gave %r, not %r" %
239 (format
, got
, retrieved
, x
))
241 # Adding any byte should cause a "too big" error.
242 any_err(unpack
, format
, '\x01' + got
)
246 expected
= string_reverse(expected
)
249 got
= pack(format
, x
)
250 verify(got
== expected
,
251 "'%s'-pack of %r gave %r, not %r" %
252 (format
, x
, got
, expected
))
255 retrieved
= unpack(format
, got
)[0]
256 verify(x
== retrieved
,
257 "'%s'-unpack of %r gave %r, not %r" %
258 (format
, got
, retrieved
, x
))
260 # Adding any byte should cause a "too big" error.
261 any_err(unpack
, format
, '\x01' + got
)
264 # x is out of range -- verify pack realizes that.
265 if code
in self
.BUGGY_RANGE_CHECK
:
267 print "Skipping buggy range check for code", code
269 any_err(pack
, ">" + code
, x
)
270 any_err(pack
, "<" + code
, x
)
272 # Much the same for unsigned.
273 code
= self
.unsigned_code
274 if self
.unsigned_min
<= x
<= self
.unsigned_max
:
278 expected
= hex(expected
)[2:-1] # chop "0x" and trailing 'L'
279 if len(expected
) & 1:
280 expected
= "0" + expected
281 expected
= unhexlify(expected
)
282 expected
= "\x00" * (self
.bytesize
- len(expected
)) + expected
285 got
= pack(format
, x
)
286 verify(got
== expected
,
287 "'%s'-pack of %r gave %r, not %r" %
288 (format
, x
, got
, expected
))
291 retrieved
= unpack(format
, got
)[0]
292 verify(x
== retrieved
,
293 "'%s'-unpack of %r gave %r, not %r" %
294 (format
, got
, retrieved
, x
))
296 # Adding any byte should cause a "too big" error.
297 any_err(unpack
, format
, '\x01' + got
)
301 expected
= string_reverse(expected
)
304 got
= pack(format
, x
)
305 verify(got
== expected
,
306 "'%s'-pack of %r gave %r, not %r" %
307 (format
, x
, got
, expected
))
310 retrieved
= unpack(format
, got
)[0]
311 verify(x
== retrieved
,
312 "'%s'-unpack of %r gave %r, not %r" %
313 (format
, got
, retrieved
, x
))
315 # Adding any byte should cause a "too big" error.
316 any_err(unpack
, format
, '\x01' + got
)
319 # x is out of range -- verify pack realizes that.
320 if code
in self
.BUGGY_RANGE_CHECK
:
322 print "Skipping buggy range check for code", code
324 any_err(pack
, ">" + code
, x
)
325 any_err(pack
, "<" + code
, x
)
328 from random
import randrange
330 # Create all interesting powers of 2.
332 for exp
in range(self
.bitsize
+ 3):
333 values
.append(1L << exp
)
335 # Add some random values.
336 for i
in range(self
.bitsize
):
338 for j
in range(self
.bytesize
):
339 val
= (val
<< 8) |
randrange(256)
342 # Try all those, and their negations, and +-1 from them. Note
343 # that this tests all power-of-2 boundaries in range, and a few out
344 # of range, plus +-(2**n +- 1).
346 for val
in -base
, base
:
347 for incr
in -1, 0, 1:
351 except OverflowError:
356 for direction
in "<>":
357 for code
in self
.formatpair
:
358 for badobject
in "a string", 3+42j
, randrange
:
359 any_err(struct
.pack
, direction
+ code
, badobject
)
361 for args
in [("bB", 1),
370 ###########################################################################
371 # The p ("Pascal string") code.
374 for code
, input, expected
, expectedback
in [
375 ('p','abc', '\x00', ''),
376 ('1p', 'abc', '\x00', ''),
377 ('2p', 'abc', '\x01a', 'a'),
378 ('3p', 'abc', '\x02ab', 'ab'),
379 ('4p', 'abc', '\x03abc', 'abc'),
380 ('5p', 'abc', '\x03abc\x00', 'abc'),
381 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
382 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
383 got
= struct
.pack(code
, input)
385 raise TestFailed("pack(%r, %r) == %r but expected %r" %
386 (code
, input, got
, expected
))
387 (got
,) = struct
.unpack(code
, got
)
388 if got
!= expectedback
:
389 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
390 (code
, input, got
, expectedback
))
395 ###########################################################################
396 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
397 # from the low-order discarded bits could propagate into the exponent
398 # field, causing the result to be wrong by a factor of 2.
403 for base
in range(1, 33):
404 # smaller <- largest representable float less than base.
406 while base
- delta
/ 2.0 != base
:
408 smaller
= base
- delta
409 # Packing this rounds away a solid string of trailing 1 bits.
410 packed
= struct
.pack("<f", smaller
)
411 unpacked
= struct
.unpack("<f", packed
)[0]
412 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
414 verify(base
== unpacked
)
415 bigpacked
= struct
.pack(">f", smaller
)
416 verify(bigpacked
== string_reverse(packed
),
417 ">f pack should be byte-reversal of <f pack")
418 unpacked
= struct
.unpack(">f", bigpacked
)[0]
419 verify(base
== unpacked
)
421 # Largest finite IEEE single.
423 big
= math
.ldexp(big
, 127 - 23)
424 packed
= struct
.pack(">f", big
)
425 unpacked
= struct
.unpack(">f", packed
)[0]
426 verify(big
== unpacked
)
428 # The same, but tack on a 1 bit so it rounds up to infinity.
430 big
= math
.ldexp(big
, 127 - 24)
432 packed
= struct
.pack(">f", big
)
433 except OverflowError:
436 TestFailed("expected OverflowError")