summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_struct.py
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-06-12 01:22:22 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-06-12 01:22:22 (GMT)
commit7a3bfc3a472dafc42d20845389eb79db8af0b046 (patch)
tree5b59ec1db42d4559a21af550c3b068b053ac79d2 /Lib/test/test_struct.py
parentac4797a12eed2fb5bcc68ae6e768e5ab4ec5b422 (diff)
downloadcpython-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/test/test_struct.py')
-rw-r--r--Lib/test/test_struct.py171
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()