home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2004 #2 / K-CD-2-2004.ISO / OpenOffice Sv / f_0397 / python-core-2.2.2 / lib / test / test_struct.py < prev    next >
Encoding:
Python Source  |  2003-07-18  |  13.6 KB  |  396 lines

  1. from test_support import TestFailed, verbose, verify
  2. import struct
  3. ## import pdb
  4.  
  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")
  10.  
  11. def string_reverse(s):
  12.     chars = list(s)
  13.     chars.reverse()
  14.     return "".join(chars)
  15.  
  16. def bigendian_to_native(value):
  17.     if ISBIGENDIAN:
  18.         return value
  19.     else:
  20.         return string_reverse(value)
  21.  
  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()
  31.  
  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()
  41.  
  42.  
  43. simple_err(struct.calcsize, 'Z')
  44.  
  45. sz = struct.calcsize('i')
  46. if sz * 3 != struct.calcsize('iii'):
  47.     raise TestFailed, 'inconsistent sizes'
  48.  
  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)
  56.  
  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)
  64.  
  65. c = 'a'
  66. b = 1
  67. h = 255
  68. i = 65535
  69. l = 65536
  70. f = 3.1415
  71. d = 3.1415
  72.  
  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)))
  85.  
  86. # Test some of the new features in detail
  87.  
  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),
  122. ]
  123.  
  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`)
  141.  
  142. ###########################################################################
  143. # Simple native q/Q tests.
  144.  
  145. has_native_qQ = 1
  146. try:
  147.     struct.pack("q", 5)
  148. except struct.error:
  149.     has_native_qQ = 0
  150.  
  151. if verbose:
  152.     print "Platform has native q/Q?", has_native_qQ and "Yes." or "No."
  153.  
  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'
  157.  
  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))
  179.  
  180. if has_native_qQ:
  181.     test_native_qQ()
  182.  
  183. ###########################################################################
  184. # Standard integer tests (bBhHiIlLqQ).
  185.  
  186. import binascii
  187.  
  188. class IntTester:
  189.  
  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"
  195.  
  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
  210.  
  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)
  216.  
  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
  230.  
  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))
  237.  
  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))
  243.  
  244.             # Adding any byte should cause a "too big" error.
  245.             any_err(unpack, format, '\x01' + got)
  246.  
  247.             # Try little-endian.
  248.             format = "<" + code
  249.             expected = string_reverse(expected)
  250.  
  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))
  256.  
  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))
  262.  
  263.             # Adding any byte should cause a "too big" error.
  264.             any_err(unpack, format, '\x01' + got)
  265.  
  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)
  274.  
  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
  286.  
  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))
  292.  
  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))
  298.  
  299.             # Adding any byte should cause a "too big" error.
  300.             any_err(unpack, format, '\x01' + got)
  301.  
  302.             # Try little-endian.
  303.             format = "<" + code
  304.             expected = string_reverse(expected)
  305.  
  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))
  311.  
  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))
  317.  
  318.             # Adding any byte should cause a "too big" error.
  319.             any_err(unpack, format, '\x01' + got)
  320.  
  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)
  329.  
  330.     def run(self):
  331.         from random import randrange
  332.  
  333.         # Create all interesting powers of 2.
  334.         values = []
  335.         for exp in range(self.bitsize + 3):
  336.             values.append(1L << exp)
  337.  
  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)
  344.  
  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)
  357.  
  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)
  363.  
  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()
  371.  
  372.  
  373. ###########################################################################
  374. # The p ("Pascal string") code.
  375.  
  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))
  394.  
  395. test_p_code()
  396.