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