home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 July / maximum-cd-2011-07.iso / DiscContents / LibO_3.3.2_Win_x86_install_multi.exe / libreoffice1.cab / test_struct.py < prev    next >
Encoding:
Python Source  |  2011-03-15  |  23.4 KB  |  580 lines

  1. import array
  2. import unittest
  3. import struct
  4. import warnings
  5.  
  6. from functools import wraps
  7. from test.test_support import TestFailed, verbose, run_unittest
  8.  
  9. import sys
  10. ISBIGENDIAN = sys.byteorder == "big"
  11. IS32BIT = sys.maxsize == 0x7fffffff
  12. del sys
  13.  
  14. try:
  15.     import _struct
  16. except ImportError:
  17.     PY_STRUCT_RANGE_CHECKING = 0
  18.     PY_STRUCT_OVERFLOW_MASKING = 1
  19.     PY_STRUCT_FLOAT_COERCE = 2
  20. else:
  21.     PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
  22.     PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
  23.     PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
  24.  
  25. def string_reverse(s):
  26.     return "".join(reversed(s))
  27.  
  28. def bigendian_to_native(value):
  29.     if ISBIGENDIAN:
  30.         return value
  31.     else:
  32.         return string_reverse(value)
  33.  
  34. def with_warning_restore(func):
  35.     @wraps(func)
  36.     def decorator(*args, **kw):
  37.         with warnings.catch_warnings():
  38.             # We need this function to warn every time, so stick an
  39.             # unqualifed 'always' at the head of the filter list
  40.             warnings.simplefilter("always")
  41.             warnings.filterwarnings("error", category=DeprecationWarning)
  42.             return func(*args, **kw)
  43.     return decorator
  44.  
  45. @with_warning_restore
  46. def deprecated_err(func, *args):
  47.     try:
  48.         func(*args)
  49.     except (struct.error, TypeError):
  50.         pass
  51.     except DeprecationWarning:
  52.         if not PY_STRUCT_OVERFLOW_MASKING:
  53.             raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
  54.                 func.__name__, args)
  55.     else:
  56.         raise TestFailed, "%s%s did not raise error" % (
  57.             func.__name__, args)
  58.  
  59.  
  60. class StructTest(unittest.TestCase):
  61.  
  62.     @with_warning_restore
  63.     def check_float_coerce(self, format, number):
  64.         # SF bug 1530559. struct.pack raises TypeError where it used to convert.
  65.         if PY_STRUCT_FLOAT_COERCE == 2:
  66.             # Test for pre-2.5 struct module
  67.             packed = struct.pack(format, number)
  68.             floored = struct.unpack(format, packed)[0]
  69.             self.assertEqual(floored, int(number),
  70.                              "did not correcly coerce float to int")
  71.             return
  72.         try:
  73.             struct.pack(format, number)
  74.         except (struct.error, TypeError):
  75.             if PY_STRUCT_FLOAT_COERCE:
  76.                 self.fail("expected DeprecationWarning for float coerce")
  77.         except DeprecationWarning:
  78.             if not PY_STRUCT_FLOAT_COERCE:
  79.                 self.fail("expected to raise struct.error for float coerce")
  80.         else:
  81.             self.fail("did not raise error for float coerce")
  82.  
  83.     def test_isbigendian(self):
  84.         self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
  85.  
  86.     def test_consistence(self):
  87.         self.assertRaises(struct.error, struct.calcsize, 'Z')
  88.  
  89.         sz = struct.calcsize('i')
  90.         self.assertEqual(sz * 3, struct.calcsize('iii'))
  91.  
  92.         fmt = 'cbxxxxxxhhhhiillffd?'
  93.         fmt3 = '3c3b18x12h6i6l6f3d3?'
  94.         sz = struct.calcsize(fmt)
  95.         sz3 = struct.calcsize(fmt3)
  96.         self.assertEqual(sz * 3, sz3)
  97.  
  98.         self.assertRaises(struct.error, struct.pack, 'iii', 3)
  99.         self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
  100.         self.assertRaises(struct.error, struct.pack, 'i', 'foo')
  101.         self.assertRaises(struct.error, struct.pack, 'P', 'foo')
  102.         self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
  103.         s = struct.pack('ii', 1, 2)
  104.         self.assertRaises(struct.error, struct.unpack, 'iii', s)
  105.         self.assertRaises(struct.error, struct.unpack, 'i', s)
  106.  
  107.     def test_transitiveness(self):
  108.         c = 'a'
  109.         b = 1
  110.         h = 255
  111.         i = 65535
  112.         l = 65536
  113.         f = 3.1415
  114.         d = 3.1415
  115.         t = True
  116.  
  117.         for prefix in ('', '@', '<', '>', '=', '!'):
  118.             for format in ('xcbhilfd?', 'xcBHILfd?'):
  119.                 format = prefix + format
  120.                 s = struct.pack(format, c, b, h, i, l, f, d, t)
  121.                 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
  122.                 self.assertEqual(cp, c)
  123.                 self.assertEqual(bp, b)
  124.                 self.assertEqual(hp, h)
  125.                 self.assertEqual(ip, i)
  126.                 self.assertEqual(lp, l)
  127.                 self.assertEqual(int(100 * fp), int(100 * f))
  128.                 self.assertEqual(int(100 * dp), int(100 * d))
  129.                 self.assertEqual(tp, t)
  130.  
  131.     def test_new_features(self):
  132.         # Test some of the new features in detail
  133.         # (format, argument, big-endian result, little-endian result, asymmetric)
  134.         tests = [
  135.             ('c', 'a', 'a', 'a', 0),
  136.             ('xc', 'a', '\0a', '\0a', 0),
  137.             ('cx', 'a', 'a\0', 'a\0', 0),
  138.             ('s', 'a', 'a', 'a', 0),
  139.             ('0s', 'helloworld', '', '', 1),
  140.             ('1s', 'helloworld', 'h', 'h', 1),
  141.             ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
  142.             ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
  143.             ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
  144.             ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
  145.             ('b', 7, '\7', '\7', 0),
  146.             ('b', -7, '\371', '\371', 0),
  147.             ('B', 7, '\7', '\7', 0),
  148.             ('B', 249, '\371', '\371', 0),
  149.             ('h', 700, '\002\274', '\274\002', 0),
  150.             ('h', -700, '\375D', 'D\375', 0),
  151.             ('H', 700, '\002\274', '\274\002', 0),
  152.             ('H', 0x10000-700, '\375D', 'D\375', 0),
  153.             ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
  154.             ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
  155.             ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
  156.             ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
  157.             ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
  158.             ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
  159.             ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
  160.             ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
  161.             ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
  162.             ('d', 2.0, '@\000\000\000\000\000\000\000',
  163.                        '\000\000\000\000\000\000\000@', 0),
  164.             ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
  165.             ('d', -2.0, '\300\000\000\000\000\000\000\000',
  166.                        '\000\000\000\000\000\000\000\300', 0),
  167.                 ('?', 0, '\0', '\0', 0),
  168.                 ('?', 3, '\1', '\1', 1),
  169.                 ('?', True, '\1', '\1', 0),
  170.                 ('?', [], '\0', '\0', 1),
  171.                 ('?', (1,), '\1', '\1', 1),
  172.         ]
  173.  
  174.         for fmt, arg, big, lil, asy in tests:
  175.             for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
  176.                                 ('='+fmt, ISBIGENDIAN and big or lil)]:
  177.                 res = struct.pack(xfmt, arg)
  178.                 self.assertEqual(res, exp)
  179.                 self.assertEqual(struct.calcsize(xfmt), len(res))
  180.                 rev = struct.unpack(xfmt, res)[0]
  181.                 if rev != arg:
  182.                     self.assert_(asy)
  183.  
  184.     def test_native_qQ(self):
  185.         # can't pack -1 as unsigned regardless
  186.         self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
  187.         # can't pack string as 'q' regardless
  188.         self.assertRaises(struct.error, struct.pack, "q", "a")
  189.         # ditto, but 'Q'
  190.         self.assertRaises(struct.error, struct.pack, "Q", "a")
  191.  
  192.         try:
  193.             struct.pack("q", 5)
  194.         except struct.error:
  195.             # does not have native q/Q
  196.             pass
  197.         else:
  198.             bytes = struct.calcsize('q')
  199.             # The expected values here are in big-endian format, primarily
  200.             # because I'm on a little-endian machine and so this is the
  201.             # clearest way (for me) to force the code to get exercised.
  202.             for format, input, expected in (
  203.                     ('q', -1, '\xff' * bytes),
  204.                     ('q', 0, '\x00' * bytes),
  205.                     ('Q', 0, '\x00' * bytes),
  206.                     ('q', 1L, '\x00' * (bytes-1) + '\x01'),
  207.                     ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
  208.                     ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
  209.                 got = struct.pack(format, input)
  210.                 native_expected = bigendian_to_native(expected)
  211.                 self.assertEqual(got, native_expected)
  212.                 retrieved = struct.unpack(format, got)[0]
  213.                 self.assertEqual(retrieved, input)
  214.  
  215.     def test_standard_integers(self):
  216.         # Standard integer tests (bBhHiIlLqQ).
  217.         import binascii
  218.  
  219.         class IntTester(unittest.TestCase):
  220.  
  221.             # XXX Most std integer modes fail to test for out-of-range.
  222.             # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
  223.             # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
  224.             # reported by Mark Favas).
  225.             BUGGY_RANGE_CHECK = "bBhHiIlL"
  226.  
  227.             def __init__(self, formatpair, bytesize):
  228.                 self.assertEqual(len(formatpair), 2)
  229.                 self.formatpair = formatpair
  230.                 for direction in "<>!=":
  231.                     for code in formatpair:
  232.                         format = direction + code
  233.                         self.assertEqual(struct.calcsize(format), bytesize)
  234.                 self.bytesize = bytesize
  235.                 self.bitsize = bytesize * 8
  236.                 self.signed_code, self.unsigned_code = formatpair
  237.                 self.unsigned_min = 0
  238.                 self.unsigned_max = 2L**self.bitsize - 1
  239.                 self.signed_min = -(2L**(self.bitsize-1))
  240.                 self.signed_max = 2L**(self.bitsize-1) - 1
  241.  
  242.             def test_one(self, x, pack=struct.pack,
  243.                                   unpack=struct.unpack,
  244.                                   unhexlify=binascii.unhexlify):
  245.                 # Try signed.
  246.                 code = self.signed_code
  247.                 if self.signed_min <= x <= self.signed_max:
  248.                     # Try big-endian.
  249.                     expected = long(x)
  250.                     if x < 0:
  251.                         expected += 1L << self.bitsize
  252.                         self.assert_(expected > 0)
  253.                     expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
  254.                     if len(expected) & 1:
  255.                         expected = "0" + expected
  256.                     expected = unhexlify(expected)
  257.                     expected = "\x00" * (self.bytesize - len(expected)) + expected
  258.  
  259.                     # Pack work?
  260.                     format = ">" + code
  261.                     got = pack(format, x)
  262.                     self.assertEqual(got, expected)
  263.  
  264.                     # Unpack work?
  265.                     retrieved = unpack(format, got)[0]
  266.                     self.assertEqual(x, retrieved)
  267.  
  268.                     # Adding any byte should cause a "too big" error.
  269.                     self.assertRaises((struct.error, TypeError), unpack, format,
  270.                                                                  '\x01' + got)
  271.                     # Try little-endian.
  272.                     format = "<" + code
  273.                     expected = string_reverse(expected)
  274.  
  275.                     # Pack work?
  276.                     got = pack(format, x)
  277.                     self.assertEqual(got, expected)
  278.  
  279.                     # Unpack work?
  280.                     retrieved = unpack(format, got)[0]
  281.                     self.assertEqual(x, retrieved)
  282.  
  283.                     # Adding any byte should cause a "too big" error.
  284.                     self.assertRaises((struct.error, TypeError), unpack, format,
  285.                                                                  '\x01' + got)
  286.  
  287.                 else:
  288.                     # x is out of range -- verify pack realizes that.
  289.                     if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
  290.                         if verbose:
  291.                             print "Skipping buggy range check for code", code
  292.                     else:
  293.                         deprecated_err(pack, ">" + code, x)
  294.                         deprecated_err(pack, "<" + code, x)
  295.  
  296.                 # Much the same for unsigned.
  297.                 code = self.unsigned_code
  298.                 if self.unsigned_min <= x <= self.unsigned_max:
  299.                     # Try big-endian.
  300.                     format = ">" + code
  301.                     expected = long(x)
  302.                     expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
  303.                     if len(expected) & 1:
  304.                         expected = "0" + expected
  305.                     expected = unhexlify(expected)
  306.                     expected = "\x00" * (self.bytesize - len(expected)) + expected
  307.  
  308.                     # Pack work?
  309.                     got = pack(format, x)
  310.                     self.assertEqual(got, expected)
  311.  
  312.                     # Unpack work?
  313.                     retrieved = unpack(format, got)[0]
  314.                     self.assertEqual(x, retrieved)
  315.  
  316.                     # Adding any byte should cause a "too big" error.
  317.                     self.assertRaises((struct.error, TypeError), unpack, format,
  318.                                                                  '\x01' + got)
  319.  
  320.                     # Try little-endian.
  321.                     format = "<" + code
  322.                     expected = string_reverse(expected)
  323.  
  324.                     # Pack work?
  325.                     got = pack(format, x)
  326.                     self.assertEqual(got, expected)
  327.  
  328.                     # Unpack work?
  329.                     retrieved = unpack(format, got)[0]
  330.                     self.assertEqual(x, retrieved)
  331.  
  332.                     # Adding any byte should cause a "too big" error.
  333.                     self.assertRaises((struct.error, TypeError), unpack, format,
  334.                                                                  '\x01' + got)
  335.  
  336.                 else:
  337.                     # x is out of range -- verify pack realizes that.
  338.                     if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
  339.                         if verbose:
  340.                             print "Skipping buggy range check for code", code
  341.                     else:
  342.                         deprecated_err(pack, ">" + code, x)
  343.                         deprecated_err(pack, "<" + code, x)
  344.  
  345.             def run(self):
  346.                 from random import randrange
  347.  
  348.                 # Create all interesting powers of 2.
  349.                 values = []
  350.                 for exp in range(self.bitsize + 3):
  351.                     values.append(1L << exp)
  352.  
  353.                 # Add some random values.
  354.                 for i in range(self.bitsize):
  355.                     val = 0L
  356.                     for j in range(self.bytesize):
  357.                         val = (val << 8) | randrange(256)
  358.                     values.append(val)
  359.  
  360.                 # Try all those, and their negations, and +-1 from them.  Note
  361.                 # that this tests all power-of-2 boundaries in range, and a few out
  362.                 # of range, plus +-(2**n +- 1).
  363.                 for base in values:
  364.                     for val in -base, base:
  365.                         for incr in -1, 0, 1:
  366.                             x = val + incr
  367.                             try:
  368.                                 x = int(x)
  369.                             except OverflowError:
  370.                                 pass
  371.                             self.test_one(x)
  372.  
  373.                 # Some error cases.
  374.                 for direction in "<>":
  375.                     for code in self.formatpair:
  376.                         for badobject in "a string", 3+42j, randrange:
  377.                             self.assertRaises((struct.error, TypeError),
  378.                                                struct.pack, direction + code,
  379.                                                badobject)
  380.  
  381.         for args in [("bB", 1),
  382.                      ("hH", 2),
  383.                      ("iI", 4),
  384.                      ("lL", 4),
  385.                      ("qQ", 8)]:
  386.             t = IntTester(*args)
  387.             t.run()
  388.  
  389.     def test_p_code(self):
  390.         # Test p ("Pascal string") code.
  391.         for code, input, expected, expectedback in [
  392.                 ('p','abc', '\x00', ''),
  393.                 ('1p', 'abc', '\x00', ''),
  394.                 ('2p', 'abc', '\x01a', 'a'),
  395.                 ('3p', 'abc', '\x02ab', 'ab'),
  396.                 ('4p', 'abc', '\x03abc', 'abc'),
  397.                 ('5p', 'abc', '\x03abc\x00', 'abc'),
  398.                 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
  399.                 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
  400.             got = struct.pack(code, input)
  401.             self.assertEqual(got, expected)
  402.             (got,) = struct.unpack(code, got)
  403.             self.assertEqual(got, expectedback)
  404.  
  405.     def test_705836(self):
  406.         # SF bug 705836.  "<f" and ">f" had a severe rounding bug, where a carry
  407.         # from the low-order discarded bits could propagate into the exponent
  408.         # field, causing the result to be wrong by a factor of 2.
  409.         import math
  410.  
  411.         for base in range(1, 33):
  412.             # smaller <- largest representable float less than base.
  413.             delta = 0.5
  414.             while base - delta / 2.0 != base:
  415.                 delta /= 2.0
  416.             smaller = base - delta
  417.             # Packing this rounds away a solid string of trailing 1 bits.
  418.             packed = struct.pack("<f", smaller)
  419.             unpacked = struct.unpack("<f", packed)[0]
  420.             # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
  421.             # 16, respectively.
  422.             self.assertEqual(base, unpacked)
  423.             bigpacked = struct.pack(">f", smaller)
  424.             self.assertEqual(bigpacked, string_reverse(packed))
  425.             unpacked = struct.unpack(">f", bigpacked)[0]
  426.             self.assertEqual(base, unpacked)
  427.  
  428.         # Largest finite IEEE single.
  429.         big = (1 << 24) - 1
  430.         big = math.ldexp(big, 127 - 23)
  431.         packed = struct.pack(">f", big)
  432.         unpacked = struct.unpack(">f", packed)[0]
  433.         self.assertEqual(big, unpacked)
  434.  
  435.         # The same, but tack on a 1 bit so it rounds up to infinity.
  436.         big = (1 << 25) - 1
  437.         big = math.ldexp(big, 127 - 24)
  438.         self.assertRaises(OverflowError, struct.pack, ">f", big)
  439.  
  440.     if PY_STRUCT_RANGE_CHECKING:
  441.         def test_1229380(self):
  442.             # SF bug 1229380. No struct.pack exception for some out of
  443.             # range integers
  444.             import sys
  445.             for endian in ('', '>', '<'):
  446.                 for cls in (int, long):
  447.                     for fmt in ('B', 'H', 'I', 'L'):
  448.                         deprecated_err(struct.pack, endian + fmt, cls(-1))
  449.  
  450.                     deprecated_err(struct.pack, endian + 'B', cls(300))
  451.                     deprecated_err(struct.pack, endian + 'H', cls(70000))
  452.  
  453.                 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
  454.                 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
  455.  
  456.     def XXXtest_1530559(self):
  457.         # XXX This is broken: see the bug report
  458.         # SF bug 1530559. struct.pack raises TypeError where it used to convert.
  459.         for endian in ('', '>', '<'):
  460.             for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
  461.                 self.check_float_coerce(endian + fmt, 1.0)
  462.                 self.check_float_coerce(endian + fmt, 1.5)
  463.  
  464.     def test_unpack_from(self):
  465.         test_string = 'abcd01234'
  466.         fmt = '4s'
  467.         s = struct.Struct(fmt)
  468.         for cls in (str, buffer):
  469.             data = cls(test_string)
  470.             self.assertEqual(s.unpack_from(data), ('abcd',))
  471.             self.assertEqual(s.unpack_from(data, 2), ('cd01',))
  472.             self.assertEqual(s.unpack_from(data, 4), ('0123',))
  473.             for i in xrange(6):
  474.                 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
  475.             for i in xrange(6, len(test_string) + 1):
  476.                 self.assertRaises(struct.error, s.unpack_from, data, i)
  477.         for cls in (str, buffer):
  478.             data = cls(test_string)
  479.             self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
  480.             self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
  481.             self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
  482.             for i in xrange(6):
  483.                 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
  484.             for i in xrange(6, len(test_string) + 1):
  485.                 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
  486.  
  487.     def test_pack_into(self):
  488.         test_string = 'Reykjavik rocks, eow!'
  489.         writable_buf = array.array('c', ' '*100)
  490.         fmt = '21s'
  491.         s = struct.Struct(fmt)
  492.  
  493.         # Test without offset
  494.         s.pack_into(writable_buf, 0, test_string)
  495.         from_buf = writable_buf.tostring()[:len(test_string)]
  496.         self.assertEqual(from_buf, test_string)
  497.  
  498.         # Test with offset.
  499.         s.pack_into(writable_buf, 10, test_string)
  500.         from_buf = writable_buf.tostring()[:len(test_string)+10]
  501.         self.assertEqual(from_buf, test_string[:10] + test_string)
  502.  
  503.         # Go beyond boundaries.
  504.         small_buf = array.array('c', ' '*10)
  505.         self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
  506.         self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
  507.  
  508.     def test_pack_into_fn(self):
  509.         test_string = 'Reykjavik rocks, eow!'
  510.         writable_buf = array.array('c', ' '*100)
  511.         fmt = '21s'
  512.         pack_into = lambda *args: struct.pack_into(fmt, *args)
  513.  
  514.         # Test without offset.
  515.         pack_into(writable_buf, 0, test_string)
  516.         from_buf = writable_buf.tostring()[:len(test_string)]
  517.         self.assertEqual(from_buf, test_string)
  518.  
  519.         # Test with offset.
  520.         pack_into(writable_buf, 10, test_string)
  521.         from_buf = writable_buf.tostring()[:len(test_string)+10]
  522.         self.assertEqual(from_buf, test_string[:10] + test_string)
  523.  
  524.         # Go beyond boundaries.
  525.         small_buf = array.array('c', ' '*10)
  526.         self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
  527.         self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
  528.  
  529.     def test_unpack_with_buffer(self):
  530.         # SF bug 1563759: struct.unpack doens't support buffer protocol objects
  531.         data1 = array.array('B', '\x12\x34\x56\x78')
  532.         data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
  533.         for data in [data1, data2]:
  534.             value, = struct.unpack('>I', data)
  535.             self.assertEqual(value, 0x12345678)
  536.  
  537.     def test_bool(self):
  538.         for prefix in tuple("<>!=")+('',):
  539.             false = (), [], [], '', 0
  540.             true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
  541.  
  542.             falseFormat = prefix + '?' * len(false)
  543.             packedFalse = struct.pack(falseFormat, *false)
  544.             unpackedFalse = struct.unpack(falseFormat, packedFalse)
  545.  
  546.             trueFormat = prefix + '?' * len(true)
  547.             packedTrue = struct.pack(trueFormat, *true)
  548.             unpackedTrue = struct.unpack(trueFormat, packedTrue)
  549.  
  550.             self.assertEqual(len(true), len(unpackedTrue))
  551.             self.assertEqual(len(false), len(unpackedFalse))
  552.  
  553.             for t in unpackedFalse:
  554.                 self.assertFalse(t)
  555.             for t in unpackedTrue:
  556.                 self.assertTrue(t)
  557.  
  558.             packed = struct.pack(prefix+'?', 1)
  559.  
  560.             self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
  561.  
  562.             if len(packed) != 1:
  563.                 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
  564.                                              %packed)
  565.  
  566.             for c in '\x01\x7f\xff\x0f\xf0':
  567.                 self.assertTrue(struct.unpack('>?', c)[0])
  568.  
  569.     if IS32BIT:
  570.         def test_crasher(self):
  571.             self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
  572.  
  573.  
  574.  
  575. def test_main():
  576.     run_unittest(StructTest)
  577.  
  578. if __name__ == '__main__':
  579.     test_main()
  580.