1 from test_support
import TestFailed
, verbose
, verify
6 ISBIGENDIAN
= sys
.byteorder
== "big"
8 verify((struct
.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN
,
9 "bigendian determination appears wrong")
11 def string_reverse(s
):
16 def bigendian_to_native(value
):
20 return string_reverse(value
)
22 def simple_err(func
, *args
):
28 raise TestFailed
, "%s%s did not raise struct.error" % (
32 def any_err(func
, *args
):
35 except (struct
.error
, OverflowError, TypeError):
38 raise TestFailed
, "%s%s did not raise error" % (
43 simple_err(struct
.calcsize
, 'Z')
45 sz
= struct
.calcsize('i')
46 if sz
* 3 != struct
.calcsize('iii'):
47 raise TestFailed
, 'inconsistent sizes'
49 fmt
= 'cbxxxxxxhhhhiillffd'
50 fmt3
= '3c3b18x12h6i6l6f3d'
51 sz
= struct
.calcsize(fmt
)
52 sz3
= struct
.calcsize(fmt3
)
54 raise TestFailed
, 'inconsistent sizes (3*%s -> 3*%d = %d, %s -> %d)' % (
55 `fmt`
, sz
, 3*sz
, `fmt3`
, sz3
)
57 simple_err(struct
.pack
, 'iii', 3)
58 simple_err(struct
.pack
, 'i', 3, 3, 3)
59 simple_err(struct
.pack
, 'i', 'foo')
60 simple_err(struct
.unpack
, 'd', 'flap')
61 s
= struct
.pack('ii', 1, 2)
62 simple_err(struct
.unpack
, 'iii', s
)
63 simple_err(struct
.unpack
, 'i', s
)
73 for prefix
in ('', '@', '<', '>', '=', '!'):
74 for format
in ('xcbhilfd', 'xcBHILfd'):
75 format
= prefix
+ format
77 print "trying:", format
78 s
= struct
.pack(format
, c
, b
, h
, i
, l
, f
, d
)
79 cp
, bp
, hp
, ip
, lp
, fp
, dp
= struct
.unpack(format
, s
)
80 if (cp
!= c
or bp
!= b
or hp
!= h
or ip
!= i
or lp
!= l
or
81 int(100 * fp
) != int(100 * f
) or int(100 * dp
) != int(100 * d
)):
82 # ^^^ calculate only to two decimal places
83 raise TestFailed
, "unpack/pack not transitive (%s, %s)" % (
84 str(format
), str((cp
, bp
, hp
, ip
, lp
, fp
, dp
)))
86 # Test some of the new features in detail
88 # (format, argument, big-endian result, little-endian result, asymmetric)
90 ('c', 'a', 'a', 'a', 0),
91 ('xc', 'a', '\0a', '\0a', 0),
92 ('cx', 'a', 'a\0', 'a\0', 0),
93 ('s', 'a', 'a', 'a', 0),
94 ('0s', 'helloworld', '', '', 1),
95 ('1s', 'helloworld', 'h', 'h', 1),
96 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
97 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
98 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
99 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
100 ('b', 7, '\7', '\7', 0),
101 ('b', -7, '\371', '\371', 0),
102 ('B', 7, '\7', '\7', 0),
103 ('B', 249, '\371', '\371', 0),
104 ('h', 700, '\002\274', '\274\002', 0),
105 ('h', -700, '\375D', 'D\375', 0),
106 ('H', 700, '\002\274', '\274\002', 0),
107 ('H', 0x10000-700, '\375D', 'D\375', 0),
108 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
109 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
110 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
111 ('I', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
112 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
113 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
114 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
115 ('L', 0x100000000L
-70000000, '\373\323\342\200', '\200\342\323\373', 0),
116 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
117 ('d', 2.0, '@\000\000\000\000\000\000\000',
118 '\000\000\000\000\000\000\000@', 0),
119 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
120 ('d', -2.0, '\300\000\000\000\000\000\000\000',
121 '\000\000\000\000\000\000\000\300', 0),
124 for fmt
, arg
, big
, lil
, asy
in tests
:
126 print `fmt`
, `arg`
, `big`
, `lil`
127 for (xfmt
, exp
) in [('>'+fmt
, big
), ('!'+fmt
, big
), ('<'+fmt
, lil
),
128 ('='+fmt
, ISBIGENDIAN
and big
or lil
)]:
129 res
= struct
.pack(xfmt
, arg
)
131 raise TestFailed
, "pack(%s, %s) -> %s # expected %s" % (
132 `fmt`
, `arg`
, `res`
, `exp`
)
133 n
= struct
.calcsize(xfmt
)
135 raise TestFailed
, "calcsize(%s) -> %d # expected %d" % (
137 rev
= struct
.unpack(xfmt
, res
)[0]
138 if rev
!= arg
and not asy
:
139 raise TestFailed
, "unpack(%s, %s) -> (%s,) # expected (%s,)" % (
140 `fmt`
, `res`
, `rev`
, `arg`
)
142 ###########################################################################
143 # Simple native q/Q tests.
152 print "Platform has native q/Q?", has_native_qQ
and "Yes." or "No."
154 any_err(struct
.pack
, "Q", -1) # can't pack -1 as unsigned regardless
155 simple_err(struct
.pack
, "q", "a") # can't pack string as 'q' regardless
156 simple_err(struct
.pack
, "Q", "a") # ditto, but 'Q'
158 def test_native_qQ():
159 bytes
= struct
.calcsize('q')
160 # The expected values here are in big-endian format, primarily because
161 # I'm on a little-endian machine and so this is the clearest way (for
162 # me) to force the code to get exercised.
163 for format
, input, expected
in (
164 ('q', -1, '\xff' * bytes
),
165 ('q', 0, '\x00' * bytes
),
166 ('Q', 0, '\x00' * bytes
),
167 ('q', 1L, '\x00' * (bytes
-1) + '\x01'),
168 ('Q', (1L << (8*bytes
))-1, '\xff' * bytes
),
169 ('q', (1L << (8*bytes
-1))-1, '\x7f' + '\xff' * (bytes
- 1))):
170 got
= struct
.pack(format
, input)
171 native_expected
= bigendian_to_native(expected
)
172 verify(got
== native_expected
,
173 "%r-pack of %r gave %r, not %r" %
174 (format
, input, got
, native_expected
))
175 retrieved
= struct
.unpack(format
, got
)[0]
176 verify(retrieved
== input,
177 "%r-unpack of %r gave %r, not %r" %
178 (format
, got
, retrieved
, input))
183 ###########################################################################
184 # Standard integer tests (bBhHiIlLqQ).
190 # XXX Most std integer modes fail to test for out-of-range.
191 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
192 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
193 # reported by Mark Favas).
194 BUGGY_RANGE_CHECK
= "bBhHiIlL"
196 def __init__(self
, formatpair
, bytesize
):
197 assert len(formatpair
) == 2
198 self
.formatpair
= formatpair
199 for direction
in "<>!=":
200 for code
in formatpair
:
201 format
= direction
+ code
202 verify(struct
.calcsize(format
) == bytesize
)
203 self
.bytesize
= bytesize
204 self
.bitsize
= bytesize
* 8
205 self
.signed_code
, self
.unsigned_code
= formatpair
206 self
.unsigned_min
= 0
207 self
.unsigned_max
= 2L**self
.bitsize
- 1
208 self
.signed_min
= -(2L**(self
.bitsize
-1))
209 self
.signed_max
= 2L**(self
.bitsize
-1) - 1
211 def test_one(self
, x
, pack
=struct
.pack
,
212 unpack
=struct
.unpack
,
213 unhexlify
=binascii
.unhexlify
):
215 print "trying std", self
.formatpair
, "on", x
, "==", hex(x
)
218 code
= self
.signed_code
219 if self
.signed_min
<= x
<= self
.signed_max
:
223 expected
+= 1L << self
.bitsize
225 expected
= hex(expected
)[2:-1] # chop "0x" and trailing 'L'
226 if len(expected
) & 1:
227 expected
= "0" + expected
228 expected
= unhexlify(expected
)
229 expected
= "\x00" * (self
.bytesize
- len(expected
)) + expected
233 got
= pack(format
, x
)
234 verify(got
== expected
,
235 "'%s'-pack of %r gave %r, not %r" %
236 (format
, x
, got
, expected
))
239 retrieved
= unpack(format
, got
)[0]
240 verify(x
== retrieved
,
241 "'%s'-unpack of %r gave %r, not %r" %
242 (format
, got
, retrieved
, x
))
244 # Adding any byte should cause a "too big" error.
245 any_err(unpack
, format
, '\x01' + got
)
249 expected
= string_reverse(expected
)
252 got
= pack(format
, x
)
253 verify(got
== expected
,
254 "'%s'-pack of %r gave %r, not %r" %
255 (format
, x
, got
, expected
))
258 retrieved
= unpack(format
, got
)[0]
259 verify(x
== retrieved
,
260 "'%s'-unpack of %r gave %r, not %r" %
261 (format
, got
, retrieved
, x
))
263 # Adding any byte should cause a "too big" error.
264 any_err(unpack
, format
, '\x01' + got
)
267 # x is out of range -- verify pack realizes that.
268 if code
in self
.BUGGY_RANGE_CHECK
:
270 print "Skipping buggy range check for code", code
272 any_err(pack
, ">" + code
, x
)
273 any_err(pack
, "<" + code
, x
)
275 # Much the same for unsigned.
276 code
= self
.unsigned_code
277 if self
.unsigned_min
<= x
<= self
.unsigned_max
:
281 expected
= hex(expected
)[2:-1] # chop "0x" and trailing 'L'
282 if len(expected
) & 1:
283 expected
= "0" + expected
284 expected
= unhexlify(expected
)
285 expected
= "\x00" * (self
.bytesize
- len(expected
)) + expected
288 got
= pack(format
, x
)
289 verify(got
== expected
,
290 "'%s'-pack of %r gave %r, not %r" %
291 (format
, x
, got
, expected
))
294 retrieved
= unpack(format
, got
)[0]
295 verify(x
== retrieved
,
296 "'%s'-unpack of %r gave %r, not %r" %
297 (format
, got
, retrieved
, x
))
299 # Adding any byte should cause a "too big" error.
300 any_err(unpack
, format
, '\x01' + got
)
304 expected
= string_reverse(expected
)
307 got
= pack(format
, x
)
308 verify(got
== expected
,
309 "'%s'-pack of %r gave %r, not %r" %
310 (format
, x
, got
, expected
))
313 retrieved
= unpack(format
, got
)[0]
314 verify(x
== retrieved
,
315 "'%s'-unpack of %r gave %r, not %r" %
316 (format
, got
, retrieved
, x
))
318 # Adding any byte should cause a "too big" error.
319 any_err(unpack
, format
, '\x01' + got
)
322 # x is out of range -- verify pack realizes that.
323 if code
in self
.BUGGY_RANGE_CHECK
:
325 print "Skipping buggy range check for code", code
327 any_err(pack
, ">" + code
, x
)
328 any_err(pack
, "<" + code
, x
)
331 from random
import randrange
333 # Create all interesting powers of 2.
335 for exp
in range(self
.bitsize
+ 3):
336 values
.append(1L << exp
)
338 # Add some random values.
339 for i
in range(self
.bitsize
):
341 for j
in range(self
.bytesize
):
342 val
= (val
<< 8) |
randrange(256)
345 # Try all those, and their negations, and +-1 from them. Note
346 # that this tests all power-of-2 boundaries in range, and a few out
347 # of range, plus +-(2**n +- 1).
349 for val
in -base
, base
:
350 for incr
in -1, 0, 1:
354 except OverflowError:
359 for direction
in "<>":
360 for code
in self
.formatpair
:
361 for badobject
in "a string", 3+42j
, randrange
:
362 any_err(struct
.pack
, direction
+ code
, badobject
)
364 for args
in [("bB", 1),