openfile(): Go back to opening the files in text mode. This undoes
[python/dscho.git] / Lib / test / test_struct.py
blobb9895d458e0b44ebeecf9f6709a7dea932474f40
1 from test.test_support import TestFailed, verbose, verify
2 import struct
3 ## import pdb
5 import sys
6 ISBIGENDIAN = sys.byteorder == "big"
7 del sys
8 verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
9 "bigendian determination appears wrong")
11 def string_reverse(s):
12 chars = list(s)
13 chars.reverse()
14 return "".join(chars)
16 def bigendian_to_native(value):
17 if ISBIGENDIAN:
18 return value
19 else:
20 return string_reverse(value)
22 def simple_err(func, *args):
23 try:
24 apply(func, args)
25 except struct.error:
26 pass
27 else:
28 raise TestFailed, "%s%s did not raise struct.error" % (
29 func.__name__, args)
30 ## pdb.set_trace()
32 def any_err(func, *args):
33 try:
34 apply(func, args)
35 except (struct.error, OverflowError, TypeError):
36 pass
37 else:
38 raise TestFailed, "%s%s did not raise error" % (
39 func.__name__, args)
40 ## pdb.set_trace()
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)
53 if sz * 3 != sz3:
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)
65 c = 'a'
66 b = 1
67 h = 255
68 i = 65535
69 l = 65536
70 f = 3.1415
71 d = 3.1415
73 for prefix in ('', '@', '<', '>', '=', '!'):
74 for format in ('xcbhilfd', 'xcBHILfd'):
75 format = prefix + format
76 if verbose:
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)
89 tests = [
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:
125 if verbose:
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)
130 if res != exp:
131 raise TestFailed, "pack(%s, %s) -> %s # expected %s" % (
132 `fmt`, `arg`, `res`, `exp`)
133 n = struct.calcsize(xfmt)
134 if n != len(res):
135 raise TestFailed, "calcsize(%s) -> %d # expected %d" % (
136 `xfmt`, n, len(res))
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.
145 has_native_qQ = 1
146 try:
147 struct.pack("q", 5)
148 except struct.error:
149 has_native_qQ = 0
151 if verbose:
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))
180 if has_native_qQ:
181 test_native_qQ()
183 ###########################################################################
184 # Standard integer tests (bBhHiIlLqQ).
186 import binascii
188 class IntTester:
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):
214 if verbose:
215 print "trying std", self.formatpair, "on", x, "==", hex(x)
217 # Try signed.
218 code = self.signed_code
219 if self.signed_min <= x <= self.signed_max:
220 # Try big-endian.
221 expected = long(x)
222 if x < 0:
223 expected += 1L << self.bitsize
224 assert expected > 0
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
231 # Pack work?
232 format = ">" + code
233 got = pack(format, x)
234 verify(got == expected,
235 "'%s'-pack of %r gave %r, not %r" %
236 (format, x, got, expected))
238 # Unpack work?
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)
247 # Try little-endian.
248 format = "<" + code
249 expected = string_reverse(expected)
251 # Pack work?
252 got = pack(format, x)
253 verify(got == expected,
254 "'%s'-pack of %r gave %r, not %r" %
255 (format, x, got, expected))
257 # Unpack work?
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)
266 else:
267 # x is out of range -- verify pack realizes that.
268 if code in self.BUGGY_RANGE_CHECK:
269 if verbose:
270 print "Skipping buggy range check for code", code
271 else:
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:
278 # Try big-endian.
279 format = ">" + code
280 expected = long(x)
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
287 # Pack work?
288 got = pack(format, x)
289 verify(got == expected,
290 "'%s'-pack of %r gave %r, not %r" %
291 (format, x, got, expected))
293 # Unpack work?
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)
302 # Try little-endian.
303 format = "<" + code
304 expected = string_reverse(expected)
306 # Pack work?
307 got = pack(format, x)
308 verify(got == expected,
309 "'%s'-pack of %r gave %r, not %r" %
310 (format, x, got, expected))
312 # Unpack work?
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)
321 else:
322 # x is out of range -- verify pack realizes that.
323 if code in self.BUGGY_RANGE_CHECK:
324 if verbose:
325 print "Skipping buggy range check for code", code
326 else:
327 any_err(pack, ">" + code, x)
328 any_err(pack, "<" + code, x)
330 def run(self):
331 from random import randrange
333 # Create all interesting powers of 2.
334 values = []
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):
340 val = 0L
341 for j in range(self.bytesize):
342 val = (val << 8) | randrange(256)
343 values.append(val)
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).
348 for base in values:
349 for val in -base, base:
350 for incr in -1, 0, 1:
351 x = val + incr
352 try:
353 x = int(x)
354 except OverflowError:
355 pass
356 self.test_one(x)
358 # Some error cases.
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),
365 ("hH", 2),
366 ("iI", 4),
367 ("lL", 4),
368 ("qQ", 8)]:
369 t = IntTester(*args)
370 t.run()
373 ###########################################################################
374 # The p ("Pascal string") code.
376 def test_p_code():
377 for code, input, expected, expectedback in [
378 ('p','abc', '\x00', ''),
379 ('1p', 'abc', '\x00', ''),
380 ('2p', 'abc', '\x01a', 'a'),
381 ('3p', 'abc', '\x02ab', 'ab'),
382 ('4p', 'abc', '\x03abc', 'abc'),
383 ('5p', 'abc', '\x03abc\x00', 'abc'),
384 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
385 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
386 got = struct.pack(code, input)
387 if got != expected:
388 raise TestFailed("pack(%r, %r) == %r but expected %r" %
389 (code, input, got, expected))
390 (got,) = struct.unpack(code, got)
391 if got != expectedback:
392 raise TestFailed("unpack(%r, %r) == %r but expected %r" %
393 (code, input, got, expectedback))
395 test_p_code()