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