1from ctypes import * 2import unittest 3import os 4 5import ctypes 6import _ctypes_test 7 8class BITS(Structure): 9 _fields_ = [("A", c_int, 1), 10 ("B", c_int, 2), 11 ("C", c_int, 3), 12 ("D", c_int, 4), 13 ("E", c_int, 5), 14 ("F", c_int, 6), 15 ("G", c_int, 7), 16 ("H", c_int, 8), 17 ("I", c_int, 9), 18 19 ("M", c_short, 1), 20 ("N", c_short, 2), 21 ("O", c_short, 3), 22 ("P", c_short, 4), 23 ("Q", c_short, 5), 24 ("R", c_short, 6), 25 ("S", c_short, 7)] 26 27func = CDLL(_ctypes_test.__file__).unpack_bitfields 28func.argtypes = POINTER(BITS), c_char 29 30##for n in "ABCDEFGHIMNOPQRS": 31## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset 32 33class C_Test(unittest.TestCase): 34 35 def test_ints(self): 36 for i in range(512): 37 for name in "ABCDEFGHI": 38 b = BITS() 39 setattr(b, name, i) 40 self.assertEqual((name, i, getattr(b, name)), (name, i, func(byref(b), name))) 41 42 def test_shorts(self): 43 for i in range(256): 44 for name in "MNOPQRS": 45 b = BITS() 46 setattr(b, name, i) 47 self.assertEqual((name, i, getattr(b, name)), (name, i, func(byref(b), name))) 48 49signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong) 50unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong) 51int_types = unsigned_int_types + signed_int_types 52 53class BitFieldTest(unittest.TestCase): 54 55 def test_longlong(self): 56 class X(Structure): 57 _fields_ = [("a", c_longlong, 1), 58 ("b", c_longlong, 62), 59 ("c", c_longlong, 1)] 60 61 self.assertEqual(sizeof(X), sizeof(c_longlong)) 62 x = X() 63 x.a, x.b, x.c = -1, 7, -1 64 self.assertEqual((x.a, x.b, x.c), (-1, 7, -1)) 65 66 def test_ulonglong(self): 67 class X(Structure): 68 _fields_ = [("a", c_ulonglong, 1), 69 ("b", c_ulonglong, 62), 70 ("c", c_ulonglong, 1)] 71 72 self.assertEqual(sizeof(X), sizeof(c_longlong)) 73 x = X() 74 self.assertEqual((x.a, x.b, x.c), (0, 0, 0)) 75 x.a, x.b, x.c = 7, 7, 7 76 self.assertEqual((x.a, x.b, x.c), (1, 7, 1)) 77 78 def test_signed(self): 79 for c_typ in signed_int_types: 80 class X(Structure): 81 _fields_ = [("dummy", c_typ), 82 ("a", c_typ, 3), 83 ("b", c_typ, 3), 84 ("c", c_typ, 1)] 85 self.assertEqual(sizeof(X), sizeof(c_typ)*2) 86 87 x = X() 88 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0)) 89 x.a = -1 90 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, -1, 0, 0)) 91 x.a, x.b = 0, -1 92 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, -1, 0)) 93 94 95 def test_unsigned(self): 96 for c_typ in unsigned_int_types: 97 class X(Structure): 98 _fields_ = [("a", c_typ, 3), 99 ("b", c_typ, 3), 100 ("c", c_typ, 1)] 101 self.assertEqual(sizeof(X), sizeof(c_typ)) 102 103 x = X() 104 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0)) 105 x.a = -1 106 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 7, 0, 0)) 107 x.a, x.b = 0, -1 108 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0)) 109 110 111 def fail_fields(self, *fields): 112 return self.get_except(type(Structure), "X", (), 113 {"_fields_": fields}) 114 115 def test_nonint_types(self): 116 # bit fields are not allowed on non-integer types. 117 result = self.fail_fields(("a", c_char_p, 1)) 118 self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char_p')) 119 120 result = self.fail_fields(("a", c_void_p, 1)) 121 self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_void_p')) 122 123 if c_int != c_long: 124 result = self.fail_fields(("a", POINTER(c_int), 1)) 125 self.assertEqual(result, (TypeError, 'bit fields not allowed for type LP_c_int')) 126 127 result = self.fail_fields(("a", c_char, 1)) 128 self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char')) 129 130 try: 131 c_wchar 132 except NameError: 133 pass 134 else: 135 result = self.fail_fields(("a", c_wchar, 1)) 136 self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_wchar')) 137 138 class Dummy(Structure): 139 _fields_ = [] 140 141 result = self.fail_fields(("a", Dummy, 1)) 142 self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy')) 143 144 def test_single_bitfield_size(self): 145 for c_typ in int_types: 146 result = self.fail_fields(("a", c_typ, -1)) 147 self.assertEqual(result, (ValueError, 'number of bits invalid for bit field')) 148 149 result = self.fail_fields(("a", c_typ, 0)) 150 self.assertEqual(result, (ValueError, 'number of bits invalid for bit field')) 151 152 class X(Structure): 153 _fields_ = [("a", c_typ, 1)] 154 self.assertEqual(sizeof(X), sizeof(c_typ)) 155 156 class X(Structure): 157 _fields_ = [("a", c_typ, sizeof(c_typ)*8)] 158 self.assertEqual(sizeof(X), sizeof(c_typ)) 159 160 result = self.fail_fields(("a", c_typ, sizeof(c_typ)*8 + 1)) 161 self.assertEqual(result, (ValueError, 'number of bits invalid for bit field')) 162 163 def test_multi_bitfields_size(self): 164 class X(Structure): 165 _fields_ = [("a", c_short, 1), 166 ("b", c_short, 14), 167 ("c", c_short, 1)] 168 self.assertEqual(sizeof(X), sizeof(c_short)) 169 170 class X(Structure): 171 _fields_ = [("a", c_short, 1), 172 ("a1", c_short), 173 ("b", c_short, 14), 174 ("c", c_short, 1)] 175 self.assertEqual(sizeof(X), sizeof(c_short)*3) 176 self.assertEqual(X.a.offset, 0) 177 self.assertEqual(X.a1.offset, sizeof(c_short)) 178 self.assertEqual(X.b.offset, sizeof(c_short)*2) 179 self.assertEqual(X.c.offset, sizeof(c_short)*2) 180 181 class X(Structure): 182 _fields_ = [("a", c_short, 3), 183 ("b", c_short, 14), 184 ("c", c_short, 14)] 185 self.assertEqual(sizeof(X), sizeof(c_short)*3) 186 self.assertEqual(X.a.offset, sizeof(c_short)*0) 187 self.assertEqual(X.b.offset, sizeof(c_short)*1) 188 self.assertEqual(X.c.offset, sizeof(c_short)*2) 189 190 191 def get_except(self, func, *args, **kw): 192 try: 193 func(*args, **kw) 194 except Exception, detail: 195 return detail.__class__, str(detail) 196 197 def test_mixed_1(self): 198 class X(Structure): 199 _fields_ = [("a", c_byte, 4), 200 ("b", c_int, 4)] 201 if os.name in ("nt", "ce"): 202 self.assertEqual(sizeof(X), sizeof(c_int)*2) 203 else: 204 self.assertEqual(sizeof(X), sizeof(c_int)) 205 206 def test_mixed_2(self): 207 class X(Structure): 208 _fields_ = [("a", c_byte, 4), 209 ("b", c_int, 32)] 210 self.assertEqual(sizeof(X), sizeof(c_int)*2) 211 212 def test_mixed_3(self): 213 class X(Structure): 214 _fields_ = [("a", c_byte, 4), 215 ("b", c_ubyte, 4)] 216 self.assertEqual(sizeof(X), sizeof(c_byte)) 217 218 def test_mixed_4(self): 219 class X(Structure): 220 _fields_ = [("a", c_short, 4), 221 ("b", c_short, 4), 222 ("c", c_int, 24), 223 ("d", c_short, 4), 224 ("e", c_short, 4), 225 ("f", c_int, 24)] 226 # MSVC does NOT combine c_short and c_int into one field, GCC 227 # does (unless GCC is run with '-mms-bitfields' which 228 # produces code compatible with MSVC). 229 if os.name in ("nt", "ce"): 230 self.assertEqual(sizeof(X), sizeof(c_int) * 4) 231 else: 232 self.assertEqual(sizeof(X), sizeof(c_int) * 2) 233 234 def test_anon_bitfields(self): 235 # anonymous bit-fields gave a strange error message 236 class X(Structure): 237 _fields_ = [("a", c_byte, 4), 238 ("b", c_ubyte, 4)] 239 class Y(Structure): 240 _anonymous_ = ["_"] 241 _fields_ = [("_", X)] 242 243 @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") 244 def test_uint32(self): 245 class X(Structure): 246 _fields_ = [("a", c_uint32, 32)] 247 x = X() 248 x.a = 10 249 self.assertEqual(x.a, 10) 250 x.a = 0xFDCBA987 251 self.assertEqual(x.a, 0xFDCBA987) 252 253 @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") 254 def test_uint64(self): 255 class X(Structure): 256 _fields_ = [("a", c_uint64, 64)] 257 x = X() 258 x.a = 10 259 self.assertEqual(x.a, 10) 260 x.a = 0xFEDCBA9876543211 261 self.assertEqual(x.a, 0xFEDCBA9876543211) 262 263if __name__ == "__main__": 264 unittest.main() 265