1 from test
.test_support
import TestFailed
, verbose
, verify
, vereq
2 import test
.test_support
8 ISBIGENDIAN
= sys
.byteorder
== "big"
10 verify((struct
.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN
,
11 "bigendian determination appears wrong")
16 PY_STRUCT_RANGE_CHECKING
= 0
17 PY_STRUCT_OVERFLOW_MASKING
= 1
18 PY_STRUCT_FLOAT_COERCE
= 2
20 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)
24 def string_reverse(s
):
25 return "".join(reversed(s
))
27 def bigendian_to_native(value
):
31 return string_reverse(value
)
33 def simple_err(func
, *args
):
39 raise TestFailed
, "%s%s did not raise struct.error" % (
42 def any_err(func
, *args
):
45 except (struct
.error
, TypeError):
48 raise TestFailed
, "%s%s did not raise error" % (
51 def with_warning_restore(func
):
52 def _with_warning_restore(*args
, **kw
):
53 with test
.test_support
.catch_warning():
54 # Grrr, we need this function to warn every time. Without removing
55 # the warningregistry, running test_tarfile then test_struct would fail
56 # on 64-bit platforms.
57 globals = func
.func_globals
58 if '__warningregistry__' in globals:
59 del globals['__warningregistry__']
60 warnings
.filterwarnings("error", r
"""^struct.*""", DeprecationWarning)
61 warnings
.filterwarnings("error", r
""".*format requires.*""",
63 return func(*args
, **kw
)
64 return _with_warning_restore
66 def deprecated_err(func
, *args
):
69 except (struct
.error
, TypeError):
71 except DeprecationWarning:
72 if not PY_STRUCT_OVERFLOW_MASKING
:
73 raise TestFailed
, "%s%s expected to raise struct.error" % (
76 raise TestFailed
, "%s%s did not raise error" % (
78 deprecated_err
= with_warning_restore(deprecated_err
)
81 simple_err(struct
.calcsize
, 'Z')
83 sz
= struct
.calcsize('i')
84 if sz
* 3 != struct
.calcsize('iii'):
85 raise TestFailed
, 'inconsistent sizes'
87 fmt
= 'cbxxxxxxhhhhiillffdt'
88 fmt3
= '3c3b18x12h6i6l6f3d3t'
89 sz
= struct
.calcsize(fmt
)
90 sz3
= struct
.calcsize(fmt3
)
92 raise TestFailed
, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
93 fmt
, sz
, 3*sz
, fmt3
, sz3
)
95 simple_err(struct
.pack
, 'iii', 3)
96 simple_err(struct
.pack
, 'i', 3, 3, 3)
97 simple_err(struct
.pack
, 'i', 'foo')
98 simple_err(struct
.pack
, 'P', 'foo')
99 simple_err(struct
.unpack
, 'd', 'flap')
100 s
= struct
.pack('ii', 1, 2)
101 simple_err(struct
.unpack
, 'iii', s
)
102 simple_err(struct
.unpack
, 'i', s
)
113 for prefix
in ('', '@', '<', '>', '=', '!'):
114 for format
in ('xcbhilfdt', 'xcBHILfdt'):
115 format
= prefix
+ format
117 print "trying:", format
118 s
= struct
.pack(format
, c
, b
, h
, i
, l
, f
, d
, t
)
119 cp
, bp
, hp
, ip
, lp
, fp
, dp
, tp
= struct
.unpack(format
, s
)
120 if (cp
!= c
or bp
!= b
or hp
!= h
or ip
!= i
or lp
!= l
or
121 int(100 * fp
) != int(100 * f
) or int(100 * dp
) != int(100 * d
) or
123 # ^^^ calculate only to two decimal places
124 raise TestFailed
, "unpack/pack not transitive (%s, %s)" % (
125 str(format
), str((cp
, bp
, hp
, ip
, lp
, fp
, dp
, tp
)))
127 # Test some of the new features in detail
129 # (format, argument, big-endian result, little-endian result, asymmetric)
131 ('c', 'a', 'a', 'a', 0),
132 ('xc', 'a', '\0a', '\0a', 0),
133 ('cx', 'a', 'a\0', 'a\0', 0),
134 ('s', 'a', 'a', 'a', 0),
135 ('0s', 'helloworld', '', '', 1),
136 ('1s', 'helloworld', 'h', 'h', 1),
137 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
138 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
139 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
140 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
141 ('b', 7, '\7', '\7', 0),
142 ('b', -7, '\371', '\371', 0),
143 ('B', 7, '\7', '\7', 0),
144 ('B', 249, '\371', '\371', 0),
145 ('h', 700, '\002\274', '\274\002', 0),
146 ('h', -700, '\375D', 'D\375', 0),
147 ('H', 700, '\002\274', '\274\002', 0),
148 ('H', 0x10000-700, '\375D', 'D\375', 0),
149 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
150 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
151 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
152 ('I', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
153 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
154 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
155 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
156 ('L', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
158 ('d', 2.0, '@\000\000\000\000\000\000\000',
159 '\000\000\000\000\000\000\000@', 0),
160 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
161 ('d', -2.0, '\300\000\000\000\000\000\000\000',
162 '\000\000\000\000\000\000\000\300', 0),
163 ('t', 0, '\0', '\0', 0),
164 ('t', 3, '\1', '\1', 1),
165 ('t', True, '\1', '\1', 0),
166 ('t', [], '\0', '\0', 1),
167 ('t', (1,), '\1', '\1', 1),
170 for fmt
, arg
, big
, lil
, asy
in tests
:
172 print "%r %r %r %r" % (fmt
, arg
, big
, lil
)
173 for (xfmt
, exp
) in [('>'+fmt
, big
), ('!'+fmt
, big
), ('<'+fmt
, lil
),
174 ('='+fmt
, ISBIGENDIAN
and big
or lil
)]:
175 res
= struct
.pack(xfmt
, arg
)
177 raise TestFailed
, "pack(%r, %r) -> %r # expected %r" % (
179 n
= struct
.calcsize(xfmt
)
181 raise TestFailed
, "calcsize(%r) -> %d # expected %d" % (
183 rev
= struct
.unpack(xfmt
, res
)[0]
184 if rev
!= arg
and not asy
:
185 raise TestFailed
, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
188 ###########################################################################
189 # Simple native q/Q tests.
198 print "Platform has native q/Q?", has_native_qQ
and "Yes." or "No."
200 any_err(struct
.pack
, "Q", -1) # can't pack -1 as unsigned regardless
201 simple_err(struct
.pack
, "q", "a") # can't pack string as 'q' regardless
202 simple_err(struct
.pack
, "Q", "a") # ditto, but 'Q'
204 def test_native_qQ():
205 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)
217 native_expected
= bigendian_to_native(expected
)
218 verify(got
== native_expected
,
219 "%r-pack of %r gave %r, not %r" %
220 (format
, input, got
, native_expected
))
221 retrieved
= struct
.unpack(format
, got
)[0]
222 verify(retrieved
== input,
223 "%r-unpack of %r gave %r, not %r" %
224 (format
, got
, retrieved
, input))
229 ###########################################################################
230 # Standard integer tests (bBhHiIlLqQ).
236 # XXX Most std integer modes fail to test for out-of-range.
237 # 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"
242 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
257 def test_one(self
, x
, pack
=struct
.pack
,
258 unpack
=struct
.unpack
,
259 unhexlify
=binascii
.unhexlify
):
261 print "trying std", self
.formatpair
, "on", x
, "==", hex(x
)
264 code
= self
.signed_code
265 if self
.signed_min
<= x
<= self
.signed_max
:
269 expected
+= 1L << self
.bitsize
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
279 got
= pack(format
, x
)
280 verify(got
== expected
,
281 "'%s'-pack of %r gave %r, not %r" %
282 (format
, x
, got
, expected
))
285 retrieved
= unpack(format
, got
)[0]
286 verify(x
== retrieved
,
287 "'%s'-unpack of %r gave %r, not %r" %
288 (format
, got
, retrieved
, x
))
290 # Adding any byte should cause a "too big" error.
291 any_err(unpack
, format
, '\x01' + got
)
295 expected
= string_reverse(expected
)
298 got
= pack(format
, x
)
299 verify(got
== expected
,
300 "'%s'-pack of %r gave %r, not %r" %
301 (format
, x
, got
, expected
))
304 retrieved
= unpack(format
, got
)[0]
305 verify(x
== retrieved
,
306 "'%s'-unpack of %r gave %r, not %r" %
307 (format
, got
, retrieved
, x
))
309 # Adding any byte should cause a "too big" error.
310 any_err(unpack
, format
, '\x01' + got
)
313 # x is out of range -- verify pack realizes that.
314 if not PY_STRUCT_RANGE_CHECKING
and code
in self
.BUGGY_RANGE_CHECK
:
316 print "Skipping buggy range check for code", code
318 deprecated_err(pack
, ">" + code
, x
)
319 deprecated_err(pack
, "<" + code
, x
)
321 # Much the same for unsigned.
322 code
= self
.unsigned_code
323 if self
.unsigned_min
<= x
<= self
.unsigned_max
:
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
334 got
= pack(format
, x
)
335 verify(got
== expected
,
336 "'%s'-pack of %r gave %r, not %r" %
337 (format
, x
, got
, expected
))
340 retrieved
= unpack(format
, got
)[0]
341 verify(x
== retrieved
,
342 "'%s'-unpack of %r gave %r, not %r" %
343 (format
, got
, retrieved
, x
))
345 # Adding any byte should cause a "too big" error.
346 any_err(unpack
, format
, '\x01' + got
)
350 expected
= string_reverse(expected
)
353 got
= pack(format
, x
)
354 verify(got
== expected
,
355 "'%s'-pack of %r gave %r, not %r" %
356 (format
, x
, got
, expected
))
359 retrieved
= unpack(format
, got
)[0]
360 verify(x
== retrieved
,
361 "'%s'-unpack of %r gave %r, not %r" %
362 (format
, got
, retrieved
, x
))
364 # Adding any byte should cause a "too big" error.
365 any_err(unpack
, format
, '\x01' + got
)
368 # x is out of range -- verify pack realizes that.
369 if not PY_STRUCT_RANGE_CHECKING
and code
in self
.BUGGY_RANGE_CHECK
:
371 print "Skipping buggy range check for code", code
373 deprecated_err(pack
, ">" + code
, x
)
374 deprecated_err(pack
, "<" + code
, x
)
377 from random
import randrange
379 # Create all interesting powers of 2.
381 for exp
in range(self
.bitsize
+ 3):
382 values
.append(1L << exp
)
384 # Add some random values.
385 for i
in range(self
.bitsize
):
387 for j
in range(self
.bytesize
):
388 val
= (val
<< 8) |
randrange(256)
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).
395 for val
in -base
, base
:
396 for incr
in -1, 0, 1:
400 except OverflowError:
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
)
410 for args
in [("bB", 1),
419 ###########################################################################
420 # The p ("Pascal string") 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)
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
))
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.
452 for base
in range(1, 33):
453 # smaller <- largest representable float less than base.
455 while base
- delta
/ 2.0 != base
:
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
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
)
470 # Largest finite IEEE single.
472 big
= math
.ldexp(big
, 127 - 23)
473 packed
= struct
.pack(">f", big
)
474 unpacked
= struct
.unpack(">f", packed
)[0]
475 verify(big
== unpacked
)
477 # The same, but tack on a 1 bit so it rounds up to infinity.
479 big
= math
.ldexp(big
, 127 - 24)
481 packed
= struct
.pack(">f", big
)
482 except OverflowError:
485 TestFailed("expected OverflowError")
489 ###########################################################################
490 # SF bug 1229380. No struct.pack exception for some out of range integers
494 for endian
in ('', '>', '<'):
495 for cls
in (int, long):
496 for fmt
in ('B', 'H', 'I', 'L'):
497 deprecated_err(struct
.pack
, endian
+ fmt
, cls(-1))
499 deprecated_err(struct
.pack
, endian
+ 'B', cls(300))
500 deprecated_err(struct
.pack
, endian
+ 'H', cls(70000))
502 deprecated_err(struct
.pack
, endian
+ 'I', sys
.maxint
* 4L)
503 deprecated_err(struct
.pack
, endian
+ 'L', sys
.maxint
* 4L)
505 if PY_STRUCT_RANGE_CHECKING
:
508 ###########################################################################
509 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
511 def 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")
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")
528 raise TestFailed("did not raise error for float coerce")
530 check_float_coerce
= with_warning_restore(deprecated_err
)
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)
540 ###########################################################################
541 # Packing and unpacking to/from buffers.
543 # Copied and modified from unittest.
544 def assertRaises(excClass
, callableObj
, *args
, **kwargs
):
546 callableObj(*args
, **kwargs
)
550 raise TestFailed("%s not raised." % excClass
)
552 def test_unpack_from():
553 test_string
= 'abcd01234'
555 s
= struct
.Struct(fmt
)
556 for cls
in (str, buffer):
557 data
= cls(test_string
)
558 vereq(s
.unpack_from(data
), ('abcd',))
559 vereq(s
.unpack_from(data
, 2), ('cd01',))
560 vereq(s
.unpack_from(data
, 4), ('0123',))
562 vereq(s
.unpack_from(data
, i
), (data
[i
:i
+4],))
563 for i
in xrange(6, len(test_string
) + 1):
564 simple_err(s
.unpack_from
, data
, i
)
565 for cls
in (str, buffer):
566 data
= cls(test_string
)
567 vereq(struct
.unpack_from(fmt
, data
), ('abcd',))
568 vereq(struct
.unpack_from(fmt
, data
, 2), ('cd01',))
569 vereq(struct
.unpack_from(fmt
, data
, 4), ('0123',))
571 vereq(struct
.unpack_from(fmt
, data
, i
), (data
[i
:i
+4],))
572 for i
in xrange(6, len(test_string
) + 1):
573 simple_err(struct
.unpack_from
, fmt
, data
, i
)
575 def test_pack_into():
576 test_string
= 'Reykjavik rocks, eow!'
577 writable_buf
= array
.array('c', ' '*100)
579 s
= struct
.Struct(fmt
)
581 # Test without offset
582 s
.pack_into(writable_buf
, 0, test_string
)
583 from_buf
= writable_buf
.tostring()[:len(test_string
)]
584 vereq(from_buf
, test_string
)
587 s
.pack_into(writable_buf
, 10, test_string
)
588 from_buf
= writable_buf
.tostring()[:len(test_string
)+10]
589 vereq(from_buf
, test_string
[:10] + test_string
)
591 # Go beyond boundaries.
592 small_buf
= array
.array('c', ' '*10)
593 assertRaises(struct
.error
, s
.pack_into
, small_buf
, 0, test_string
)
594 assertRaises(struct
.error
, s
.pack_into
, small_buf
, 2, test_string
)
596 def test_pack_into_fn():
597 test_string
= 'Reykjavik rocks, eow!'
598 writable_buf
= array
.array('c', ' '*100)
600 pack_into
= lambda *args
: struct
.pack_into(fmt
, *args
)
602 # Test without offset.
603 pack_into(writable_buf
, 0, test_string
)
604 from_buf
= writable_buf
.tostring()[:len(test_string
)]
605 vereq(from_buf
, test_string
)
608 pack_into(writable_buf
, 10, test_string
)
609 from_buf
= writable_buf
.tostring()[:len(test_string
)+10]
610 vereq(from_buf
, test_string
[:10] + test_string
)
612 # Go beyond boundaries.
613 small_buf
= array
.array('c', ' '*10)
614 assertRaises(struct
.error
, pack_into
, small_buf
, 0, test_string
)
615 assertRaises(struct
.error
, pack_into
, small_buf
, 2, test_string
)
617 def test_unpack_with_buffer():
618 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
619 data1
= array
.array('B', '\x12\x34\x56\x78')
620 data2
= buffer('......\x12\x34\x56\x78......', 6, 4)
621 for data
in [data1
, data2
]:
622 value
, = struct
.unpack('>I', data
)
623 vereq(value
, 0x12345678)
625 # Test methods to pack and unpack from buffers rather than strings.
629 test_unpack_with_buffer()
632 for prefix
in tuple("<>!=")+('',):
633 false
= (), [], [], '', 0
634 true
= [1], 'test', 5, -1, 0xffffffffL
+1, 0xffffffff/2
636 falseFormat
= prefix
+ 't' * len(false
)
638 print 'trying bool pack/unpack on', false
, 'using format', falseFormat
639 packedFalse
= struct
.pack(falseFormat
, *false
)
640 unpackedFalse
= struct
.unpack(falseFormat
, packedFalse
)
642 trueFormat
= prefix
+ 't' * len(true
)
644 print 'trying bool pack/unpack on', true
, 'using format', trueFormat
645 packedTrue
= struct
.pack(trueFormat
, *true
)
646 unpackedTrue
= struct
.unpack(trueFormat
, packedTrue
)
648 if len(true
) != len(unpackedTrue
):
649 raise TestFailed('unpacked true array is not of same size as input')
650 if len(false
) != len(unpackedFalse
):
651 raise TestFailed('unpacked false array is not of same size as input')
653 for t
in unpackedFalse
:
655 raise TestFailed('%r did not unpack as False' % t
)
656 for t
in unpackedTrue
:
658 raise TestFailed('%r did not unpack as false' % t
)
660 if prefix
and verbose
:
661 print 'trying size of bool with format %r' % (prefix
+'t')
662 packed
= struct
.pack(prefix
+'t', 1)
664 if len(packed
) != struct
.calcsize(prefix
+'t'):
665 raise TestFailed('packed length is not equal to calculated size')
667 if len(packed
) != 1 and prefix
:
668 raise TestFailed('encoded bool is not one byte: %r' % packed
)
669 elif not prefix
and verbose
:
670 print 'size of bool in native format is %i' % (len(packed
))
672 for c
in '\x01\x7f\xff\x0f\xf0':
673 if struct
.unpack('>t', c
)[0] is not True:
674 raise TestFailed('%c did not unpack as True' % c
)