diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-06-12 01:22:22 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-06-12 01:22:22 (GMT) |
commit | 7a3bfc3a472dafc42d20845389eb79db8af0b046 (patch) | |
tree | 5b59ec1db42d4559a21af550c3b068b053ac79d2 /Lib | |
parent | ac4797a12eed2fb5bcc68ae6e768e5ab4ec5b422 (diff) | |
download | cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.zip cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.tar.gz cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.tar.bz2 |
Added q/Q standard (x-platform 8-byte ints) mode in struct module.
This completes the q/Q project.
longobject.c _PyLong_AsByteArray: The original code had a gross bug:
the most-significant Python digit doesn't necessarily have SHIFT
significant bits, and you really need to count how many copies of the sign
bit it has else spurious overflow errors result.
test_struct.py: This now does exhaustive std q/Q testing at, and on both
sides of, all relevant power-of-2 boundaries, both positive and negative.
NEWS: Added brief dict news while I was at it.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_struct.py | 171 |
1 files changed, 165 insertions, 6 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index c977913..e6c8bb2 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -12,6 +12,16 @@ def simple_err(func, *args): func.__name__, args) ## pdb.set_trace() +def any_err(func, *args): + try: + apply(func, args) + except (struct.error, OverflowError, TypeError): + pass + else: + raise TestFailed, "%s%s did not raise error" % ( + func.__name__, args) +## pdb.set_trace() + simple_err(struct.calcsize, 'Z') sz = struct.calcsize('i') @@ -113,7 +123,8 @@ for fmt, arg, big, lil, asy in tests: raise TestFailed, "unpack(%s, %s) -> (%s,) # expected (%s,)" % ( `fmt`, `res`, `rev`, `arg`) -# Some q/Q sanity checks. +########################################################################### +# q/Q tests. has_native_qQ = 1 try: @@ -124,18 +135,22 @@ except struct.error: if verbose: print "Platform has native q/Q?", has_native_qQ and "Yes." or "No." -simple_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless +any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless simple_err(struct.pack, "Q", "a") # ditto, but 'Q' +def string_reverse(s): + chars = list(s) + chars.reverse() + return "".join(chars) + def bigendian_to_native(value): if isbigendian: return value - chars = list(value) - chars.reverse() - return "".join(chars) + else: + return string_reverse(value) -if has_native_qQ: +def test_native_qQ(): bytes = struct.calcsize('q') # The expected values here are in big-endian format, primarily because # I'm on a little-endian machine and so this is the clearest way (for @@ -156,3 +171,147 @@ if has_native_qQ: verify(retrieved == input, "%r-unpack of %r gave %r, not %r" % (format, got, retrieved, input)) + +if has_native_qQ: + test_native_qQ() + +# Standard q/Q (8 bytes; should work on all platforms). + +MIN_Q, MAX_Q = 0, 2L**64 - 1 +MIN_q, MAX_q = -(2L**63), 2L**63 - 1 + +import binascii +def test_one_qQ(x, pack=struct.pack, + unpack=struct.unpack, + unhexlify=binascii.unhexlify): + if verbose: + print "trying std q/Q on", x, "==", hex(x) + + # Try 'q'. + if MIN_q <= x <= MAX_q: + # Try '>q'. + expected = long(x) + if x < 0: + expected += 1L << 64 + assert expected > 0 + expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' + if len(expected) & 1: + expected = "0" + expected + expected = unhexlify(expected) + expected = "\x00" * (8 - len(expected)) + expected + + # >q pack work? + got = pack(">q", x) + verify(got == expected, + "'>q'-pack of %r gave %r, not %r" % + (x, got, expected)) + + # >q unpack work? + retrieved = unpack(">q", got)[0] + verify(x == retrieved, + "'>q'-unpack of %r gave %r, not %r" % + (got, retrieved, x)) + + # Adding any byte should cause a "too big" error. + any_err(unpack, ">q", '\x01' + got) + + # Try '<q'. + expected = string_reverse(expected) + + # <q pack work? + got = pack("<q", x) + verify(got == expected, + "'<q'-pack of %r gave %r, not %r" % + (x, got, expected)) + + # <q unpack work? + retrieved = unpack("<q", got)[0] + verify(x == retrieved, + "'<q'-unpack of %r gave %r, not %r" % + (got, retrieved, x)) + + # Adding any byte should cause a "too big" error. + any_err(unpack, "<q", '\x01' + got) + + else: + # x is out of q's range -- verify pack realizes that. + any_err(pack, '>q', x) + any_err(pack, '<q', x) + + # Much the same for 'Q'. + if MIN_Q <= x <= MAX_Q: + # Try '>Q'. + expected = long(x) + expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' + if len(expected) & 1: + expected = "0" + expected + expected = unhexlify(expected) + expected = "\x00" * (8 - len(expected)) + expected + + # >Q pack work? + got = pack(">Q", x) + verify(got == expected, + "'>Q'-pack of %r gave %r, not %r" % + (x, got, expected)) + + # >Q unpack work? + retrieved = unpack(">Q", got)[0] + verify(x == retrieved, + "'>Q'-unpack of %r gave %r, not %r" % + (got, retrieved, x)) + + # Adding any byte should cause a "too big" error. + any_err(unpack, ">Q", '\x01' + got) + + # Try '<Q'. + expected = string_reverse(expected) + + # <Q pack work? + got = pack("<Q", x) + verify(got == expected, + "'<Q'-pack of %r gave %r, not %r" % + (x, got, expected)) + + # <Q unpack work? + retrieved = unpack("<Q", got)[0] + verify(x == retrieved, + "'<Q'-unpack of %r gave %r, not %r" % + (got, retrieved, x)) + + # Adding any byte should cause a "too big" error. + any_err(unpack, "<Q", '\x01' + got) + + else: + # x is out of Q's range -- verify pack realizes that. + any_err(pack, '>Q', x) + any_err(pack, '<Q', x) + +def test_std_qQ(): + from random import randrange + + # Create all interesting powers of 2. + values = [] + for exp in range(70): + values.append(1L << exp) + + # Add some random 64-bit values. + for i in range(50): + val = 0L + for j in range(8): + val = (val << 8) | randrange(256) + values.append(val) + + # Try all those, and their negations, and +-1 from them. Note + # that this tests all power-of-2 boundaries in range, and a few out + # of range, plus +-(2**n +- 1). + for base in values: + for val in -base, base: + for incr in -1, 0, 1: + x = val + incr + try: + x = int(x) + except OverflowError: + pass + test_one_qQ(x) + +test_std_qQ() |