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

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

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