+++ /dev/null
-import os\r
-import array\r
-import unittest\r
-import struct\r
-import inspect\r
-from test.test_support import run_unittest, check_warnings, check_py3k_warnings\r
-\r
-import sys\r
-ISBIGENDIAN = sys.byteorder == "big"\r
-IS32BIT = sys.maxsize == 0x7fffffff\r
-\r
-integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'\r
-\r
-testmod_filename = os.path.splitext(__file__)[0] + '.py'\r
-# Native 'q' packing isn't available on systems that don't have the C\r
-# long long type.\r
-try:\r
- struct.pack('q', 5)\r
-except struct.error:\r
- HAVE_LONG_LONG = False\r
-else:\r
- HAVE_LONG_LONG = True\r
-\r
-def string_reverse(s):\r
- return "".join(reversed(s))\r
-\r
-def bigendian_to_native(value):\r
- if ISBIGENDIAN:\r
- return value\r
- else:\r
- return string_reverse(value)\r
-\r
-class StructTest(unittest.TestCase):\r
-\r
- def check_float_coerce(self, format, number):\r
- # SF bug 1530559. struct.pack raises TypeError where it used\r
- # to convert.\r
- with check_warnings((".*integer argument expected, got float",\r
- DeprecationWarning)) as w:\r
- got = struct.pack(format, number)\r
- lineno = inspect.currentframe().f_lineno - 1\r
- self.assertEqual(w.filename, testmod_filename)\r
- self.assertEqual(w.lineno, lineno)\r
- self.assertEqual(len(w.warnings), 1)\r
- expected = struct.pack(format, int(number))\r
- self.assertEqual(got, expected)\r
-\r
- def test_isbigendian(self):\r
- self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)\r
-\r
- def test_consistence(self):\r
- self.assertRaises(struct.error, struct.calcsize, 'Z')\r
-\r
- sz = struct.calcsize('i')\r
- self.assertEqual(sz * 3, struct.calcsize('iii'))\r
-\r
- fmt = 'cbxxxxxxhhhhiillffd?'\r
- fmt3 = '3c3b18x12h6i6l6f3d3?'\r
- sz = struct.calcsize(fmt)\r
- sz3 = struct.calcsize(fmt3)\r
- self.assertEqual(sz * 3, sz3)\r
-\r
- self.assertRaises(struct.error, struct.pack, 'iii', 3)\r
- self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)\r
- self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')\r
- self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')\r
- self.assertRaises(struct.error, struct.unpack, 'd', 'flap')\r
- s = struct.pack('ii', 1, 2)\r
- self.assertRaises(struct.error, struct.unpack, 'iii', s)\r
- self.assertRaises(struct.error, struct.unpack, 'i', s)\r
-\r
- def test_transitiveness(self):\r
- c = 'a'\r
- b = 1\r
- h = 255\r
- i = 65535\r
- l = 65536\r
- f = 3.1415\r
- d = 3.1415\r
- t = True\r
-\r
- for prefix in ('', '@', '<', '>', '=', '!'):\r
- for format in ('xcbhilfd?', 'xcBHILfd?'):\r
- format = prefix + format\r
- s = struct.pack(format, c, b, h, i, l, f, d, t)\r
- cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)\r
- self.assertEqual(cp, c)\r
- self.assertEqual(bp, b)\r
- self.assertEqual(hp, h)\r
- self.assertEqual(ip, i)\r
- self.assertEqual(lp, l)\r
- self.assertEqual(int(100 * fp), int(100 * f))\r
- self.assertEqual(int(100 * dp), int(100 * d))\r
- self.assertEqual(tp, t)\r
-\r
- def test_new_features(self):\r
- # Test some of the new features in detail\r
- # (format, argument, big-endian result, little-endian result, asymmetric)\r
- tests = [\r
- ('c', 'a', 'a', 'a', 0),\r
- ('xc', 'a', '\0a', '\0a', 0),\r
- ('cx', 'a', 'a\0', 'a\0', 0),\r
- ('s', 'a', 'a', 'a', 0),\r
- ('0s', 'helloworld', '', '', 1),\r
- ('1s', 'helloworld', 'h', 'h', 1),\r
- ('9s', 'helloworld', 'helloworl', 'helloworl', 1),\r
- ('10s', 'helloworld', 'helloworld', 'helloworld', 0),\r
- ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),\r
- ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),\r
- ('b', 7, '\7', '\7', 0),\r
- ('b', -7, '\371', '\371', 0),\r
- ('B', 7, '\7', '\7', 0),\r
- ('B', 249, '\371', '\371', 0),\r
- ('h', 700, '\002\274', '\274\002', 0),\r
- ('h', -700, '\375D', 'D\375', 0),\r
- ('H', 700, '\002\274', '\274\002', 0),\r
- ('H', 0x10000-700, '\375D', 'D\375', 0),\r
- ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),\r
- ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),\r
- ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),\r
- ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),\r
- ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),\r
- ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),\r
- ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),\r
- ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),\r
- ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),\r
- ('d', 2.0, '@\000\000\000\000\000\000\000',\r
- '\000\000\000\000\000\000\000@', 0),\r
- ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),\r
- ('d', -2.0, '\300\000\000\000\000\000\000\000',\r
- '\000\000\000\000\000\000\000\300', 0),\r
- ('?', 0, '\0', '\0', 0),\r
- ('?', 3, '\1', '\1', 1),\r
- ('?', True, '\1', '\1', 0),\r
- ('?', [], '\0', '\0', 1),\r
- ('?', (1,), '\1', '\1', 1),\r
- ]\r
-\r
- for fmt, arg, big, lil, asy in tests:\r
- for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),\r
- ('='+fmt, ISBIGENDIAN and big or lil)]:\r
- res = struct.pack(xfmt, arg)\r
- self.assertEqual(res, exp)\r
- self.assertEqual(struct.calcsize(xfmt), len(res))\r
- rev = struct.unpack(xfmt, res)[0]\r
- if rev != arg:\r
- self.assertTrue(asy)\r
-\r
- def test_calcsize(self):\r
- expected_size = {\r
- 'b': 1, 'B': 1,\r
- 'h': 2, 'H': 2,\r
- 'i': 4, 'I': 4,\r
- 'l': 4, 'L': 4,\r
- 'q': 8, 'Q': 8,\r
- }\r
-\r
- # standard integer sizes\r
- for code in integer_codes:\r
- for byteorder in ('=', '<', '>', '!'):\r
- format = byteorder+code\r
- size = struct.calcsize(format)\r
- self.assertEqual(size, expected_size[code])\r
-\r
- # native integer sizes, except 'q' and 'Q'\r
- for format_pair in ('bB', 'hH', 'iI', 'lL'):\r
- for byteorder in ['', '@']:\r
- signed_size = struct.calcsize(byteorder + format_pair[0])\r
- unsigned_size = struct.calcsize(byteorder + format_pair[1])\r
- self.assertEqual(signed_size, unsigned_size)\r
-\r
- # bounds for native integer sizes\r
- self.assertEqual(struct.calcsize('b'), 1)\r
- self.assertLessEqual(2, struct.calcsize('h'))\r
- self.assertLessEqual(4, struct.calcsize('l'))\r
- self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))\r
- self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))\r
-\r
- # tests for native 'q' and 'Q' when applicable\r
- if HAVE_LONG_LONG:\r
- self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))\r
- self.assertLessEqual(8, struct.calcsize('q'))\r
- self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))\r
-\r
- def test_integers(self):\r
- # Integer tests (bBhHiIlLqQ).\r
- import binascii\r
-\r
- class IntTester(unittest.TestCase):\r
- def __init__(self, format):\r
- super(IntTester, self).__init__(methodName='test_one')\r
- self.format = format\r
- self.code = format[-1]\r
- self.direction = format[:-1]\r
- if not self.direction in ('', '@', '=', '<', '>', '!'):\r
- raise ValueError("unrecognized packing direction: %s" %\r
- self.direction)\r
- self.bytesize = struct.calcsize(format)\r
- self.bitsize = self.bytesize * 8\r
- if self.code in tuple('bhilq'):\r
- self.signed = True\r
- self.min_value = -(2L**(self.bitsize-1))\r
- self.max_value = 2L**(self.bitsize-1) - 1\r
- elif self.code in tuple('BHILQ'):\r
- self.signed = False\r
- self.min_value = 0\r
- self.max_value = 2L**self.bitsize - 1\r
- else:\r
- raise ValueError("unrecognized format code: %s" %\r
- self.code)\r
-\r
- def test_one(self, x, pack=struct.pack,\r
- unpack=struct.unpack,\r
- unhexlify=binascii.unhexlify):\r
-\r
- format = self.format\r
- if self.min_value <= x <= self.max_value:\r
- expected = long(x)\r
- if self.signed and x < 0:\r
- expected += 1L << self.bitsize\r
- self.assertGreaterEqual(expected, 0)\r
- expected = '%x' % expected\r
- if len(expected) & 1:\r
- expected = "0" + expected\r
- expected = unhexlify(expected)\r
- expected = ("\x00" * (self.bytesize - len(expected)) +\r
- expected)\r
- if (self.direction == '<' or\r
- self.direction in ('', '@', '=') and not ISBIGENDIAN):\r
- expected = string_reverse(expected)\r
- self.assertEqual(len(expected), self.bytesize)\r
-\r
- # Pack work?\r
- got = pack(format, x)\r
- self.assertEqual(got, expected)\r
-\r
- # Unpack work?\r
- retrieved = unpack(format, got)[0]\r
- self.assertEqual(x, retrieved)\r
-\r
- # Adding any byte should cause a "too big" error.\r
- self.assertRaises((struct.error, TypeError), unpack, format,\r
- '\x01' + got)\r
- else:\r
- # x is out of range -- verify pack realizes that.\r
- self.assertRaises((OverflowError, ValueError, struct.error),\r
- pack, format, x)\r
-\r
- def run(self):\r
- from random import randrange\r
-\r
- # Create all interesting powers of 2.\r
- values = []\r
- for exp in range(self.bitsize + 3):\r
- values.append(1L << exp)\r
-\r
- # Add some random values.\r
- for i in range(self.bitsize):\r
- val = 0L\r
- for j in range(self.bytesize):\r
- val = (val << 8) | randrange(256)\r
- values.append(val)\r
-\r
- # Values absorbed from other tests\r
- values.extend([300, 700000, sys.maxint*4])\r
-\r
- # Try all those, and their negations, and +-1 from\r
- # them. Note that this tests all power-of-2\r
- # boundaries in range, and a few out of range, plus\r
- # +-(2**n +- 1).\r
- for base in values:\r
- for val in -base, base:\r
- for incr in -1, 0, 1:\r
- x = val + incr\r
- self.test_one(int(x))\r
- self.test_one(long(x))\r
-\r
- # Some error cases.\r
- class NotAnIntNS(object):\r
- def __int__(self):\r
- return 42\r
-\r
- def __long__(self):\r
- return 1729L\r
-\r
- class NotAnIntOS:\r
- def __int__(self):\r
- return 85\r
-\r
- def __long__(self):\r
- return -163L\r
-\r
- # Objects with an '__index__' method should be allowed\r
- # to pack as integers. That is assuming the implemented\r
- # '__index__' method returns and 'int' or 'long'.\r
- class Indexable(object):\r
- def __init__(self, value):\r
- self._value = value\r
-\r
- def __index__(self):\r
- return self._value\r
-\r
- # If the '__index__' method raises a type error, then\r
- # '__int__' should be used with a deprecation warning.\r
- class BadIndex(object):\r
- def __index__(self):\r
- raise TypeError\r
-\r
- def __int__(self):\r
- return 42\r
-\r
- self.assertRaises((TypeError, struct.error),\r
- struct.pack, self.format,\r
- "a string")\r
- self.assertRaises((TypeError, struct.error),\r
- struct.pack, self.format,\r
- randrange)\r
- with check_warnings(("integer argument expected, "\r
- "got non-integer", DeprecationWarning)):\r
- with self.assertRaises((TypeError, struct.error)):\r
- struct.pack(self.format, 3+42j)\r
-\r
- # an attempt to convert a non-integer (with an\r
- # implicit conversion via __int__) should succeed,\r
- # with a DeprecationWarning\r
- for nonint in NotAnIntNS(), NotAnIntOS(), BadIndex():\r
- with check_warnings((".*integer argument expected, got non"\r
- "-integer", DeprecationWarning)) as w:\r
- got = struct.pack(self.format, nonint)\r
- lineno = inspect.currentframe().f_lineno - 1\r
- self.assertEqual(w.filename, testmod_filename)\r
- self.assertEqual(w.lineno, lineno)\r
- self.assertEqual(len(w.warnings), 1)\r
- expected = struct.pack(self.format, int(nonint))\r
- self.assertEqual(got, expected)\r
-\r
- # Check for legitimate values from '__index__'.\r
- for obj in (Indexable(0), Indexable(10), Indexable(17),\r
- Indexable(42), Indexable(100), Indexable(127)):\r
- try:\r
- struct.pack(format, obj)\r
- except:\r
- self.fail("integer code pack failed on object "\r
- "with '__index__' method")\r
-\r
- # Check for bogus values from '__index__'.\r
- for obj in (Indexable('a'), Indexable(u'b'), Indexable(None),\r
- Indexable({'a': 1}), Indexable([1, 2, 3])):\r
- self.assertRaises((TypeError, struct.error),\r
- struct.pack, self.format,\r
- obj)\r
-\r
- byteorders = '', '@', '=', '<', '>', '!'\r
- for code in integer_codes:\r
- for byteorder in byteorders:\r
- if (byteorder in ('', '@') and code in ('q', 'Q') and\r
- not HAVE_LONG_LONG):\r
- continue\r
- format = byteorder+code\r
- t = IntTester(format)\r
- t.run()\r
-\r
- def test_p_code(self):\r
- # Test p ("Pascal string") code.\r
- for code, input, expected, expectedback in [\r
- ('p','abc', '\x00', ''),\r
- ('1p', 'abc', '\x00', ''),\r
- ('2p', 'abc', '\x01a', 'a'),\r
- ('3p', 'abc', '\x02ab', 'ab'),\r
- ('4p', 'abc', '\x03abc', 'abc'),\r
- ('5p', 'abc', '\x03abc\x00', 'abc'),\r
- ('6p', 'abc', '\x03abc\x00\x00', 'abc'),\r
- ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:\r
- got = struct.pack(code, input)\r
- self.assertEqual(got, expected)\r
- (got,) = struct.unpack(code, got)\r
- self.assertEqual(got, expectedback)\r
-\r
- def test_705836(self):\r
- # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry\r
- # from the low-order discarded bits could propagate into the exponent\r
- # field, causing the result to be wrong by a factor of 2.\r
- import math\r
-\r
- for base in range(1, 33):\r
- # smaller <- largest representable float less than base.\r
- delta = 0.5\r
- while base - delta / 2.0 != base:\r
- delta /= 2.0\r
- smaller = base - delta\r
- # Packing this rounds away a solid string of trailing 1 bits.\r
- packed = struct.pack("<f", smaller)\r
- unpacked = struct.unpack("<f", packed)[0]\r
- # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and\r
- # 16, respectively.\r
- self.assertEqual(base, unpacked)\r
- bigpacked = struct.pack(">f", smaller)\r
- self.assertEqual(bigpacked, string_reverse(packed))\r
- unpacked = struct.unpack(">f", bigpacked)[0]\r
- self.assertEqual(base, unpacked)\r
-\r
- # Largest finite IEEE single.\r
- big = (1 << 24) - 1\r
- big = math.ldexp(big, 127 - 23)\r
- packed = struct.pack(">f", big)\r
- unpacked = struct.unpack(">f", packed)[0]\r
- self.assertEqual(big, unpacked)\r
-\r
- # The same, but tack on a 1 bit so it rounds up to infinity.\r
- big = (1 << 25) - 1\r
- big = math.ldexp(big, 127 - 24)\r
- self.assertRaises(OverflowError, struct.pack, ">f", big)\r
-\r
- def test_1530559(self):\r
- # SF bug 1530559. struct.pack raises TypeError where it used to convert.\r
- for endian in ('', '>', '<'):\r
- for fmt in integer_codes:\r
- self.check_float_coerce(endian + fmt, 1.0)\r
- self.check_float_coerce(endian + fmt, 1.5)\r
-\r
- def test_unpack_from(self, cls=str):\r
- data = cls('abcd01234')\r
- fmt = '4s'\r
- s = struct.Struct(fmt)\r
-\r
- self.assertEqual(s.unpack_from(data), ('abcd',))\r
- self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))\r
- for i in xrange(6):\r
- self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))\r
- self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))\r
- for i in xrange(6, len(data) + 1):\r
- self.assertRaises(struct.error, s.unpack_from, data, i)\r
- self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)\r
-\r
- def test_pack_into(self):\r
- test_string = 'Reykjavik rocks, eow!'\r
- writable_buf = array.array('c', ' '*100)\r
- fmt = '21s'\r
- s = struct.Struct(fmt)\r
-\r
- # Test without offset\r
- s.pack_into(writable_buf, 0, test_string)\r
- from_buf = writable_buf.tostring()[:len(test_string)]\r
- self.assertEqual(from_buf, test_string)\r
-\r
- # Test with offset.\r
- s.pack_into(writable_buf, 10, test_string)\r
- from_buf = writable_buf.tostring()[:len(test_string)+10]\r
- self.assertEqual(from_buf, test_string[:10] + test_string)\r
-\r
- # Go beyond boundaries.\r
- small_buf = array.array('c', ' '*10)\r
- self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,\r
- test_string)\r
- self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,\r
- test_string)\r
-\r
- # Test bogus offset (issue 3694)\r
- sb = small_buf\r
- self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,\r
- None)\r
-\r
- def test_pack_into_fn(self):\r
- test_string = 'Reykjavik rocks, eow!'\r
- writable_buf = array.array('c', ' '*100)\r
- fmt = '21s'\r
- pack_into = lambda *args: struct.pack_into(fmt, *args)\r
-\r
- # Test without offset.\r
- pack_into(writable_buf, 0, test_string)\r
- from_buf = writable_buf.tostring()[:len(test_string)]\r
- self.assertEqual(from_buf, test_string)\r
-\r
- # Test with offset.\r
- pack_into(writable_buf, 10, test_string)\r
- from_buf = writable_buf.tostring()[:len(test_string)+10]\r
- self.assertEqual(from_buf, test_string[:10] + test_string)\r
-\r
- # Go beyond boundaries.\r
- small_buf = array.array('c', ' '*10)\r
- self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,\r
- test_string)\r
- self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,\r
- test_string)\r
-\r
- def test_unpack_with_buffer(self):\r
- with check_py3k_warnings(("buffer.. not supported in 3.x",\r
- DeprecationWarning)):\r
- # SF bug 1563759: struct.unpack doesn't support buffer protocol objects\r
- data1 = array.array('B', '\x12\x34\x56\x78')\r
- data2 = buffer('......\x12\x34\x56\x78......', 6, 4)\r
- for data in [data1, data2]:\r
- value, = struct.unpack('>I', data)\r
- self.assertEqual(value, 0x12345678)\r
-\r
- self.test_unpack_from(cls=buffer)\r
-\r
- def test_bool(self):\r
- class ExplodingBool(object):\r
- def __nonzero__(self):\r
- raise IOError\r
- for prefix in tuple("<>!=")+('',):\r
- false = (), [], [], '', 0\r
- true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2\r
-\r
- falseFormat = prefix + '?' * len(false)\r
- packedFalse = struct.pack(falseFormat, *false)\r
- unpackedFalse = struct.unpack(falseFormat, packedFalse)\r
-\r
- trueFormat = prefix + '?' * len(true)\r
- packedTrue = struct.pack(trueFormat, *true)\r
- unpackedTrue = struct.unpack(trueFormat, packedTrue)\r
-\r
- self.assertEqual(len(true), len(unpackedTrue))\r
- self.assertEqual(len(false), len(unpackedFalse))\r
-\r
- for t in unpackedFalse:\r
- self.assertFalse(t)\r
- for t in unpackedTrue:\r
- self.assertTrue(t)\r
-\r
- packed = struct.pack(prefix+'?', 1)\r
-\r
- self.assertEqual(len(packed), struct.calcsize(prefix+'?'))\r
-\r
- if len(packed) != 1:\r
- self.assertFalse(prefix, msg='encoded bool is not one byte: %r'\r
- %packed)\r
-\r
- self.assertRaises(IOError, struct.pack, prefix + '?',\r
- ExplodingBool())\r
-\r
- for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:\r
- self.assertTrue(struct.unpack('>?', c)[0])\r
-\r
- @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")\r
- def test_crasher(self):\r
- self.assertRaises(MemoryError, struct.pack, "357913941c", "a")\r
-\r
- def test_count_overflow(self):\r
- hugecount = '{}b'.format(sys.maxsize+1)\r
- self.assertRaises(struct.error, struct.calcsize, hugecount)\r
-\r
- hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)\r
- self.assertRaises(struct.error, struct.calcsize, hugecount2)\r
-\r
-def test_main():\r
- run_unittest(StructTest)\r
-\r
-if __name__ == '__main__':\r
- test_main()\r