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