PyXR

c:\python24\lib \ test \ test_struct.py



0001 from test.test_support import TestFailed, verbose, verify
0002 import struct
0003 
0004 import sys
0005 ISBIGENDIAN = sys.byteorder == "big"
0006 del sys
0007 verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
0008        "bigendian determination appears wrong")
0009 
0010 def string_reverse(s):
0011     chars = list(s)
0012     chars.reverse()
0013     return "".join(chars)
0014 
0015 def bigendian_to_native(value):
0016     if ISBIGENDIAN:
0017         return value
0018     else:
0019         return string_reverse(value)
0020 
0021 def simple_err(func, *args):
0022     try:
0023         func(*args)
0024     except struct.error:
0025         pass
0026     else:
0027         raise TestFailed, "%s%s did not raise struct.error" % (
0028             func.__name__, args)
0029 
0030 def any_err(func, *args):
0031     try:
0032         func(*args)
0033     except (struct.error, OverflowError, TypeError):
0034         pass
0035     else:
0036         raise TestFailed, "%s%s did not raise error" % (
0037             func.__name__, args)
0038 
0039 
0040 simple_err(struct.calcsize, 'Z')
0041 
0042 sz = struct.calcsize('i')
0043 if sz * 3 != struct.calcsize('iii'):
0044     raise TestFailed, 'inconsistent sizes'
0045 
0046 fmt = 'cbxxxxxxhhhhiillffd'
0047 fmt3 = '3c3b18x12h6i6l6f3d'
0048 sz = struct.calcsize(fmt)
0049 sz3 = struct.calcsize(fmt3)
0050 if sz * 3 != sz3:
0051     raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % (
0052         fmt, sz, 3*sz, fmt3, sz3)
0053 
0054 simple_err(struct.pack, 'iii', 3)
0055 simple_err(struct.pack, 'i', 3, 3, 3)
0056 simple_err(struct.pack, 'i', 'foo')
0057 simple_err(struct.pack, 'P', 'foo')
0058 simple_err(struct.unpack, 'd', 'flap')
0059 s = struct.pack('ii', 1, 2)
0060 simple_err(struct.unpack, 'iii', s)
0061 simple_err(struct.unpack, 'i', s)
0062 
0063 c = 'a'
0064 b = 1
0065 h = 255
0066 i = 65535
0067 l = 65536
0068 f = 3.1415
0069 d = 3.1415
0070 
0071 for prefix in ('', '@', '<', '>', '=', '!'):
0072     for format in ('xcbhilfd', 'xcBHILfd'):
0073         format = prefix + format
0074         if verbose:
0075             print "trying:", format
0076         s = struct.pack(format, c, b, h, i, l, f, d)
0077         cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s)
0078         if (cp != c or bp != b or hp != h or ip != i or lp != l or
0079             int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)):
0080             # ^^^ calculate only to two decimal places
0081             raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
0082                 str(format), str((cp, bp, hp, ip, lp, fp, dp)))
0083 
0084 # Test some of the new features in detail
0085 
0086 # (format, argument, big-endian result, little-endian result, asymmetric)
0087 tests = [
0088     ('c', 'a', 'a', 'a', 0),
0089     ('xc', 'a', '\0a', '\0a', 0),
0090     ('cx', 'a', 'a\0', 'a\0', 0),
0091     ('s', 'a', 'a', 'a', 0),
0092     ('0s', 'helloworld', '', '', 1),
0093     ('1s', 'helloworld', 'h', 'h', 1),
0094     ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
0095     ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
0096     ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
0097     ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
0098     ('b', 7, '\7', '\7', 0),
0099     ('b', -7, '\371', '\371', 0),
0100     ('B', 7, '\7', '\7', 0),
0101     ('B', 249, '\371', '\371', 0),
0102     ('h', 700, '\002\274', '\274\002', 0),
0103     ('h', -700, '\375D', 'D\375', 0),
0104     ('H', 700, '\002\274', '\274\002', 0),
0105     ('H', 0x10000-700, '\375D', 'D\375', 0),
0106     ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
0107     ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
0108     ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
0109     ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
0110     ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
0111     ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
0112     ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
0113     ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
0114     ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
0115     ('d', 2.0, '@\000\000\000\000\000\000\000',
0116                '\000\000\000\000\000\000\000@', 0),
0117     ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
0118     ('d', -2.0, '\300\000\000\000\000\000\000\000',
0119                '\000\000\000\000\000\000\000\300', 0),
0120 ]
0121 
0122 for fmt, arg, big, lil, asy in tests:
0123     if verbose:
0124         print "%r %r %r %r" % (fmt, arg, big, lil)
0125     for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
0126                         ('='+fmt, ISBIGENDIAN and big or lil)]:
0127         res = struct.pack(xfmt, arg)
0128         if res != exp:
0129             raise TestFailed, "pack(%r, %r) -> %r # expected %r" % (
0130                 fmt, arg, res, exp)
0131         n = struct.calcsize(xfmt)
0132         if n != len(res):
0133             raise TestFailed, "calcsize(%r) -> %d # expected %d" % (
0134                 xfmt, n, len(res))
0135         rev = struct.unpack(xfmt, res)[0]
0136         if rev != arg and not asy:
0137             raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % (
0138                 fmt, res, rev, arg)
0139 
0140 ###########################################################################
0141 # Simple native q/Q tests.
0142 
0143 has_native_qQ = 1
0144 try:
0145     struct.pack("q", 5)
0146 except struct.error:
0147     has_native_qQ = 0
0148 
0149 if verbose:
0150     print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
0151 
0152 any_err(struct.pack, "Q", -1)   # can't pack -1 as unsigned regardless
0153 simple_err(struct.pack, "q", "a")  # can't pack string as 'q' regardless
0154 simple_err(struct.pack, "Q", "a")  # ditto, but 'Q'
0155 
0156 def test_native_qQ():
0157     bytes = struct.calcsize('q')
0158     # The expected values here are in big-endian format, primarily because
0159     # I'm on a little-endian machine and so this is the clearest way (for
0160     # me) to force the code to get exercised.
0161     for format, input, expected in (
0162             ('q', -1, '\xff' * bytes),
0163             ('q', 0, '\x00' * bytes),
0164             ('Q', 0, '\x00' * bytes),
0165             ('q', 1L, '\x00' * (bytes-1) + '\x01'),
0166             ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
0167             ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
0168         got = struct.pack(format, input)
0169         native_expected = bigendian_to_native(expected)
0170         verify(got == native_expected,
0171                "%r-pack of %r gave %r, not %r" %
0172                     (format, input, got, native_expected))
0173         retrieved = struct.unpack(format, got)[0]
0174         verify(retrieved == input,
0175                "%r-unpack of %r gave %r, not %r" %
0176                     (format, got, retrieved, input))
0177 
0178 if has_native_qQ:
0179     test_native_qQ()
0180 
0181 ###########################################################################
0182 # Standard integer tests (bBhHiIlLqQ).
0183 
0184 import binascii
0185 
0186 class IntTester:
0187 
0188     # XXX Most std integer modes fail to test for out-of-range.
0189     # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
0190     # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
0191     # reported by Mark Favas).
0192     BUGGY_RANGE_CHECK = "bBhHiIlL"
0193 
0194     def __init__(self, formatpair, bytesize):
0195         assert len(formatpair) == 2
0196         self.formatpair = formatpair
0197         for direction in "<>!=":
0198             for code in formatpair:
0199                 format = direction + code
0200                 verify(struct.calcsize(format) == bytesize)
0201         self.bytesize = bytesize
0202         self.bitsize = bytesize * 8
0203         self.signed_code, self.unsigned_code = formatpair
0204         self.unsigned_min = 0
0205         self.unsigned_max = 2L**self.bitsize - 1
0206         self.signed_min = -(2L**(self.bitsize-1))
0207         self.signed_max = 2L**(self.bitsize-1) - 1
0208 
0209     def test_one(self, x, pack=struct.pack,
0210                           unpack=struct.unpack,
0211                           unhexlify=binascii.unhexlify):
0212         if verbose:
0213             print "trying std", self.formatpair, "on", x, "==", hex(x)
0214 
0215         # Try signed.
0216         code = self.signed_code
0217         if self.signed_min <= x <= self.signed_max:
0218             # Try big-endian.
0219             expected = long(x)
0220             if x < 0:
0221                 expected += 1L << self.bitsize
0222                 assert expected > 0
0223             expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
0224             if len(expected) & 1:
0225                 expected = "0" + expected
0226             expected = unhexlify(expected)
0227             expected = "\x00" * (self.bytesize - len(expected)) + expected
0228 
0229             # Pack work?
0230             format = ">" + code
0231             got = pack(format, x)
0232             verify(got == expected,
0233                    "'%s'-pack of %r gave %r, not %r" %
0234                     (format, x, got, expected))
0235 
0236             # Unpack work?
0237             retrieved = unpack(format, got)[0]
0238             verify(x == retrieved,
0239                    "'%s'-unpack of %r gave %r, not %r" %
0240                     (format, got, retrieved, x))
0241 
0242             # Adding any byte should cause a "too big" error.
0243             any_err(unpack, format, '\x01' + got)
0244 
0245             # Try little-endian.
0246             format = "<" + code
0247             expected = string_reverse(expected)
0248 
0249             # Pack work?
0250             got = pack(format, x)
0251             verify(got == expected,
0252                    "'%s'-pack of %r gave %r, not %r" %
0253                     (format, x, got, expected))
0254 
0255             # Unpack work?
0256             retrieved = unpack(format, got)[0]
0257             verify(x == retrieved,
0258                    "'%s'-unpack of %r gave %r, not %r" %
0259                     (format, got, retrieved, x))
0260 
0261             # Adding any byte should cause a "too big" error.
0262             any_err(unpack, format, '\x01' + got)
0263 
0264         else:
0265             # x is out of range -- verify pack realizes that.
0266             if code in self.BUGGY_RANGE_CHECK:
0267                 if verbose:
0268                     print "Skipping buggy range check for code", code
0269             else:
0270                 any_err(pack, ">" + code, x)
0271                 any_err(pack, "<" + code, x)
0272 
0273         # Much the same for unsigned.
0274         code = self.unsigned_code
0275         if self.unsigned_min <= x <= self.unsigned_max:
0276             # Try big-endian.
0277             format = ">" + code
0278             expected = long(x)
0279             expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
0280             if len(expected) & 1:
0281                 expected = "0" + expected
0282             expected = unhexlify(expected)
0283             expected = "\x00" * (self.bytesize - len(expected)) + expected
0284 
0285             # Pack work?
0286             got = pack(format, x)
0287             verify(got == expected,
0288                    "'%s'-pack of %r gave %r, not %r" %
0289                     (format, x, got, expected))
0290 
0291             # Unpack work?
0292             retrieved = unpack(format, got)[0]
0293             verify(x == retrieved,
0294                    "'%s'-unpack of %r gave %r, not %r" %
0295                     (format, got, retrieved, x))
0296 
0297             # Adding any byte should cause a "too big" error.
0298             any_err(unpack, format, '\x01' + got)
0299 
0300             # Try little-endian.
0301             format = "<" + code
0302             expected = string_reverse(expected)
0303 
0304             # Pack work?
0305             got = pack(format, x)
0306             verify(got == expected,
0307                    "'%s'-pack of %r gave %r, not %r" %
0308                     (format, x, got, expected))
0309 
0310             # Unpack work?
0311             retrieved = unpack(format, got)[0]
0312             verify(x == retrieved,
0313                    "'%s'-unpack of %r gave %r, not %r" %
0314                     (format, got, retrieved, x))
0315 
0316             # Adding any byte should cause a "too big" error.
0317             any_err(unpack, format, '\x01' + got)
0318 
0319         else:
0320             # x is out of range -- verify pack realizes that.
0321             if code in self.BUGGY_RANGE_CHECK:
0322                 if verbose:
0323                     print "Skipping buggy range check for code", code
0324             else:
0325                 any_err(pack, ">" + code, x)
0326                 any_err(pack, "<" + code, x)
0327 
0328     def run(self):
0329         from random import randrange
0330 
0331         # Create all interesting powers of 2.
0332         values = []
0333         for exp in range(self.bitsize + 3):
0334             values.append(1L << exp)
0335 
0336         # Add some random values.
0337         for i in range(self.bitsize):
0338             val = 0L
0339             for j in range(self.bytesize):
0340                 val = (val << 8) | randrange(256)
0341             values.append(val)
0342 
0343         # Try all those, and their negations, and +-1 from them.  Note
0344         # that this tests all power-of-2 boundaries in range, and a few out
0345         # of range, plus +-(2**n +- 1).
0346         for base in values:
0347             for val in -base, base:
0348                 for incr in -1, 0, 1:
0349                     x = val + incr
0350                     try:
0351                         x = int(x)
0352                     except OverflowError:
0353                         pass
0354                     self.test_one(x)
0355 
0356         # Some error cases.
0357         for direction in "<>":
0358             for code in self.formatpair:
0359                 for badobject in "a string", 3+42j, randrange:
0360                     any_err(struct.pack, direction + code, badobject)
0361 
0362 for args in [("bB", 1),
0363              ("hH", 2),
0364              ("iI", 4),
0365              ("lL", 4),
0366              ("qQ", 8)]:
0367     t = IntTester(*args)
0368     t.run()
0369 
0370 
0371 ###########################################################################
0372 # The p ("Pascal string") code.
0373 
0374 def test_p_code():
0375     for code, input, expected, expectedback in [
0376             ('p','abc', '\x00', ''),
0377             ('1p', 'abc', '\x00', ''),
0378             ('2p', 'abc', '\x01a', 'a'),
0379             ('3p', 'abc', '\x02ab', 'ab'),
0380             ('4p', 'abc', '\x03abc', 'abc'),
0381             ('5p', 'abc', '\x03abc\x00', 'abc'),
0382             ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
0383             ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
0384         got = struct.pack(code, input)
0385         if got != expected:
0386             raise TestFailed("pack(%r, %r) == %r but expected %r" %
0387                              (code, input, got, expected))
0388         (got,) = struct.unpack(code, got)
0389         if got != expectedback:
0390             raise TestFailed("unpack(%r, %r) == %r but expected %r" %
0391                              (code, input, got, expectedback))
0392 
0393 test_p_code()
0394 
0395 
0396 ###########################################################################
0397 # SF bug 705836.  "<f" and ">f" had a severe rounding bug, where a carry
0398 # from the low-order discarded bits could propagate into the exponent
0399 # field, causing the result to be wrong by a factor of 2.
0400 
0401 def test_705836():
0402     import math
0403 
0404     for base in range(1, 33):
0405         # smaller <- largest representable float less than base.
0406         delta = 0.5
0407         while base - delta / 2.0 != base:
0408             delta /= 2.0
0409         smaller = base - delta
0410         # Packing this rounds away a solid string of trailing 1 bits.
0411         packed = struct.pack("<f", smaller)
0412         unpacked = struct.unpack("<f", packed)[0]
0413         # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
0414         # 16, respectively.
0415         verify(base == unpacked)
0416         bigpacked = struct.pack(">f", smaller)
0417         verify(bigpacked == string_reverse(packed),
0418                ">f pack should be byte-reversal of <f pack")
0419         unpacked = struct.unpack(">f", bigpacked)[0]
0420         verify(base == unpacked)
0421 
0422     # Largest finite IEEE single.
0423     big = (1 << 24) - 1
0424     big = math.ldexp(big, 127 - 23)
0425     packed = struct.pack(">f", big)
0426     unpacked = struct.unpack(">f", packed)[0]
0427     verify(big == unpacked)
0428 
0429     # The same, but tack on a 1 bit so it rounds up to infinity.
0430     big = (1 << 25) - 1
0431     big = math.ldexp(big, 127 - 24)
0432     try:
0433         packed = struct.pack(">f", big)
0434     except OverflowError:
0435         pass
0436     else:
0437         TestFailed("expected OverflowError")
0438 
0439 test_705836()
0440 

Generated by PyXR 0.9.4
SourceForge.net Logo