1import array 2import struct 3import sys 4import unittest 5from operator import truth 6from ctypes import (byref, sizeof, alignment, 7 c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, 8 c_long, c_ulong, c_longlong, c_ulonglong, 9 c_float, c_double, c_longdouble, c_bool) 10 11 12def valid_ranges(*types): 13 # given a sequence of numeric types, collect their _type_ 14 # attribute, which is a single format character compatible with 15 # the struct module, use the struct module to calculate the 16 # minimum and maximum value allowed for this format. 17 # Returns a list of (min, max) values. 18 result = [] 19 for t in types: 20 fmt = t._type_ 21 size = struct.calcsize(fmt) 22 a = struct.unpack(fmt, (b"\x00"*32)[:size])[0] 23 b = struct.unpack(fmt, (b"\xFF"*32)[:size])[0] 24 c = struct.unpack(fmt, (b"\x7F"+b"\x00"*32)[:size])[0] 25 d = struct.unpack(fmt, (b"\x80"+b"\xFF"*32)[:size])[0] 26 result.append((min(a, b, c, d), max(a, b, c, d))) 27 return result 28 29 30ArgType = type(byref(c_int(0))) 31 32unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong] 33signed_types = [c_byte, c_short, c_int, c_long, c_longlong] 34bool_types = [c_bool] 35float_types = [c_double, c_float] 36 37unsigned_ranges = valid_ranges(*unsigned_types) 38signed_ranges = valid_ranges(*signed_types) 39bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] 40 41 42class NumberTestCase(unittest.TestCase): 43 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.assertEqual(t().value, 0) 48 49 def test_unsigned_values(self): 50 # the value given to the constructor is available 51 # as the 'value' attribute 52 for t, (l, h) in zip(unsigned_types, unsigned_ranges): 53 self.assertEqual(t(l).value, l) 54 self.assertEqual(t(h).value, h) 55 56 def test_signed_values(self): 57 # see above 58 for t, (l, h) in zip(signed_types, signed_ranges): 59 self.assertEqual(t(l).value, l) 60 self.assertEqual(t(h).value, h) 61 62 def test_bool_values(self): 63 for t, v in zip(bool_types, bool_values): 64 self.assertEqual(t(v).value, truth(v)) 65 66 def test_typeerror(self): 67 # Only numbers are allowed in the constructor, 68 # otherwise TypeError is raised 69 for t in signed_types + unsigned_types + float_types: 70 self.assertRaises(TypeError, t, "") 71 self.assertRaises(TypeError, t, None) 72 73 def test_from_param(self): 74 # the from_param class method attribute always 75 # returns PyCArgObject instances 76 for t in signed_types + unsigned_types + float_types: 77 self.assertEqual(ArgType, type(t.from_param(0))) 78 79 def test_byref(self): 80 # calling byref returns also a PyCArgObject instance 81 for t in signed_types + unsigned_types + float_types + bool_types: 82 parm = byref(t()) 83 self.assertEqual(ArgType, type(parm)) 84 85 86 def test_floats(self): 87 # c_float and c_double can be created from 88 # Python int and float 89 class FloatLike: 90 def __float__(self): 91 return 2.0 92 f = FloatLike() 93 for t in float_types: 94 self.assertEqual(t(2.0).value, 2.0) 95 self.assertEqual(t(2).value, 2.0) 96 self.assertEqual(t(2).value, 2.0) 97 self.assertEqual(t(f).value, 2.0) 98 99 def test_integers(self): 100 class FloatLike: 101 def __float__(self): 102 return 2.0 103 f = FloatLike() 104 class IntLike: 105 def __int__(self): 106 return 2 107 d = IntLike() 108 class IndexLike: 109 def __index__(self): 110 return 2 111 i = IndexLike() 112 # integers cannot be constructed from floats, 113 # but from integer-like objects 114 for t in signed_types + unsigned_types: 115 self.assertRaises(TypeError, t, 3.14) 116 self.assertRaises(TypeError, t, f) 117 self.assertRaises(TypeError, t, d) 118 self.assertEqual(t(i).value, 2) 119 120 def test_sizes(self): 121 for t in signed_types + unsigned_types + float_types + bool_types: 122 try: 123 size = struct.calcsize(t._type_) 124 except struct.error: 125 continue 126 # sizeof of the type... 127 self.assertEqual(sizeof(t), size) 128 # and sizeof of an instance 129 self.assertEqual(sizeof(t()), size) 130 131 def test_alignments(self): 132 for t in signed_types + unsigned_types + float_types: 133 code = t._type_ # the typecode 134 align = struct.calcsize("c%c" % code) - struct.calcsize(code) 135 136 # alignment of the type... 137 self.assertEqual((code, alignment(t)), 138 (code, align)) 139 # and alignment of an instance 140 self.assertEqual((code, alignment(t())), 141 (code, align)) 142 143 def test_int_from_address(self): 144 for t in signed_types + unsigned_types: 145 # the array module doesn't support all format codes 146 # (no 'q' or 'Q') 147 try: 148 array.array(t._type_) 149 except ValueError: 150 continue 151 a = array.array(t._type_, [100]) 152 153 # v now is an integer at an 'external' memory location 154 v = t.from_address(a.buffer_info()[0]) 155 self.assertEqual(v.value, a[0]) 156 self.assertEqual(type(v), t) 157 158 # changing the value at the memory location changes v's value also 159 a[0] = 42 160 self.assertEqual(v.value, a[0]) 161 162 163 def test_float_from_address(self): 164 for t in float_types: 165 a = array.array(t._type_, [3.14]) 166 v = t.from_address(a.buffer_info()[0]) 167 self.assertEqual(v.value, a[0]) 168 self.assertIs(type(v), t) 169 a[0] = 2.3456e17 170 self.assertEqual(v.value, a[0]) 171 self.assertIs(type(v), t) 172 173 def test_char_from_address(self): 174 a = array.array('b', [0]) 175 a[0] = ord('x') 176 v = c_char.from_address(a.buffer_info()[0]) 177 self.assertEqual(v.value, b'x') 178 self.assertIs(type(v), c_char) 179 180 a[0] = ord('?') 181 self.assertEqual(v.value, b'?') 182 183 def test_init(self): 184 # c_int() can be initialized from Python's int, and c_int. 185 # Not from c_long or so, which seems strange, abc should 186 # probably be changed: 187 self.assertRaises(TypeError, c_int, c_long(42)) 188 189 def test_float_overflow(self): 190 big_int = int(sys.float_info.max) * 2 191 for t in float_types + [c_longdouble]: 192 self.assertRaises(OverflowError, t, big_int) 193 if (hasattr(t, "__ctype_be__")): 194 self.assertRaises(OverflowError, t.__ctype_be__, big_int) 195 if (hasattr(t, "__ctype_le__")): 196 self.assertRaises(OverflowError, t.__ctype_le__, big_int) 197 198 199if __name__ == '__main__': 200 unittest.main() 201