1import platform 2import sys 3import unittest 4from ctypes import * 5from ctypes.test import need_symbol 6from struct import calcsize 7import _ctypes_test 8from test import support 9 10# The following definition is meant to be used from time to time to assist 11# temporarily disabling tests on specific architectures while investigations 12# are in progress, to keep buildbots happy. 13MACHINE = platform.machine() 14 15class SubclassesTest(unittest.TestCase): 16 def test_subclass(self): 17 class X(Structure): 18 _fields_ = [("a", c_int)] 19 20 class Y(X): 21 _fields_ = [("b", c_int)] 22 23 class Z(X): 24 pass 25 26 self.assertEqual(sizeof(X), sizeof(c_int)) 27 self.assertEqual(sizeof(Y), sizeof(c_int)*2) 28 self.assertEqual(sizeof(Z), sizeof(c_int)) 29 self.assertEqual(X._fields_, [("a", c_int)]) 30 self.assertEqual(Y._fields_, [("b", c_int)]) 31 self.assertEqual(Z._fields_, [("a", c_int)]) 32 33 def test_subclass_delayed(self): 34 class X(Structure): 35 pass 36 self.assertEqual(sizeof(X), 0) 37 X._fields_ = [("a", c_int)] 38 39 class Y(X): 40 pass 41 self.assertEqual(sizeof(Y), sizeof(X)) 42 Y._fields_ = [("b", c_int)] 43 44 class Z(X): 45 pass 46 47 self.assertEqual(sizeof(X), sizeof(c_int)) 48 self.assertEqual(sizeof(Y), sizeof(c_int)*2) 49 self.assertEqual(sizeof(Z), sizeof(c_int)) 50 self.assertEqual(X._fields_, [("a", c_int)]) 51 self.assertEqual(Y._fields_, [("b", c_int)]) 52 self.assertEqual(Z._fields_, [("a", c_int)]) 53 54class StructureTestCase(unittest.TestCase): 55 formats = {"c": c_char, 56 "b": c_byte, 57 "B": c_ubyte, 58 "h": c_short, 59 "H": c_ushort, 60 "i": c_int, 61 "I": c_uint, 62 "l": c_long, 63 "L": c_ulong, 64 "q": c_longlong, 65 "Q": c_ulonglong, 66 "f": c_float, 67 "d": c_double, 68 } 69 70 def test_simple_structs(self): 71 for code, tp in self.formats.items(): 72 class X(Structure): 73 _fields_ = [("x", c_char), 74 ("y", tp)] 75 self.assertEqual((sizeof(X), code), 76 (calcsize("c%c0%c" % (code, code)), code)) 77 78 def test_unions(self): 79 for code, tp in self.formats.items(): 80 class X(Union): 81 _fields_ = [("x", c_char), 82 ("y", tp)] 83 self.assertEqual((sizeof(X), code), 84 (calcsize("%c" % (code)), code)) 85 86 def test_struct_alignment(self): 87 class X(Structure): 88 _fields_ = [("x", c_char * 3)] 89 self.assertEqual(alignment(X), calcsize("s")) 90 self.assertEqual(sizeof(X), calcsize("3s")) 91 92 class Y(Structure): 93 _fields_ = [("x", c_char * 3), 94 ("y", c_int)] 95 self.assertEqual(alignment(Y), alignment(c_int)) 96 self.assertEqual(sizeof(Y), calcsize("3si")) 97 98 class SI(Structure): 99 _fields_ = [("a", X), 100 ("b", Y)] 101 self.assertEqual(alignment(SI), max(alignment(Y), alignment(X))) 102 self.assertEqual(sizeof(SI), calcsize("3s0i 3si 0i")) 103 104 class IS(Structure): 105 _fields_ = [("b", Y), 106 ("a", X)] 107 108 self.assertEqual(alignment(SI), max(alignment(X), alignment(Y))) 109 self.assertEqual(sizeof(IS), calcsize("3si 3s 0i")) 110 111 class XX(Structure): 112 _fields_ = [("a", X), 113 ("b", X)] 114 self.assertEqual(alignment(XX), alignment(X)) 115 self.assertEqual(sizeof(XX), calcsize("3s 3s 0s")) 116 117 def test_empty(self): 118 # I had problems with these 119 # 120 # Although these are pathological cases: Empty Structures! 121 class X(Structure): 122 _fields_ = [] 123 124 class Y(Union): 125 _fields_ = [] 126 127 # Is this really the correct alignment, or should it be 0? 128 self.assertTrue(alignment(X) == alignment(Y) == 1) 129 self.assertTrue(sizeof(X) == sizeof(Y) == 0) 130 131 class XX(Structure): 132 _fields_ = [("a", X), 133 ("b", X)] 134 135 self.assertEqual(alignment(XX), 1) 136 self.assertEqual(sizeof(XX), 0) 137 138 def test_fields(self): 139 # test the offset and size attributes of Structure/Union fields. 140 class X(Structure): 141 _fields_ = [("x", c_int), 142 ("y", c_char)] 143 144 self.assertEqual(X.x.offset, 0) 145 self.assertEqual(X.x.size, sizeof(c_int)) 146 147 self.assertEqual(X.y.offset, sizeof(c_int)) 148 self.assertEqual(X.y.size, sizeof(c_char)) 149 150 # readonly 151 self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92) 152 self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92) 153 154 class X(Union): 155 _fields_ = [("x", c_int), 156 ("y", c_char)] 157 158 self.assertEqual(X.x.offset, 0) 159 self.assertEqual(X.x.size, sizeof(c_int)) 160 161 self.assertEqual(X.y.offset, 0) 162 self.assertEqual(X.y.size, sizeof(c_char)) 163 164 # readonly 165 self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92) 166 self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92) 167 168 # XXX Should we check nested data types also? 169 # offset is always relative to the class... 170 171 def test_packed(self): 172 class X(Structure): 173 _fields_ = [("a", c_byte), 174 ("b", c_longlong)] 175 _pack_ = 1 176 177 self.assertEqual(sizeof(X), 9) 178 self.assertEqual(X.b.offset, 1) 179 180 class X(Structure): 181 _fields_ = [("a", c_byte), 182 ("b", c_longlong)] 183 _pack_ = 2 184 self.assertEqual(sizeof(X), 10) 185 self.assertEqual(X.b.offset, 2) 186 187 import struct 188 longlong_size = struct.calcsize("q") 189 longlong_align = struct.calcsize("bq") - longlong_size 190 191 class X(Structure): 192 _fields_ = [("a", c_byte), 193 ("b", c_longlong)] 194 _pack_ = 4 195 self.assertEqual(sizeof(X), min(4, longlong_align) + longlong_size) 196 self.assertEqual(X.b.offset, min(4, longlong_align)) 197 198 class X(Structure): 199 _fields_ = [("a", c_byte), 200 ("b", c_longlong)] 201 _pack_ = 8 202 203 self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size) 204 self.assertEqual(X.b.offset, min(8, longlong_align)) 205 206 207 d = {"_fields_": [("a", "b"), 208 ("b", "q")], 209 "_pack_": -1} 210 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d) 211 212 @support.cpython_only 213 def test_packed_c_limits(self): 214 # Issue 15989 215 import _testcapi 216 d = {"_fields_": [("a", c_byte)], 217 "_pack_": _testcapi.INT_MAX + 1} 218 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d) 219 d = {"_fields_": [("a", c_byte)], 220 "_pack_": _testcapi.UINT_MAX + 2} 221 self.assertRaises(ValueError, type(Structure), "X", (Structure,), d) 222 223 def test_initializers(self): 224 class Person(Structure): 225 _fields_ = [("name", c_char*6), 226 ("age", c_int)] 227 228 self.assertRaises(TypeError, Person, 42) 229 self.assertRaises(ValueError, Person, b"asldkjaslkdjaslkdj") 230 self.assertRaises(TypeError, Person, "Name", "HI") 231 232 # short enough 233 self.assertEqual(Person(b"12345", 5).name, b"12345") 234 # exact fit 235 self.assertEqual(Person(b"123456", 5).name, b"123456") 236 # too long 237 self.assertRaises(ValueError, Person, b"1234567", 5) 238 239 def test_conflicting_initializers(self): 240 class POINT(Structure): 241 _fields_ = [("phi", c_float), ("rho", c_float)] 242 # conflicting positional and keyword args 243 self.assertRaisesRegex(TypeError, "phi", POINT, 2, 3, phi=4) 244 self.assertRaisesRegex(TypeError, "rho", POINT, 2, 3, rho=4) 245 246 # too many initializers 247 self.assertRaises(TypeError, POINT, 2, 3, 4) 248 249 def test_keyword_initializers(self): 250 class POINT(Structure): 251 _fields_ = [("x", c_int), ("y", c_int)] 252 pt = POINT(1, 2) 253 self.assertEqual((pt.x, pt.y), (1, 2)) 254 255 pt = POINT(y=2, x=1) 256 self.assertEqual((pt.x, pt.y), (1, 2)) 257 258 def test_invalid_field_types(self): 259 class POINT(Structure): 260 pass 261 self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)]) 262 263 def test_invalid_name(self): 264 # field name must be string 265 def declare_with_name(name): 266 class S(Structure): 267 _fields_ = [(name, c_int)] 268 269 self.assertRaises(TypeError, declare_with_name, b"x") 270 271 def test_intarray_fields(self): 272 class SomeInts(Structure): 273 _fields_ = [("a", c_int * 4)] 274 275 # can use tuple to initialize array (but not list!) 276 self.assertEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0]) 277 self.assertEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0]) 278 self.assertEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1]) 279 self.assertEqual(SomeInts((1, 2)).a[::2], [1, 0]) 280 self.assertEqual(SomeInts((1, 2)).a[1:5:6], [2]) 281 self.assertEqual(SomeInts((1, 2)).a[6:4:-1], []) 282 self.assertEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4]) 283 self.assertEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4]) 284 # too long 285 # XXX Should raise ValueError?, not RuntimeError 286 self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5)) 287 288 def test_nested_initializers(self): 289 # test initializing nested structures 290 class Phone(Structure): 291 _fields_ = [("areacode", c_char*6), 292 ("number", c_char*12)] 293 294 class Person(Structure): 295 _fields_ = [("name", c_char * 12), 296 ("phone", Phone), 297 ("age", c_int)] 298 299 p = Person(b"Someone", (b"1234", b"5678"), 5) 300 301 self.assertEqual(p.name, b"Someone") 302 self.assertEqual(p.phone.areacode, b"1234") 303 self.assertEqual(p.phone.number, b"5678") 304 self.assertEqual(p.age, 5) 305 306 @need_symbol('c_wchar') 307 def test_structures_with_wchar(self): 308 class PersonW(Structure): 309 _fields_ = [("name", c_wchar * 12), 310 ("age", c_int)] 311 312 p = PersonW("Someone \xe9") 313 self.assertEqual(p.name, "Someone \xe9") 314 315 self.assertEqual(PersonW("1234567890").name, "1234567890") 316 self.assertEqual(PersonW("12345678901").name, "12345678901") 317 # exact fit 318 self.assertEqual(PersonW("123456789012").name, "123456789012") 319 #too long 320 self.assertRaises(ValueError, PersonW, "1234567890123") 321 322 def test_init_errors(self): 323 class Phone(Structure): 324 _fields_ = [("areacode", c_char*6), 325 ("number", c_char*12)] 326 327 class Person(Structure): 328 _fields_ = [("name", c_char * 12), 329 ("phone", Phone), 330 ("age", c_int)] 331 332 cls, msg = self.get_except(Person, b"Someone", (1, 2)) 333 self.assertEqual(cls, RuntimeError) 334 self.assertEqual(msg, 335 "(Phone) <class 'TypeError'>: " 336 "expected bytes, int found") 337 338 cls, msg = self.get_except(Person, b"Someone", (b"a", b"b", b"c")) 339 self.assertEqual(cls, RuntimeError) 340 self.assertEqual(msg, 341 "(Phone) <class 'TypeError'>: too many initializers") 342 343 def test_huge_field_name(self): 344 # issue12881: segfault with large structure field names 345 def create_class(length): 346 class S(Structure): 347 _fields_ = [('x' * length, c_int)] 348 349 for length in [10 ** i for i in range(0, 8)]: 350 try: 351 create_class(length) 352 except MemoryError: 353 # MemoryErrors are OK, we just don't want to segfault 354 pass 355 356 def get_except(self, func, *args): 357 try: 358 func(*args) 359 except Exception as detail: 360 return detail.__class__, str(detail) 361 362 @unittest.skip('test disabled') 363 def test_subclass_creation(self): 364 meta = type(Structure) 365 # same as 'class X(Structure): pass' 366 # fails, since we need either a _fields_ or a _abstract_ attribute 367 cls, msg = self.get_except(meta, "X", (Structure,), {}) 368 self.assertEqual((cls, msg), 369 (AttributeError, "class must define a '_fields_' attribute")) 370 371 def test_abstract_class(self): 372 class X(Structure): 373 _abstract_ = "something" 374 # try 'X()' 375 cls, msg = self.get_except(eval, "X()", locals()) 376 self.assertEqual((cls, msg), (TypeError, "abstract class")) 377 378 def test_methods(self): 379## class X(Structure): 380## _fields_ = [] 381 382 self.assertIn("in_dll", dir(type(Structure))) 383 self.assertIn("from_address", dir(type(Structure))) 384 self.assertIn("in_dll", dir(type(Structure))) 385 386 def test_positional_args(self): 387 # see also http://bugs.python.org/issue5042 388 class W(Structure): 389 _fields_ = [("a", c_int), ("b", c_int)] 390 class X(W): 391 _fields_ = [("c", c_int)] 392 class Y(X): 393 pass 394 class Z(Y): 395 _fields_ = [("d", c_int), ("e", c_int), ("f", c_int)] 396 397 z = Z(1, 2, 3, 4, 5, 6) 398 self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f), 399 (1, 2, 3, 4, 5, 6)) 400 z = Z(1) 401 self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f), 402 (1, 0, 0, 0, 0, 0)) 403 self.assertRaises(TypeError, lambda: Z(1, 2, 3, 4, 5, 6, 7)) 404 405 def test_pass_by_value(self): 406 # This should mirror the Test structure 407 # in Modules/_ctypes/_ctypes_test.c 408 class Test(Structure): 409 _fields_ = [ 410 ('first', c_ulong), 411 ('second', c_ulong), 412 ('third', c_ulong), 413 ] 414 415 s = Test() 416 s.first = 0xdeadbeef 417 s.second = 0xcafebabe 418 s.third = 0x0bad1dea 419 dll = CDLL(_ctypes_test.__file__) 420 func = dll._testfunc_large_struct_update_value 421 func.argtypes = (Test,) 422 func.restype = None 423 func(s) 424 self.assertEqual(s.first, 0xdeadbeef) 425 self.assertEqual(s.second, 0xcafebabe) 426 self.assertEqual(s.third, 0x0bad1dea) 427 428 def test_pass_by_value_finalizer(self): 429 # bpo-37140: Similar to test_pass_by_value(), but the Python structure 430 # has a finalizer (__del__() method): the finalizer must only be called 431 # once. 432 433 finalizer_calls = [] 434 435 class Test(Structure): 436 _fields_ = [ 437 ('first', c_ulong), 438 ('second', c_ulong), 439 ('third', c_ulong), 440 ] 441 def __del__(self): 442 finalizer_calls.append("called") 443 444 s = Test(1, 2, 3) 445 # Test the StructUnionType_paramfunc() code path which copies the 446 # structure: if the stucture is larger than sizeof(void*). 447 self.assertGreater(sizeof(s), sizeof(c_void_p)) 448 449 dll = CDLL(_ctypes_test.__file__) 450 func = dll._testfunc_large_struct_update_value 451 func.argtypes = (Test,) 452 func.restype = None 453 func(s) 454 # bpo-37140: Passing the structure by refrence must not call 455 # its finalizer! 456 self.assertEqual(finalizer_calls, []) 457 self.assertEqual(s.first, 1) 458 self.assertEqual(s.second, 2) 459 self.assertEqual(s.third, 3) 460 461 # The finalizer must be called exactly once 462 s = None 463 support.gc_collect() 464 self.assertEqual(finalizer_calls, ["called"]) 465 466 def test_pass_by_value_in_register(self): 467 class X(Structure): 468 _fields_ = [ 469 ('first', c_uint), 470 ('second', c_uint) 471 ] 472 473 s = X() 474 s.first = 0xdeadbeef 475 s.second = 0xcafebabe 476 dll = CDLL(_ctypes_test.__file__) 477 func = dll._testfunc_reg_struct_update_value 478 func.argtypes = (X,) 479 func.restype = None 480 func(s) 481 self.assertEqual(s.first, 0xdeadbeef) 482 self.assertEqual(s.second, 0xcafebabe) 483 got = X.in_dll(dll, "last_tfrsuv_arg") 484 self.assertEqual(s.first, got.first) 485 self.assertEqual(s.second, got.second) 486 487 def test_array_in_struct(self): 488 # See bpo-22273 489 490 # These should mirror the structures in Modules/_ctypes/_ctypes_test.c 491 class Test2(Structure): 492 _fields_ = [ 493 ('data', c_ubyte * 16), 494 ] 495 496 class Test3(Structure): 497 _fields_ = [ 498 ('data', c_double * 2), 499 ] 500 501 class Test3A(Structure): 502 _fields_ = [ 503 ('data', c_float * 2), 504 ] 505 506 class Test3B(Test3A): 507 _fields_ = [ 508 ('more_data', c_float * 2), 509 ] 510 511 s = Test2() 512 expected = 0 513 for i in range(16): 514 s.data[i] = i 515 expected += i 516 dll = CDLL(_ctypes_test.__file__) 517 func = dll._testfunc_array_in_struct1 518 func.restype = c_int 519 func.argtypes = (Test2,) 520 result = func(s) 521 self.assertEqual(result, expected) 522 # check the passed-in struct hasn't changed 523 for i in range(16): 524 self.assertEqual(s.data[i], i) 525 526 s = Test3() 527 s.data[0] = 3.14159 528 s.data[1] = 2.71828 529 expected = 3.14159 + 2.71828 530 func = dll._testfunc_array_in_struct2 531 func.restype = c_double 532 func.argtypes = (Test3,) 533 result = func(s) 534 self.assertEqual(result, expected) 535 # check the passed-in struct hasn't changed 536 self.assertEqual(s.data[0], 3.14159) 537 self.assertEqual(s.data[1], 2.71828) 538 539 s = Test3B() 540 s.data[0] = 3.14159 541 s.data[1] = 2.71828 542 s.more_data[0] = -3.0 543 s.more_data[1] = -2.0 544 545 expected = 3.14159 + 2.71828 - 5.0 546 func = dll._testfunc_array_in_struct2a 547 func.restype = c_double 548 func.argtypes = (Test3B,) 549 result = func(s) 550 self.assertAlmostEqual(result, expected, places=6) 551 # check the passed-in struct hasn't changed 552 self.assertAlmostEqual(s.data[0], 3.14159, places=6) 553 self.assertAlmostEqual(s.data[1], 2.71828, places=6) 554 self.assertAlmostEqual(s.more_data[0], -3.0, places=6) 555 self.assertAlmostEqual(s.more_data[1], -2.0, places=6) 556 557 def test_38368(self): 558 class U(Union): 559 _fields_ = [ 560 ('f1', c_uint8 * 16), 561 ('f2', c_uint16 * 8), 562 ('f3', c_uint32 * 4), 563 ] 564 u = U() 565 u.f3[0] = 0x01234567 566 u.f3[1] = 0x89ABCDEF 567 u.f3[2] = 0x76543210 568 u.f3[3] = 0xFEDCBA98 569 f1 = [u.f1[i] for i in range(16)] 570 f2 = [u.f2[i] for i in range(8)] 571 if sys.byteorder == 'little': 572 self.assertEqual(f1, [0x67, 0x45, 0x23, 0x01, 573 0xef, 0xcd, 0xab, 0x89, 574 0x10, 0x32, 0x54, 0x76, 575 0x98, 0xba, 0xdc, 0xfe]) 576 self.assertEqual(f2, [0x4567, 0x0123, 0xcdef, 0x89ab, 577 0x3210, 0x7654, 0xba98, 0xfedc]) 578 579 @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576') 580 def test_union_by_value(self): 581 # See bpo-16575 582 583 # These should mirror the structures in Modules/_ctypes/_ctypes_test.c 584 585 class Nested1(Structure): 586 _fields_ = [ 587 ('an_int', c_int), 588 ('another_int', c_int), 589 ] 590 591 class Test4(Union): 592 _fields_ = [ 593 ('a_long', c_long), 594 ('a_struct', Nested1), 595 ] 596 597 class Nested2(Structure): 598 _fields_ = [ 599 ('an_int', c_int), 600 ('a_union', Test4), 601 ] 602 603 class Test5(Structure): 604 _fields_ = [ 605 ('an_int', c_int), 606 ('nested', Nested2), 607 ('another_int', c_int), 608 ] 609 610 test4 = Test4() 611 dll = CDLL(_ctypes_test.__file__) 612 with self.assertRaises(TypeError) as ctx: 613 func = dll._testfunc_union_by_value1 614 func.restype = c_long 615 func.argtypes = (Test4,) 616 result = func(test4) 617 self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 618 'a union by value, which is unsupported.') 619 test5 = Test5() 620 with self.assertRaises(TypeError) as ctx: 621 func = dll._testfunc_union_by_value2 622 func.restype = c_long 623 func.argtypes = (Test5,) 624 result = func(test5) 625 self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 626 'a union by value, which is unsupported.') 627 628 # passing by reference should be OK 629 test4.a_long = 12345; 630 func = dll._testfunc_union_by_reference1 631 func.restype = c_long 632 func.argtypes = (POINTER(Test4),) 633 result = func(byref(test4)) 634 self.assertEqual(result, 12345) 635 self.assertEqual(test4.a_long, 0) 636 self.assertEqual(test4.a_struct.an_int, 0) 637 self.assertEqual(test4.a_struct.another_int, 0) 638 test4.a_struct.an_int = 0x12340000 639 test4.a_struct.another_int = 0x5678 640 func = dll._testfunc_union_by_reference2 641 func.restype = c_long 642 func.argtypes = (POINTER(Test4),) 643 result = func(byref(test4)) 644 self.assertEqual(result, 0x12345678) 645 self.assertEqual(test4.a_long, 0) 646 self.assertEqual(test4.a_struct.an_int, 0) 647 self.assertEqual(test4.a_struct.another_int, 0) 648 test5.an_int = 0x12000000 649 test5.nested.an_int = 0x345600 650 test5.another_int = 0x78 651 func = dll._testfunc_union_by_reference3 652 func.restype = c_long 653 func.argtypes = (POINTER(Test5),) 654 result = func(byref(test5)) 655 self.assertEqual(result, 0x12345678) 656 self.assertEqual(test5.an_int, 0) 657 self.assertEqual(test5.nested.an_int, 0) 658 self.assertEqual(test5.another_int, 0) 659 660 @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576') 661 def test_bitfield_by_value(self): 662 # See bpo-16576 663 664 # These should mirror the structures in Modules/_ctypes/_ctypes_test.c 665 666 class Test6(Structure): 667 _fields_ = [ 668 ('A', c_int, 1), 669 ('B', c_int, 2), 670 ('C', c_int, 3), 671 ('D', c_int, 2), 672 ] 673 674 test6 = Test6() 675 # As these are signed int fields, all are logically -1 due to sign 676 # extension. 677 test6.A = 1 678 test6.B = 3 679 test6.C = 7 680 test6.D = 3 681 dll = CDLL(_ctypes_test.__file__) 682 with self.assertRaises(TypeError) as ctx: 683 func = dll._testfunc_bitfield_by_value1 684 func.restype = c_long 685 func.argtypes = (Test6,) 686 result = func(test6) 687 self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 688 'a struct/union with a bitfield by value, which is ' 689 'unsupported.') 690 # passing by reference should be OK 691 func = dll._testfunc_bitfield_by_reference1 692 func.restype = c_long 693 func.argtypes = (POINTER(Test6),) 694 result = func(byref(test6)) 695 self.assertEqual(result, -4) 696 self.assertEqual(test6.A, 0) 697 self.assertEqual(test6.B, 0) 698 self.assertEqual(test6.C, 0) 699 self.assertEqual(test6.D, 0) 700 701 class Test7(Structure): 702 _fields_ = [ 703 ('A', c_uint, 1), 704 ('B', c_uint, 2), 705 ('C', c_uint, 3), 706 ('D', c_uint, 2), 707 ] 708 test7 = Test7() 709 test7.A = 1 710 test7.B = 3 711 test7.C = 7 712 test7.D = 3 713 func = dll._testfunc_bitfield_by_reference2 714 func.restype = c_long 715 func.argtypes = (POINTER(Test7),) 716 result = func(byref(test7)) 717 self.assertEqual(result, 14) 718 self.assertEqual(test7.A, 0) 719 self.assertEqual(test7.B, 0) 720 self.assertEqual(test7.C, 0) 721 self.assertEqual(test7.D, 0) 722 723 # for a union with bitfields, the union check happens first 724 class Test8(Union): 725 _fields_ = [ 726 ('A', c_int, 1), 727 ('B', c_int, 2), 728 ('C', c_int, 3), 729 ('D', c_int, 2), 730 ] 731 732 test8 = Test8() 733 with self.assertRaises(TypeError) as ctx: 734 func = dll._testfunc_bitfield_by_value2 735 func.restype = c_long 736 func.argtypes = (Test8,) 737 result = func(test8) 738 self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 739 'a union by value, which is unsupported.') 740 741class PointerMemberTestCase(unittest.TestCase): 742 743 def test(self): 744 # a Structure with a POINTER field 745 class S(Structure): 746 _fields_ = [("array", POINTER(c_int))] 747 748 s = S() 749 # We can assign arrays of the correct type 750 s.array = (c_int * 3)(1, 2, 3) 751 items = [s.array[i] for i in range(3)] 752 self.assertEqual(items, [1, 2, 3]) 753 754 # The following are bugs, but are included here because the unittests 755 # also describe the current behaviour. 756 # 757 # This fails with SystemError: bad arg to internal function 758 # or with IndexError (with a patch I have) 759 760 s.array[0] = 42 761 762 items = [s.array[i] for i in range(3)] 763 self.assertEqual(items, [42, 2, 3]) 764 765 s.array[0] = 1 766 767## s.array[1] = 42 768 769 items = [s.array[i] for i in range(3)] 770 self.assertEqual(items, [1, 2, 3]) 771 772 def test_none_to_pointer_fields(self): 773 class S(Structure): 774 _fields_ = [("x", c_int), 775 ("p", POINTER(c_int))] 776 777 s = S() 778 s.x = 12345678 779 s.p = None 780 self.assertEqual(s.x, 12345678) 781 782class TestRecursiveStructure(unittest.TestCase): 783 def test_contains_itself(self): 784 class Recursive(Structure): 785 pass 786 787 try: 788 Recursive._fields_ = [("next", Recursive)] 789 except AttributeError as details: 790 self.assertIn("Structure or union cannot contain itself", 791 str(details)) 792 else: 793 self.fail("Structure or union cannot contain itself") 794 795 796 def test_vice_versa(self): 797 class First(Structure): 798 pass 799 class Second(Structure): 800 pass 801 802 First._fields_ = [("second", Second)] 803 804 try: 805 Second._fields_ = [("first", First)] 806 except AttributeError as details: 807 self.assertIn("_fields_ is final", str(details)) 808 else: 809 self.fail("AttributeError not raised") 810 811if __name__ == '__main__': 812 unittest.main() 813