summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_struct.py
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-06-13 22:45:27 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-06-13 22:45:27 (GMT)
commit17e17d440644f780e793466b47ca354459a8d68a (patch)
tree319e7e3d00ff3b4990f0b2dcaf38169fb99ff890 /Lib/test/test_struct.py
parentf251d06a66dcadd4d64c6b4d2b3608f33c8a1868 (diff)
downloadcpython-17e17d440644f780e793466b47ca354459a8d68a.zip
cpython-17e17d440644f780e793466b47ca354459a8d68a.tar.gz
cpython-17e17d440644f780e793466b47ca354459a8d68a.tar.bz2
Generalize the new qQ std-mode tests to all int codes (bBhHiIlLqQ).
Unfortunately, the std-mode bBhHIL codes don't do any range-checking; if and when some of those get fixed, remove their letters from the IntTester.BUGGY_RANGE_CHECK string. In the meantime, a msg saying that range-tests are getting skipped is printed to stdout whenever one is skipped.
Diffstat (limited to 'Lib/test/test_struct.py')
-rw-r--r--Lib/test/test_struct.py360
1 files changed, 202 insertions, 158 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 31f4dd7..f7ad094 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -2,6 +2,23 @@ from test_support import TestFailed, verbose, verify
import struct
## import pdb
+import sys
+ISBIGENDIAN = sys.byteorder == "big"
+del sys
+verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN,
+ "bigendian determination appears wrong")
+
+def string_reverse(s):
+ chars = list(s)
+ chars.reverse()
+ return "".join(chars)
+
+def bigendian_to_native(value):
+ if ISBIGENDIAN:
+ return value
+ else:
+ return string_reverse(value)
+
def simple_err(func, *args):
try:
apply(func, args)
@@ -22,6 +39,7 @@ def any_err(func, *args):
func.__name__, args)
## pdb.set_trace()
+
simple_err(struct.calcsize, 'Z')
sz = struct.calcsize('i')
@@ -103,13 +121,11 @@ tests = [
'\000\000\000\000\000\000\000\300', 0),
]
-isbigendian = struct.pack('=i', 1)[0] == chr(0)
-
for fmt, arg, big, lil, asy in tests:
if verbose:
print `fmt`, `arg`, `big`, `lil`
for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
- ('='+fmt, isbigendian and big or lil)]:
+ ('='+fmt, ISBIGENDIAN and big or lil)]:
res = struct.pack(xfmt, arg)
if res != exp:
raise TestFailed, "pack(%s, %s) -> %s # expected %s" % (
@@ -124,7 +140,7 @@ for fmt, arg, big, lil, asy in tests:
`fmt`, `res`, `rev`, `arg`)
###########################################################################
-# q/Q tests.
+# Simple native q/Q tests.
has_native_qQ = 1
try:
@@ -139,17 +155,6 @@ 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
- else:
- return string_reverse(value)
-
def test_native_qQ():
bytes = struct.calcsize('q')
# The expected values here are in big-endian format, primarily because
@@ -175,149 +180,188 @@ def test_native_qQ():
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
+###########################################################################
+# Standard integer tests (bBhHiIlLqQ).
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)
-
- # Some error cases.
- for direction in "<>":
- for letter in "qQ":
- for badobject in "a string", 3+42j, randrange:
- any_err(struct.pack, direction + letter, badobject)
-
-test_std_qQ()
+class IntTester:
+
+ # XXX Most std integer modes fail to test for out-of-range.
+ BUGGY_RANGE_CHECK = "bBhHIL"
+
+ def __init__(self, formatpair, bytesize):
+ assert len(formatpair) == 2
+ self.formatpair = formatpair
+ for direction in "<>!=":
+ for code in formatpair:
+ format = direction + code
+ verify(struct.calcsize(format) == bytesize)
+ self.bytesize = bytesize
+ self.bitsize = bytesize * 8
+ self.signed_code, self.unsigned_code = formatpair
+ self.unsigned_min = 0
+ self.unsigned_max = 2L**self.bitsize - 1
+ self.signed_min = -(2L**(self.bitsize-1))
+ self.signed_max = 2L**(self.bitsize-1) - 1
+
+ def test_one(self, x, pack=struct.pack,
+ unpack=struct.unpack,
+ unhexlify=binascii.unhexlify):
+ if verbose:
+ print "trying std", self.formatpair, "on", x, "==", hex(x)
+
+ # Try signed.
+ code = self.signed_code
+ if self.signed_min <= x <= self.signed_max:
+ # Try big-endian.
+ expected = long(x)
+ if x < 0:
+ expected += 1L << self.bitsize
+ 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" * (self.bytesize - len(expected)) + expected
+
+ # Pack work?
+ format = ">" + code
+ got = pack(format, x)
+ verify(got == expected,
+ "'%s'-pack of %r gave %r, not %r" %
+ (format, x, got, expected))
+
+ # Unpack work?
+ retrieved = unpack(format, got)[0]
+ verify(x == retrieved,
+ "'%s'-unpack of %r gave %r, not %r" %
+ (format, got, retrieved, x))
+
+ # Adding any byte should cause a "too big" error.
+ any_err(unpack, format, '\x01' + got)
+
+ # Try little-endian.
+ format = "<" + code
+ expected = string_reverse(expected)
+
+ # Pack work?
+ got = pack(format, x)
+ verify(got == expected,
+ "'%s'-pack of %r gave %r, not %r" %
+ (format, x, got, expected))
+
+ # Unpack work?
+ retrieved = unpack(format, got)[0]
+ verify(x == retrieved,
+ "'%s'-unpack of %r gave %r, not %r" %
+ (format, got, retrieved, x))
+
+ # Adding any byte should cause a "too big" error.
+ any_err(unpack, format, '\x01' + got)
+
+ else:
+ # x is out of range -- verify pack realizes that.
+ if code in self.BUGGY_RANGE_CHECK:
+ if verbose:
+ print "Skipping buggy range check for code", code
+ else:
+ any_err(pack, ">" + code, x)
+ any_err(pack, "<" + code, x)
+
+ # Much the same for unsigned.
+ code = self.unsigned_code
+ if self.unsigned_min <= x <= self.unsigned_max:
+ # Try big-endian.
+ format = ">" + code
+ 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" * (self.bytesize - len(expected)) + expected
+
+ # Pack work?
+ got = pack(format, x)
+ verify(got == expected,
+ "'%s'-pack of %r gave %r, not %r" %
+ (format, x, got, expected))
+
+ # Unpack work?
+ retrieved = unpack(format, got)[0]
+ verify(x == retrieved,
+ "'%s'-unpack of %r gave %r, not %r" %
+ (format, got, retrieved, x))
+
+ # Adding any byte should cause a "too big" error.
+ any_err(unpack, format, '\x01' + got)
+
+ # Try little-endian.
+ format = "<" + code
+ expected = string_reverse(expected)
+
+ # Pack work?
+ got = pack(format, x)
+ verify(got == expected,
+ "'%s'-pack of %r gave %r, not %r" %
+ (format, x, got, expected))
+
+ # Unpack work?
+ retrieved = unpack(format, got)[0]
+ verify(x == retrieved,
+ "'%s'-unpack of %r gave %r, not %r" %
+ (format, got, retrieved, x))
+
+ # Adding any byte should cause a "too big" error.
+ any_err(unpack, format, '\x01' + got)
+
+ else:
+ # x is out of range -- verify pack realizes that.
+ if code in self.BUGGY_RANGE_CHECK:
+ if verbose:
+ print "Skipping buggy range check for code", code
+ else:
+ any_err(pack, ">" + code, x)
+ any_err(pack, "<" + code, x)
+
+ def run(self):
+ from random import randrange
+
+ # Create all interesting powers of 2.
+ values = []
+ for exp in range(self.bitsize + 3):
+ values.append(1L << exp)
+
+ # Add some random values.
+ for i in range(self.bitsize):
+ val = 0L
+ for j in range(self.bytesize):
+ 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
+ self.test_one(x)
+
+ # Some error cases.
+ for direction in "<>":
+ for code in self.formatpair:
+ for badobject in "a string", 3+42j, randrange:
+ any_err(struct.pack, direction + code, badobject)
+
+for args in [("bB", 1),
+ ("hH", 2),
+ ("iI", 4),
+ ("lL", 4),
+ ("qQ", 8)]:
+ t = IntTester(*args)
+ t.run()