PageRenderTime 57ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/ctypes/test/test_numbers.py

https://bitbucket.org/glix/python
Python | 276 lines | 249 code | 15 blank | 12 comment | 12 complexity | 2db0edeade019c45725c193e39609b85 MD5 | raw file
  1. from ctypes import *
  2. import unittest
  3. import struct
  4. def valid_ranges(*types):
  5. # given a sequence of numeric types, collect their _type_
  6. # attribute, which is a single format character compatible with
  7. # the struct module, use the struct module to calculate the
  8. # minimum and maximum value allowed for this format.
  9. # Returns a list of (min, max) values.
  10. result = []
  11. for t in types:
  12. fmt = t._type_
  13. size = struct.calcsize(fmt)
  14. a = struct.unpack(fmt, ("\x00"*32)[:size])[0]
  15. b = struct.unpack(fmt, ("\xFF"*32)[:size])[0]
  16. c = struct.unpack(fmt, ("\x7F"+"\x00"*32)[:size])[0]
  17. d = struct.unpack(fmt, ("\x80"+"\xFF"*32)[:size])[0]
  18. result.append((min(a, b, c, d), max(a, b, c, d)))
  19. return result
  20. ArgType = type(byref(c_int(0)))
  21. unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
  22. signed_types = [c_byte, c_short, c_int, c_long, c_longlong]
  23. bool_types = []
  24. float_types = [c_double, c_float]
  25. try:
  26. c_ulonglong
  27. c_longlong
  28. except NameError:
  29. pass
  30. else:
  31. unsigned_types.append(c_ulonglong)
  32. signed_types.append(c_longlong)
  33. try:
  34. c_bool
  35. except NameError:
  36. pass
  37. else:
  38. bool_types.append(c_bool)
  39. unsigned_ranges = valid_ranges(*unsigned_types)
  40. signed_ranges = valid_ranges(*signed_types)
  41. bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]
  42. ################################################################
  43. class NumberTestCase(unittest.TestCase):
  44. def test_default_init(self):
  45. # default values are set to zero
  46. for t in signed_types + unsigned_types + float_types:
  47. self.failUnlessEqual(t().value, 0)
  48. def test_unsigned_values(self):
  49. # the value given to the constructor is available
  50. # as the 'value' attribute
  51. for t, (l, h) in zip(unsigned_types, unsigned_ranges):
  52. self.failUnlessEqual(t(l).value, l)
  53. self.failUnlessEqual(t(h).value, h)
  54. def test_signed_values(self):
  55. # see above
  56. for t, (l, h) in zip(signed_types, signed_ranges):
  57. self.failUnlessEqual(t(l).value, l)
  58. self.failUnlessEqual(t(h).value, h)
  59. def test_bool_values(self):
  60. from operator import truth
  61. for t, v in zip(bool_types, bool_values):
  62. self.failUnlessEqual(t(v).value, truth(v))
  63. def test_typeerror(self):
  64. # Only numbers are allowed in the contructor,
  65. # otherwise TypeError is raised
  66. for t in signed_types + unsigned_types + float_types:
  67. self.assertRaises(TypeError, t, "")
  68. self.assertRaises(TypeError, t, None)
  69. ## def test_valid_ranges(self):
  70. ## # invalid values of the correct type
  71. ## # raise ValueError (not OverflowError)
  72. ## for t, (l, h) in zip(unsigned_types, unsigned_ranges):
  73. ## self.assertRaises(ValueError, t, l-1)
  74. ## self.assertRaises(ValueError, t, h+1)
  75. def test_from_param(self):
  76. # the from_param class method attribute always
  77. # returns PyCArgObject instances
  78. for t in signed_types + unsigned_types + float_types:
  79. self.failUnlessEqual(ArgType, type(t.from_param(0)))
  80. def test_byref(self):
  81. # calling byref returns also a PyCArgObject instance
  82. for t in signed_types + unsigned_types + float_types + bool_types:
  83. parm = byref(t())
  84. self.failUnlessEqual(ArgType, type(parm))
  85. def test_floats(self):
  86. # c_float and c_double can be created from
  87. # Python int, long and float
  88. class FloatLike(object):
  89. def __float__(self):
  90. return 2.0
  91. f = FloatLike()
  92. for t in float_types:
  93. self.failUnlessEqual(t(2.0).value, 2.0)
  94. self.failUnlessEqual(t(2).value, 2.0)
  95. self.failUnlessEqual(t(2L).value, 2.0)
  96. self.failUnlessEqual(t(f).value, 2.0)
  97. def test_integers(self):
  98. class FloatLike(object):
  99. def __float__(self):
  100. return 2.0
  101. f = FloatLike()
  102. class IntLike(object):
  103. def __int__(self):
  104. return 2
  105. i = IntLike()
  106. # integers cannot be constructed from floats,
  107. # but from integer-like objects
  108. for t in signed_types + unsigned_types:
  109. self.assertRaises(TypeError, t, 3.14)
  110. self.assertRaises(TypeError, t, f)
  111. self.failUnlessEqual(t(i).value, 2)
  112. def test_sizes(self):
  113. for t in signed_types + unsigned_types + float_types + bool_types:
  114. try:
  115. size = struct.calcsize(t._type_)
  116. except struct.error:
  117. continue
  118. # sizeof of the type...
  119. self.failUnlessEqual(sizeof(t), size)
  120. # and sizeof of an instance
  121. self.failUnlessEqual(sizeof(t()), size)
  122. def test_alignments(self):
  123. for t in signed_types + unsigned_types + float_types:
  124. code = t._type_ # the typecode
  125. align = struct.calcsize("c%c" % code) - struct.calcsize(code)
  126. # alignment of the type...
  127. self.failUnlessEqual((code, alignment(t)),
  128. (code, align))
  129. # and alignment of an instance
  130. self.failUnlessEqual((code, alignment(t())),
  131. (code, align))
  132. def test_int_from_address(self):
  133. from array import array
  134. for t in signed_types + unsigned_types:
  135. # the array module doesn't suppport all format codes
  136. # (no 'q' or 'Q')
  137. try:
  138. array(t._type_)
  139. except ValueError:
  140. continue
  141. a = array(t._type_, [100])
  142. # v now is an integer at an 'external' memory location
  143. v = t.from_address(a.buffer_info()[0])
  144. self.failUnlessEqual(v.value, a[0])
  145. self.failUnlessEqual(type(v), t)
  146. # changing the value at the memory location changes v's value also
  147. a[0] = 42
  148. self.failUnlessEqual(v.value, a[0])
  149. def test_float_from_address(self):
  150. from array import array
  151. for t in float_types:
  152. a = array(t._type_, [3.14])
  153. v = t.from_address(a.buffer_info()[0])
  154. self.failUnlessEqual(v.value, a[0])
  155. self.failUnless(type(v) is t)
  156. a[0] = 2.3456e17
  157. self.failUnlessEqual(v.value, a[0])
  158. self.failUnless(type(v) is t)
  159. def test_char_from_address(self):
  160. from ctypes import c_char
  161. from array import array
  162. a = array('c', 'x')
  163. v = c_char.from_address(a.buffer_info()[0])
  164. self.failUnlessEqual(v.value, a[0])
  165. self.failUnless(type(v) is c_char)
  166. a[0] = '?'
  167. self.failUnlessEqual(v.value, a[0])
  168. # array does not support c_bool / 't'
  169. # def test_bool_from_address(self):
  170. # from ctypes import c_bool
  171. # from array import array
  172. # a = array(c_bool._type_, [True])
  173. # v = t.from_address(a.buffer_info()[0])
  174. # self.failUnlessEqual(v.value, a[0])
  175. # self.failUnlessEqual(type(v) is t)
  176. # a[0] = False
  177. # self.failUnlessEqual(v.value, a[0])
  178. # self.failUnlessEqual(type(v) is t)
  179. def test_init(self):
  180. # c_int() can be initialized from Python's int, and c_int.
  181. # Not from c_long or so, which seems strange, abd should
  182. # probably be changed:
  183. self.assertRaises(TypeError, c_int, c_long(42))
  184. ## def test_perf(self):
  185. ## check_perf()
  186. from ctypes import _SimpleCData
  187. class c_int_S(_SimpleCData):
  188. _type_ = "i"
  189. __slots__ = []
  190. def run_test(rep, msg, func, arg=None):
  191. ## items = [None] * rep
  192. items = range(rep)
  193. from time import clock
  194. if arg is not None:
  195. start = clock()
  196. for i in items:
  197. func(arg); func(arg); func(arg); func(arg); func(arg)
  198. stop = clock()
  199. else:
  200. start = clock()
  201. for i in items:
  202. func(); func(); func(); func(); func()
  203. stop = clock()
  204. print "%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep))
  205. def check_perf():
  206. # Construct 5 objects
  207. from ctypes import c_int
  208. REP = 200000
  209. run_test(REP, "int()", int)
  210. run_test(REP, "int(999)", int)
  211. run_test(REP, "c_int()", c_int)
  212. run_test(REP, "c_int(999)", c_int)
  213. run_test(REP, "c_int_S()", c_int_S)
  214. run_test(REP, "c_int_S(999)", c_int_S)
  215. # Python 2.3 -OO, win2k, P4 700 MHz:
  216. #
  217. # int(): 0.87 us
  218. # int(999): 0.87 us
  219. # c_int(): 3.35 us
  220. # c_int(999): 3.34 us
  221. # c_int_S(): 3.23 us
  222. # c_int_S(999): 3.24 us
  223. # Python 2.2 -OO, win2k, P4 700 MHz:
  224. #
  225. # int(): 0.89 us
  226. # int(999): 0.89 us
  227. # c_int(): 9.99 us
  228. # c_int(999): 10.02 us
  229. # c_int_S(): 9.87 us
  230. # c_int_S(999): 9.85 us
  231. if __name__ == '__main__':
  232. ## check_perf()
  233. unittest.main()