PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/struct/test/test_struct.py

https://bitbucket.org/pypy/pypy/
Python | 490 lines | 479 code | 4 blank | 7 comment | 0 complexity | a90d566df9d7e4659bae5e4894fbd091 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. Tests for the struct module implemented at interp-level in pypy/module/struct.
  3. """
  4. from rpython.rlib.rstruct.nativefmttable import native_is_bigendian
  5. class AppTestStruct(object):
  6. spaceconfig = dict(usemodules=['struct', 'array'])
  7. def setup_class(cls):
  8. """
  9. Create a space with the struct module and import it for use by the
  10. tests.
  11. """
  12. cls.w_struct = cls.space.appexec([], """():
  13. import struct
  14. return struct
  15. """)
  16. cls.w_native_is_bigendian = cls.space.wrap(native_is_bigendian)
  17. def test_error(self):
  18. """
  19. struct.error should be an exception class.
  20. """
  21. assert issubclass(self.struct.error, Exception)
  22. assert self.struct.error.__mro__ == (self.struct.error, Exception,
  23. BaseException, object)
  24. assert self.struct.error.__name__ == "error"
  25. assert self.struct.error.__module__ == "struct"
  26. def test_calcsize_standard(self):
  27. """
  28. Check the standard size of the various format characters.
  29. """
  30. calcsize = self.struct.calcsize
  31. assert calcsize('=') == 0
  32. assert calcsize('<x') == 1
  33. assert calcsize('>c') == 1
  34. assert calcsize('!b') == 1
  35. assert calcsize('=B') == 1
  36. assert calcsize('<h') == 2
  37. assert calcsize('>H') == 2
  38. assert calcsize('!i') == 4
  39. assert calcsize('=I') == 4
  40. assert calcsize('<l') == 4
  41. assert calcsize('>L') == 4
  42. assert calcsize('!q') == 8
  43. assert calcsize('=Q') == 8
  44. assert calcsize('<f') == 4
  45. assert calcsize('>d') == 8
  46. assert calcsize('!13s') == 13
  47. assert calcsize('=500p') == 500
  48. # test with some repetitions and multiple format characters
  49. assert calcsize('=bQ3i') == 1 + 8 + 3*4
  50. def test_index(self):
  51. class X(object):
  52. def __index__(self):
  53. return 3
  54. assert self.struct.unpack("i", self.struct.pack("i", X()))[0] == 3
  55. def test_deprecation_warning(self):
  56. import warnings
  57. for code in 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q':
  58. for val in [3., 3j]:
  59. with warnings.catch_warnings(record=True) as w:
  60. warnings.simplefilter("always")
  61. if type(val) is float:
  62. self.struct.pack(code, val)
  63. else:
  64. raises(TypeError, self.struct.pack, code, val)
  65. assert len(w) == 1
  66. if type(val) is float:
  67. assert str(w[0].message) == (
  68. "integer argument expected, got float")
  69. else:
  70. assert str(w[0].message) == (
  71. "integer argument expected, got non-integer"
  72. " (implicit conversion using __int__ is deprecated)")
  73. assert w[0].category is DeprecationWarning
  74. def test_pack_standard_little(self):
  75. """
  76. Check packing with the '<' format specifier.
  77. """
  78. pack = self.struct.pack
  79. assert pack("<i", 0x41424344) == 'DCBA'
  80. assert pack("<i", -3) == '\xfd\xff\xff\xff'
  81. assert pack("<i", -2147483648) == '\x00\x00\x00\x80'
  82. assert pack("<I", 0x81424344) == 'DCB\x81'
  83. assert pack("<q", 0x4142434445464748) == 'HGFEDCBA'
  84. assert pack("<q", -0x41B2B3B4B5B6B7B8) == 'HHIJKLM\xbe'
  85. assert pack("<Q", 0x8142434445464748) == 'HGFEDCB\x81'
  86. def test_unpack_standard_little(self):
  87. """
  88. Check unpacking with the '<' format specifier.
  89. """
  90. unpack = self.struct.unpack
  91. assert unpack("<i", 'DCBA') == (0x41424344,)
  92. assert unpack("<i", '\xfd\xff\xff\xff') == (-3,)
  93. assert unpack("<i", '\x00\x00\x00\x80') == (-2147483648,)
  94. assert unpack("<I", 'DCB\x81') == (0x81424344,)
  95. assert unpack("<q", 'HGFEDCBA') == (0x4142434445464748,)
  96. assert unpack("<q", 'HHIJKLM\xbe') == (-0x41B2B3B4B5B6B7B8,)
  97. assert unpack("<Q", 'HGFEDCB\x81') == (0x8142434445464748,)
  98. def test_pack_standard_big(self):
  99. """
  100. Check packing with the '>' format specifier.
  101. """
  102. pack = self.struct.pack
  103. assert pack(">i", 0x41424344) == 'ABCD'
  104. assert pack(">i", -3) == '\xff\xff\xff\xfd'
  105. assert pack(">i", -2147483648) == '\x80\x00\x00\x00'
  106. assert pack(">I", 0x81424344) == '\x81BCD'
  107. assert pack(">q", 0x4142434445464748) == 'ABCDEFGH'
  108. assert pack(">q", -0x41B2B3B4B5B6B7B8) == '\xbeMLKJIHH'
  109. assert pack(">Q", 0x8142434445464748) == '\x81BCDEFGH'
  110. def test_unpack_standard_big(self):
  111. """
  112. Check unpacking with the '>' format specifier.
  113. """
  114. unpack = self.struct.unpack
  115. assert unpack(">i", 'ABCD') == (0x41424344,)
  116. assert unpack(">i", '\xff\xff\xff\xfd') == (-3,)
  117. assert unpack(">i", '\x80\x00\x00\x00') == (-2147483648,)
  118. assert unpack(">I", '\x81BCD') == (0x81424344,)
  119. assert unpack(">q", 'ABCDEFGH') == (0x4142434445464748,)
  120. assert unpack(">q", '\xbeMLKJIHH') == (-0x41B2B3B4B5B6B7B8,)
  121. assert unpack(">Q", '\x81BCDEFGH') == (0x8142434445464748,)
  122. def test_calcsize_native(self):
  123. """
  124. Check that the size of the various format characters is reasonable.
  125. """
  126. calcsize = self.struct.calcsize
  127. assert calcsize('') == 0
  128. assert calcsize('x') == 1
  129. assert calcsize('c') == 1
  130. assert calcsize('b') == 1
  131. assert calcsize('B') == 1
  132. assert (2 <= calcsize('h') == calcsize('H')
  133. < calcsize('i') == calcsize('I')
  134. <= calcsize('l') == calcsize('L')
  135. <= calcsize('q') == calcsize('Q'))
  136. assert 4 <= calcsize('f') <= 8 <= calcsize('d')
  137. assert calcsize('13s') == 13
  138. assert calcsize('500p') == 500
  139. assert 4 <= calcsize('P') <= 8
  140. # test with some repetitions and multiple format characters
  141. assert 4 + 8 + 3*4 <= calcsize('bQ3i') <= 8 + 8 + 3*8
  142. # test alignment
  143. assert calcsize('bi') == calcsize('ii') == 2 * calcsize('i')
  144. assert calcsize('bbi') == calcsize('ii') == 2 * calcsize('i')
  145. assert calcsize('hi') == calcsize('ii') == 2 * calcsize('i')
  146. # CPython adds no padding at the end, unlike a C compiler
  147. assert calcsize('ib') == calcsize('i') + calcsize('b')
  148. assert calcsize('ibb') == calcsize('i') + 2 * calcsize('b')
  149. assert calcsize('ih') == calcsize('i') + calcsize('h')
  150. def test_pack_native(self):
  151. """
  152. Check packing with the native format.
  153. """
  154. calcsize = self.struct.calcsize
  155. pack = self.struct.pack
  156. sizeofi = calcsize("i")
  157. res = pack("bi", -2, 5)
  158. assert len(res) == 2 * sizeofi
  159. assert res[0] == '\xfe'
  160. assert res[1:sizeofi] == '\x00' * (sizeofi-1) # padding
  161. if self.native_is_bigendian:
  162. assert res[sizeofi:] == '\x00' * (sizeofi-1) + '\x05'
  163. else:
  164. assert res[sizeofi:] == '\x05' + '\x00' * (sizeofi-1)
  165. assert pack("q", -1) == '\xff' * calcsize("q")
  166. def test_unpack_native(self):
  167. """
  168. Check unpacking with the native format.
  169. """
  170. calcsize = self.struct.calcsize
  171. pack = self.struct.pack
  172. unpack = self.struct.unpack
  173. assert unpack("bi", pack("bi", -2, 5)) == (-2, 5)
  174. assert unpack("q", '\xff' * calcsize("q")) == (-1,)
  175. def test_string_format(self):
  176. """
  177. Check the 's' format character.
  178. """
  179. pack = self.struct.pack
  180. unpack = self.struct.unpack
  181. assert pack("7s", "hello") == "hello\x00\x00"
  182. assert pack("5s", "world") == "world"
  183. assert pack("3s", "spam") == "spa"
  184. assert pack("0s", "foo") == ""
  185. assert unpack("7s", "hello\x00\x00") == ("hello\x00\x00",)
  186. assert unpack("5s3s", "worldspa") == ("world", "spa")
  187. assert unpack("0s", "") == ("",)
  188. def test_pascal_format(self):
  189. """
  190. Check the 'p' format character.
  191. """
  192. pack = self.struct.pack
  193. unpack = self.struct.unpack
  194. longstring = str(range(70)) # this has 270 chars
  195. longpacked300 = "\xff" + longstring + "\x00" * (299-len(longstring))
  196. assert pack("8p", "hello") == "\x05hello\x00\x00"
  197. assert pack("6p", "world") == "\x05world"
  198. assert pack("4p", "spam") == "\x03spa"
  199. assert pack("1p", "foo") == "\x00"
  200. assert pack("10p", longstring) == "\x09" + longstring[:9]
  201. assert pack("300p", longstring) == longpacked300
  202. assert unpack("8p", "\x05helloxx") == ("hello",)
  203. assert unpack("5p", "\x80abcd") == ("abcd",)
  204. assert unpack("1p", "\x03") == ("",)
  205. assert unpack("300p", longpacked300) == (longstring[:255],)
  206. def test_char_format(self):
  207. """
  208. Check the 'c' format character.
  209. """
  210. pack = self.struct.pack
  211. unpack = self.struct.unpack
  212. assert pack("c", "?") == "?"
  213. assert pack("5c", "a", "\xc0", "\x00", "\n", "-") == "a\xc0\x00\n-"
  214. assert unpack("c", "?") == ("?",)
  215. assert unpack("5c", "a\xc0\x00\n-") == ("a", "\xc0", "\x00", "\n", "-")
  216. def test_pad_format(self):
  217. """
  218. Check the 'x' format character.
  219. """
  220. pack = self.struct.pack
  221. unpack = self.struct.unpack
  222. assert pack("x") == "\x00"
  223. assert pack("5x") == "\x00" * 5
  224. assert unpack("x", "?") == ()
  225. assert unpack("5x", "hello") == ()
  226. def test_native_floats(self):
  227. """
  228. Check the 'd' and 'f' format characters on native packing.
  229. """
  230. calcsize = self.struct.calcsize
  231. pack = self.struct.pack
  232. unpack = self.struct.unpack
  233. data = pack("d", 12.34)
  234. assert len(data) == calcsize("d")
  235. assert unpack("d", data) == (12.34,) # no precision lost
  236. data = pack("f", 12.34)
  237. assert len(data) == calcsize("f")
  238. res, = unpack("f", data)
  239. assert res != 12.34 # precision lost
  240. assert abs(res - 12.34) < 1E-6
  241. def test_standard_floats(self):
  242. """
  243. Check the 'd' and 'f' format characters on standard packing.
  244. """
  245. pack = self.struct.pack
  246. unpack = self.struct.unpack
  247. assert pack("!d", 12.5) == '@)\x00\x00\x00\x00\x00\x00'
  248. assert pack("<d", -12.5) == '\x00\x00\x00\x00\x00\x00)\xc0'
  249. assert unpack("!d", '\xc0)\x00\x00\x00\x00\x00\x00') == (-12.5,)
  250. assert unpack("<d", '\x00\x00\x00\x00\x00\x00)@') == (12.5,)
  251. assert pack("!f", -12.5) == '\xc1H\x00\x00'
  252. assert pack("<f", 12.5) == '\x00\x00HA'
  253. assert unpack("!f", 'AH\x00\x00') == (12.5,)
  254. assert unpack("<f", '\x00\x00H\xc1') == (-12.5,)
  255. raises(OverflowError, pack, "<f", 10e100)
  256. def test_bool(self):
  257. pack = self.struct.pack
  258. assert pack("!?", True) == '\x01'
  259. assert pack(">?", True) == '\x01'
  260. assert pack("!?", False) == '\x00'
  261. assert pack(">?", False) == '\x00'
  262. assert pack("@?", True) == '\x01'
  263. assert pack("@?", False) == '\x00'
  264. def test_transitiveness(self):
  265. c = 'a'
  266. b = 1
  267. h = 255
  268. i = 65535
  269. l = 65536
  270. f = 3.1415
  271. d = 3.1415
  272. t = True
  273. for prefix in ('', '@', '<', '>', '=', '!'):
  274. for format in ('xcbhilfd?', 'xcBHILfd?'):
  275. format = prefix + format
  276. s = self.struct.pack(format, c, b, h, i, l, f, d, t)
  277. cp, bp, hp, ip, lp, fp, dp, tp = self.struct.unpack(format, s)
  278. assert cp == c
  279. assert bp == b
  280. assert hp == h
  281. assert ip == i
  282. assert lp == l
  283. assert int(100 * fp) == int(100 * f)
  284. assert int(100 * dp) == int(100 * d)
  285. assert tp == t
  286. def test_struct_error(self):
  287. """
  288. Check the various ways to get a struct.error. Note that CPython
  289. and PyPy might disagree on the specific exception raised in a
  290. specific situation, e.g. struct.error/TypeError/OverflowError.
  291. """
  292. import sys
  293. calcsize = self.struct.calcsize
  294. pack = self.struct.pack
  295. unpack = self.struct.unpack
  296. error = self.struct.error
  297. try:
  298. calcsize("12") # incomplete struct format
  299. except error: # (but ignored on CPython)
  300. pass
  301. raises(error, calcsize, "[") # bad char in struct format
  302. raises(error, calcsize, "!P") # bad char in struct format
  303. raises(error, pack, "ii", 15) # struct format requires more arguments
  304. raises(error, pack, "i", 3, 4) # too many arguments for struct format
  305. raises(error, unpack, "ii", "?")# unpack str size too short for format
  306. raises(error, unpack, "b", "??")# unpack str size too long for format
  307. raises(error, pack, "c", "foo") # expected a string of length 1
  308. try:
  309. pack("0p") # bad '0p' in struct format
  310. except error: # (but ignored on CPython)
  311. pass
  312. if '__pypy__' in sys.builtin_module_names:
  313. raises(error, unpack, "0p", "") # segfaults on CPython 2.5.2!
  314. raises(error, pack, "b", 150) # argument out of range
  315. # XXX the accepted ranges still differs between PyPy and CPython
  316. exc = raises(error, pack, ">d", 'abc')
  317. assert str(exc.value) == "required argument is not a float"
  318. exc = raises(error, pack, ">l", 'abc')
  319. assert str(exc.value) == "cannot convert argument to integer"
  320. exc = raises(error, pack, ">H", 'abc')
  321. assert str(exc.value) == "cannot convert argument to integer"
  322. def test_overflow_error(self):
  323. """
  324. Check OverflowError cases.
  325. """
  326. import sys
  327. calcsize = self.struct.calcsize
  328. someerror = (OverflowError, self.struct.error)
  329. raises(someerror, calcsize, "%dc" % (sys.maxint+1,))
  330. raises(someerror, calcsize, "999999999999999999999999999c")
  331. raises(someerror, calcsize, "%di" % (sys.maxint,))
  332. raises(someerror, calcsize, "%dcc" % (sys.maxint,))
  333. raises(someerror, calcsize, "c%dc" % (sys.maxint,))
  334. raises(someerror, calcsize, "%dci" % (sys.maxint,))
  335. def test_unicode(self):
  336. """
  337. A PyPy extension: accepts the 'u' format character in native mode,
  338. just like the array module does. (This is actually used in the
  339. implementation of our interp-level array module.)
  340. """
  341. import sys
  342. if '__pypy__' not in sys.builtin_module_names:
  343. skip("PyPy extension")
  344. data = self.struct.pack("uuu", u'X', u'Y', u'Z')
  345. assert data == str(buffer(u'XYZ'))
  346. assert self.struct.unpack("uuu", data) == (u'X', u'Y', u'Z')
  347. def test_unpack_buffer(self):
  348. """
  349. Buffer objects can be passed to struct.unpack().
  350. """
  351. b = buffer(self.struct.pack("ii", 62, 12))
  352. assert self.struct.unpack("ii", b) == (62, 12)
  353. raises(self.struct.error, self.struct.unpack, "i", b)
  354. def test_pack_unpack_buffer(self):
  355. import array
  356. b = array.array('c', '\x00' * 19)
  357. sz = self.struct.calcsize("ii")
  358. for offset in [2, -17]:
  359. self.struct.pack_into("ii", b, offset, 17, 42)
  360. assert str(buffer(b)) == ('\x00' * 2 +
  361. self.struct.pack("ii", 17, 42) +
  362. '\x00' * (19-sz-2))
  363. exc = raises(TypeError, self.struct.pack_into, "ii", buffer(b), 0, 17, 42)
  364. assert str(exc.value) == "must be read-write buffer, not buffer"
  365. exc = raises(TypeError, self.struct.pack_into, "ii", 'test', 0, 17, 42)
  366. assert str(exc.value) == "must be read-write buffer, not str"
  367. exc = raises(self.struct.error, self.struct.pack_into, "ii", b[0:1], 0, 17, 42)
  368. assert str(exc.value) == "pack_into requires a buffer of at least 8 bytes"
  369. assert self.struct.unpack_from("ii", b, 2) == (17, 42)
  370. assert self.struct.unpack_from("ii", b, -17) == (17, 42)
  371. assert self.struct.unpack_from("ii", buffer(b, 2)) == (17, 42)
  372. assert self.struct.unpack_from("ii", buffer(b), 2) == (17, 42)
  373. assert self.struct.unpack_from("ii", memoryview(buffer(b)), 2) == (17, 42)
  374. exc = raises(TypeError, self.struct.unpack_from, "ii", 123)
  375. assert 'must be string or buffer, not int' in str(exc.value)
  376. exc = raises(self.struct.error, self.struct.unpack_from, "ii", None)
  377. assert str(exc.value) == "unpack_from requires a buffer argument"
  378. exc = raises(self.struct.error, self.struct.unpack_from, "ii", '')
  379. assert str(exc.value) == "unpack_from requires a buffer of at least 8 bytes"
  380. exc = raises(self.struct.error, self.struct.unpack_from, "ii", memoryview(''))
  381. assert str(exc.value) == "unpack_from requires a buffer of at least 8 bytes"
  382. def test___float__(self):
  383. class MyFloat(object):
  384. def __init__(self, x):
  385. self.x = x
  386. def __float__(self):
  387. return self.x
  388. obj = MyFloat(42.3)
  389. data = self.struct.pack('d', obj)
  390. obj2, = self.struct.unpack('d', data)
  391. assert type(obj2) is float
  392. assert obj2 == 42.3
  393. def test_struct_object(self):
  394. s = self.struct.Struct('i')
  395. assert s.unpack(s.pack(42)) == (42,)
  396. assert s.unpack_from(memoryview(s.pack(42))) == (42,)
  397. def test_overflow(self):
  398. raises(self.struct.error, self.struct.pack, 'i', 1<<65)
  399. class AppTestStructBuffer(object):
  400. spaceconfig = dict(usemodules=['struct', '__pypy__'])
  401. def setup_class(cls):
  402. cls.w_struct = cls.space.appexec([], """():
  403. import struct
  404. return struct
  405. """)
  406. cls.w_bytebuffer = cls.space.appexec([], """():
  407. import __pypy__
  408. return __pypy__.bytebuffer
  409. """)
  410. def test_pack_into(self):
  411. b = self.bytebuffer(19)
  412. sz = self.struct.calcsize("ii")
  413. self.struct.pack_into("ii", b, 2, 17, 42)
  414. assert b[:] == ('\x00' * 2 +
  415. self.struct.pack("ii", 17, 42) +
  416. '\x00' * (19-sz-2))
  417. m = memoryview(b)
  418. self.struct.pack_into("ii", m, 2, 17, 42)
  419. def test_unpack_from(self):
  420. b = self.bytebuffer(19)
  421. sz = self.struct.calcsize("ii")
  422. b[2:2+sz] = self.struct.pack("ii", 17, 42)
  423. assert self.struct.unpack_from("ii", b, 2) == (17, 42)
  424. b[:sz] = self.struct.pack("ii", 18, 43)
  425. assert self.struct.unpack_from("ii", b) == (18, 43)
  426. class AppTestFastPath(object):
  427. spaceconfig = dict(usemodules=['struct', '__pypy__'])
  428. def setup_class(cls):
  429. from rpython.rlib.rstruct import standardfmttable
  430. standardfmttable.ALLOW_SLOWPATH = False
  431. #
  432. cls.w_struct = cls.space.appexec([], """():
  433. import struct
  434. return struct
  435. """)
  436. cls.w_bytebuffer = cls.space.appexec([], """():
  437. import __pypy__
  438. return __pypy__.bytebuffer
  439. """)
  440. def teardown_class(cls):
  441. from rpython.rlib.rstruct import standardfmttable
  442. standardfmttable.ALLOW_SLOWPATH = True
  443. def test_unpack_from(self):
  444. buf = self.struct.pack("iii", 0, 42, 43)
  445. offset = self.struct.calcsize("i")
  446. assert self.struct.unpack_from("ii", buf, offset) == (42, 43)