1from PyObjCTools.TestSupport import * 2 3import objc._bridgesupport as bridgesupport 4import os 5import re 6import sys 7import imp 8import ctypes 9import objc 10import subprocess 11 12import xml.etree.ElementTree as ET 13 14 15try: 16 basestring 17except NameError: 18 basestring = str 19 20try: 21 long 22except NameError: 23 long = int 24 25IDENTIFIER=re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") 26 27TEST_XML=b"""\ 28<signatures> 29 <unknown><!-- ignore --> 30 <enum name='nested1' value='4' /><!-- should be ignored --> 31 </unknown> 32 <opaque name='opaque1' type='^{opaque1}'/> 33 <opaque name='opaque2' type='^{opaque2=f}' type64='^{opaque2=d}' /> 34 <opaque type='^{opaque2=f}' type64='^{opaque2=d}' /><!-- ignore --> 35 <opaque name='opaque3' /><!-- ignore --> 36 <opaque name='opaque4' type64='^{opaque4=d}' /><!-- ignore 32-bit --> 37 <opaque /><!-- ignore --> 38 <constant name='constant1' type='@'/> 39 <constant name='constant2' type='I' type64='Q' /> 40 <constant type='@'/><!-- ignore --> 41 <constant name='constant3' /><!-- ignore --> 42 <constant name='constant4' type64='Q' /><!-- ignore 32-bit --> 43 <constant name='constant5' type='B' /><!-- NSBOOL --> 44 <constant name='constant6' type='Z' /><!-- bool --> 45 <constant name='constant7' type='@' magic_cookie='false' /> 46 <constant name='constant8' type='@' magic_cookie='true' /> 47 <constant /><!-- ignore --> 48 <constant name='constant9' type='{foo=i?i}' /><!-- ignore: embedded ? --> 49 <constant name='constant10' type='{foo={x=?}}' /><!-- ignore: embedded ? --> 50 <string_constant name='strconst1' value='string constant1' /> 51 <string_constant name='strconst2' value='string constant 2' value64='string constant two' /> 52 <string_constant name='strconst1u' value='string constant1 unicode' nsstring='true' /> 53 <string_constant name='strconst2u' value='string constant 2 unicode' value64='string constant two unicode' nsstring='true' /> 54 <string_constant name='strconst3' /><!-- ignore --> 55 <string_constant name='strconst4' nsstring='true' /><!-- ignore --> 56 <string_constant name='strconst5' value64='string five' /><!-- ignore 32-bit --> 57 <string_constant name='strconst6' value64='string five unicode' nsstring='true' /><!-- ignore 32-bit --> 58 <string_constant /><!-- ignore --> 59 <enum name='enum1' value='1' /> 60 <enum name='enum2' value='3' value64='4'/> 61 <enum name='enum3' le_value='5' be_value='6'/> 62 <enum name='enum4' value='7' be_value='8' /><!-- should have value 7 --> 63 <enum name='enum5' /><!-- ignore --> 64 <enum value='3' value64='4'/><!-- ignore --> 65 <enum name='enum6' value64='4'/><!-- ignore 32-bit --> 66 <enum name='enum7' be_value='6' /><!-- ignore intel --> 67 <enum name='enum8' le_value='5' /><!-- ignore ppc --> 68 <enum name='enum9' value='2.5' /> 69 <enum name='enum10' value='0x1.5p+3' /> 70 <enum /><!-- ignore --> 71 <null_const name='null1' /> 72 <null_const /><!-- ignore --> 73 <function_pointer name='func1' original='orig_function' /> 74 <function_pointer name='func2' /><!-- ignore --> 75 <function_pointer original='func3' /><!-- ignore --> 76 <function_pointer /><!-- ignore --> 77 <cftype name='CFProxy1Ref' type='^{CFProxy}' gettypeid_func='CFArrayGetTypeID' /> 78 <cftype name='CFProxy2Ref' type='^{CFProxy32}' type64='^{CFProxy64}' gettypeid_func='CFArrayGetTypeID' /> 79 <cftype name='CFProxy3Ref' type='^{CFProxy3}' tollfree='NSProxy' gettypeid_func='CFArrayGetTypeID' /> 80 <cftype name='CFProxy4Ref' type='^{CFProxy4}' tollfree='NSProxy2' /> 81 <cftype name='CFProxy5Ref' type='^{CFProxy}' gettypeid_func='NoSuchFunction' /><!-- tollfree to CFTypeRef --> 82 <cftype name='CFProxy6Ref' type='^{CFProxy}' /> 83 <cftype name='CFProxy7Ref' type='^{CFProxy32}' type64='^{CFProxy64}' /> 84 <cftype type='^{CFProxy}' gettypeid_func='CFArrayGetTypeID' /><!-- ignore --> 85 <cftype name='CFProxy8Ref' gettypeid_func='CFArrayGetTypeID' /><!-- ignore --> 86 <cftype name='CFProxy9Ref' type64='^{CFProxy64}' gettypeid_func='CFArrayGetTypeID' /><!-- ignore 32-bit --> 87 <cftype/><!-- ignore --> 88 <class name='MyClass1'></class> 89 <class /><!-- ignore --> 90 <class name='MyClass2'> 91 <function name='method.function'></function><!-- ignore, not at toplevel --> 92 <method selector='method1' classmethod='true' ></method> 93 <method selector='method2' variadic='true' ></method> 94 <method selector='method3' variadic='true' c_array_delimited_by_null='true'></method> 95 <method selector='method4' variadic='true' c_array_length_in_arg='4'></method> 96 <method selector='method5' c_array_delimited_by_null='true'><retval type='d'/></method><!-- c_array... ignored --> 97 <method selector='method6' c_array_length_in_arg='4'><retval type='d' /></method><!-- c_array... ignored --> 98 <method selector='method7' ignore='true'></method> 99 <method selector='method8' ignore='true' suggestion='ignore me'></method> 100 <method selector='method9' suggestion='ignore me'><retval type='d'/></method><!-- suggestion ignored --> 101 <method selector='method10'> 102 <retval type='d'/> 103 </method> 104 <method selector='method11' classmethod='false'> 105 <retval type='f' type64='d' /> 106 </method> 107 <method selector='method12' classmethod='true'> 108 <retval/><!-- ignore --> 109 </method> 110 <method selector='method13' class_method='true'> 111 <retval type_modifier='n' /> 112 </method> 113 <method selector='method13b' class_method='false'> 114 <retval sel_of_type='v@:f' c_array_of_fixed_length='4'/> 115 </method> 116 <method selector='method14'> 117 <retval sel_of_type='v@:f' sel_of_type64='v@:d' /> 118 </method> 119 <method selector='method15'> 120 <retval null_accepted='false' already_retained='true' c_array_length_in_result='true' /> 121 </method> 122 <method selector='method16'> 123 <retval c_array_delimited_by_null='true' already_cfretained='true' c_array_of_variable_length='true' printf_format='true' free_result='true' /> 124 </method> 125 <method selector='method17'> 126 <retval c_array_length_in_arg='1'/> 127 </method> 128 <method selector='method18'> 129 <retval c_array_length_in_arg='1,2'/> 130 </method> 131 <method selector='method19'> 132 <retval c_array_length_in_arg='4, 5'/> 133 </method> 134 <method selector='method20'> 135 <retval function_pointer_retained='false'/><!-- ignored, no function data --> 136 </method> 137 <method selector='method21'> 138 <retval function_pointer_retained='false' function_pointer='true'> 139 <retval type='v' /> 140 <arg type='@' /> 141 <arg type='d' /> 142 </retval> 143 </method> 144 <method selector='method22'> 145 <retval function_pointer_retained='false' block='true'> 146 <retval type='v' /> 147 <arg type='@' /> 148 <arg type='d' /> 149 </retval> 150 </method> 151 <method selector='method23'> 152 <retval function_pointer='true'> 153 <retval type='v' /> 154 <arg type='@' /> 155 <arg type='d' /> 156 </retval> 157 </method> 158 <method selector='method24'> 159 <retval block='true'> 160 <retval type='v' /> 161 <arg type='@' /> 162 <arg type='d' /> 163 </retval> 164 </method> 165 <method ></method><!-- ignore --> 166 <method variadic='true'></method><!-- ignore --> 167 <method ignore='true'></method><!-- ignore --> 168 </class> 169 <class name='MyClass3'> 170 <method selector='method7'> 171 <retval type='q' /> 172 <arg index='1' type='f'/> 173 <arg index='2' type='d'/> 174 </method> 175 <method selector='method8'> 176 <arg index='1' type='d'/> 177 <arg index='2' type='d'/> 178 </method> 179 <method selector='method9'> 180 <arg type='d'/><!-- ignored: no index --> 181 </method> 182 <method selector='method10'> 183 <arg index='1' type='d'/> 184 </method> 185 <method selector='method11'> 186 <arg index='1' type='f' type64='d' /> 187 </method> 188 <method selector='method12'> 189 <arg index='1'/><!-- ignore --> 190 </method> 191 <method selector='method13'> 192 <arg index='1' type_modifier='n' /> 193 </method> 194 <method selector='method13b'> 195 <arg index='1' sel_of_type='v@:f' c_array_of_fixed_length='4'/> 196 </method> 197 <method selector='method14'> 198 <arg index='1' sel_of_type='v@:f' sel_of_type64='v@:d' /> 199 </method> 200 <method selector='method15'> 201 <arg index='1' null_accepted='false' already_retained='true' c_array_length_in_result='true' /> 202 </method> 203 <method selector='method16'> 204 <arg index='1' c_array_delimited_by_null='true' already_cfretained='true' c_array_of_variable_length='true' printf_format='true' free_result='true' /> 205 </method> 206 <method selector='method17'> 207 <arg index='1' c_array_length_in_arg='1'/> 208 </method> 209 <method selector='method18'> 210 <arg index='1' c_array_length_in_arg='1,2'/> 211 </method> 212 <method selector='method19'> 213 <arg index='1' c_array_length_in_arg='4, 5'/> 214 </method> 215 <method selector='method20'> 216 <arg index='1' function_pointer_retained='false'/><!-- ignored, no function data --> 217 </method> 218 <method selector='method21'> 219 <arg index='1' function_pointer_retained='false' function_pointer='true'> 220 <retval type='v' /> 221 <arg type='@' /> 222 <arg type='d' /> 223 </arg> 224 </method> 225 <method selector='method22'> 226 <arg index='1' function_pointer_retained='false' block='true'> 227 <retval type='v' /> 228 <arg type='@' /> 229 <arg type='d' /> 230 </arg> 231 </method> 232 <method selector='method23'> 233 <arg index='1' function_pointer='true'> 234 <retval type='v' /> 235 <arg type='@' /> 236 <arg type='d' /> 237 </arg> 238 </method> 239 <method selector='method24' classmethod='true'> 240 <arg index='1' block='true'> 241 <retval type='v' /> 242 <arg type='@' /> 243 <arg type='d' /> 244 </arg> 245 </method> 246 </class> 247 <function /><!-- ignored --> 248 <function><!-- ignored --> 249 <arg type="f" /> 250 <retval type="@" /> 251 </function> 252 <function name='function1' ignore='true' ><!-- ignore --> 253 <arg type="f" /> 254 <retval type="@" /> 255 </function> 256 <function name='function2' variadic='true' ></function> 257 <function name='function3' variadic='true' c_array_delimited_by_null='true'></function> 258 <function name='function4' variadic='true' c_array_length_in_arg='4'></function> 259 <function name='function5' c_array_delimited_by_null='true'><retval type='d'/></function><!-- c_array... ignored --> 260 <function name='function6' c_array_length_in_arg='4'><retval type='d' /></function><!-- c_array... ignored --> 261 <function name='function7' ignore='true'></function> 262 <function name='function8' ignore='true' suggestion='ignore me'></function> 263 <function name='function9' suggestion='ignore me'><retval type='d'/></function><!-- suggestion ignored --> 264 <function name='function10'> 265 <retval type='d'/> 266 </function> 267 <function name='function11'> 268 <retval type='f' type64='d' /> 269 </function> 270 <function name='function12'> 271 <retval/><!-- ignore --> 272 </function> 273 <function name='function13'> 274 <retval type='i' type_modifier='n' /> 275 </function> 276 <function name='function14'> 277 <retval type=':' sel_of_type='v@:f' c_array_of_fixed_length='4'/> 278 </function> 279 <function name='function15'> 280 <retval type=':' sel_of_type='v@:f' sel_of_type64='v@:d' /> 281 </function> 282 <function name='function16'> 283 <retval type='i' null_accepted='false' already_retained='true' c_array_length_in_result='true' /> 284 </function> 285 <function name='function17'> 286 <retval type='i' already_cfretained='true' c_array_delimited_by_null='true' c_array_of_variable_length='true' printf_format='true' free_result='true' /> 287 </function> 288 <function name='function18'> 289 <retval type='i' c_array_length_in_arg='1'/> 290 </function> 291 <function name='function19'> 292 <retval type='i' c_array_length_in_arg='1,2'/> 293 </function> 294 <function name='function20'> 295 <retval type='i' c_array_length_in_arg='4, 5'/> 296 </function> 297 <function name='function21'> 298 <retval type='?' function_pointer_retained='false'/><!-- ignored, no function data --> 299 </function> 300 <function name='function22'> 301 <retval type='?' function_pointer_retained='false' function_pointer='true'> 302 <retval type='v' /> 303 <arg type='@' /> 304 <arg type='d' /> 305 </retval> 306 </function> 307 <function name='function23'> 308 <retval type='@?' function_pointer_retained='false' block='true'> 309 <retval type='v' /> 310 <arg type='@' /> 311 <arg type='d' /> 312 </retval> 313 </function> 314 <function name='function24'> 315 <retval type='?' function_pointer='true'> 316 <retval type='v' /> 317 <arg type='@' /> 318 <arg type='d' /> 319 </retval> 320 </function> 321 <function name='function25'> 322 <retval type='@?' block='true'> 323 <retval type='v' /> 324 <arg type='@' /> 325 <arg type='d' /> 326 </retval> 327 </function> 328 <function name='function26'> 329 <retval type='q' /> 330 <arg index='1' type='f'/> 331 <arg index='2' type='d'/> 332 </function> 333 <function name='function27'> 334 <arg index='1' type='d'/> 335 <arg index='2' type='d'/> 336 </function> 337 <function name='function29'> 338 <arg type='d'/> 339 </function> 340 <function name='function30'> 341 <arg type='f' type64='d' /> 342 </function> 343 <function name='function32'> 344 <arg type='@' type_modifier='n' /> 345 </function> 346 <function name='function33'> 347 <arg type=':' sel_of_type='v@:f' c_array_of_fixed_length='4'/> 348 </function> 349 <function name='function34'> 350 <arg type=':' sel_of_type='v@:f' sel_of_type64='v@:d' /> 351 </function> 352 <function name='function35'> 353 <arg type='@' null_accepted='false' already_retained='true' c_array_length_in_result='true' /> 354 </function> 355 <function name='function36'> 356 <arg type='@' c_array_delimited_by_null='true' already_cfretained='true' c_array_of_variable_length='true' printf_format='true' free_result='true' /> 357 </function> 358 <function name='function37'> 359 <arg type='@' c_array_length_in_arg='1'/> 360 </function> 361 <function name='function38'> 362 <arg type='@' c_array_length_in_arg='1,2'/> 363 </function> 364 <function name='function39'> 365 <arg type='@' c_array_length_in_arg='4, 5'/> 366 </function> 367 <function name='function40'> 368 <arg type='?' function_pointer_retained='false'/><!-- ignored, no function data --> 369 </function> 370 <function name='function41'> 371 <arg type='?' function_pointer_retained='false' function_pointer='true'> 372 <retval type='v' /> 373 <arg type='@' /> 374 <arg type='d' /> 375 </arg> 376 </function> 377 <function name='function42'> 378 <arg type='@?' function_pointer_retained='false' block='true'> 379 <retval type='v' /> 380 <arg type='@' /> 381 <arg type='d' /> 382 </arg> 383 </function> 384 <function name='function43'> 385 <arg type='?' function_pointer='true'> 386 <retval type='v' /> 387 <arg type='@' /> 388 <arg type='d' /> 389 </arg> 390 </function> 391 <function name='function44'> 392 <arg type='@?' block='true'> 393 <retval type='v' /> 394 <arg type='@' /> 395 <arg type='d' /> 396 </arg> 397 </function> 398 <function name='function45'><!-- ignore: arg node without type--> 399 <arg type_modifier='n' /> 400 </function> 401 <function name='function46'><!-- ignore: arg node without type--> 402 <arg type='@' /> 403 <arg type_modifier='n' /> 404 </function> 405 <function name='function47'><!-- ignore: retval node without type--> 406 <retval type_modifier='n'/> 407 <arg type='@' /> 408 <arg type='@' /> 409 </function> 410 <!-- TODO: type rewriting (_C_BOOL, _C_NSBOOL)--> 411 <informal_protocol/><!-- ignore --> 412 <informal_protocol name='protocol1' /> 413 <informal_protocol name='protocol2' > 414 <method selector='selector1' type='v@:f' type64='v@:d' /> 415 <method selector='selector2' type='v@:f' type64='v@:d' classmethod='false' /> 416 <method selector='selector3' type='v@:f' type64='v@:d' classmethod='true' /> 417 <method selector='selector4' type='v@:f' type64='v@:d' variadic='true' /><!-- 'variadic' is ignored --> 418 <method selector='selector5' /><!-- ignore: no type --> 419 <method selector='selector6' type64='v@:@' /><!-- ignore 32-bit --> 420 <method selector='selector7' type='v@:f' class_method='false' /><!-- manpage: class_method, pyobjc 2.3: classmethod --> 421 <method selector='selector8' type='v@:f' class_method='true' /> 422 </informal_protocol> 423 <struct/><!-- ignore --> 424 <struct type='{foo=dd}' /><!--ignore--> 425 <struct name='struct1' /><!-- ignore --> 426 <struct name='struct2' alias='module.struct3' /><!-- ignore --> 427 <struct name='struct3' type='{struct3=@@}' /> 428 <struct name='struct4' type='{struct3=ff}' type64='{struct4=dd}' /> 429 <struct name='struct5' type='{struct3=@@}' alias='module2.struct'/> 430 <struct name='struct6' type='{struct6=BB}' /><!-- _C_NSBOOL --> 431 <struct name='struct7' type='{struct7=Z@}' /><!-- _C_BOOL --> 432 <struct name='struct8' type='{struct8=@@}' alias='sys.maxsize'/> 433 <struct name='struct9' type='{struct9=ii}' alias='sys.does_not_exist'/> 434</signatures> 435""" 436 437class TestBridgeSupportParser (TestCase): 438 def testInvalidToplevel(self): 439 self.assertRaises(objc.error, bridgesupport._BridgeSupportParser, b'<signatures2></signatures2>', 'Cocoa') 440 self.assertRaises(ET.ParseError, bridgesupport._BridgeSupportParser, b'<signatures2></signatures>', 'Cocoa') 441 442 def iter_framework_dir(self, framework_dir): 443 for dn in os.listdir(framework_dir): 444 fn = os.path.join(framework_dir, dn, 'Resources', 'BridgeSupport', dn.replace('.framework', '.bridgesupport')) 445 if os.path.exists(fn): 446 yield fn 447 448 fn = os.path.join(framework_dir, dn, 'Frameworks') 449 if os.path.exists(fn): 450 for item in self.iter_framework_dir(fn): 451 yield item 452 453 def iter_system_bridgesupport_files(self): 454 for item in self.iter_framework_dir('/System/Library/Frameworks'): 455 yield item 456 457 def test_system_bridgesupport(self): 458 with filterWarnings("ignore", RuntimeWarning): 459 # Check that all system bridgesupport files can be processed correctly 460 for fn in self.iter_system_bridgesupport_files(): 461 with open(fn, 'r') as fp: 462 xmldata = fp.read() 463 464 self.assert_valid_bridgesupport(os.path.basename(fn).split('.')[0], xmldata) 465 466 def test_xml_structure_variants(self): 467 # Run 'verify_xml_structure' for all cpu variant 468 # (big/little endian, 32- en 64-bit) 469 orig_byteorder = sys.byteorder 470 orig_maxsize = sys.maxsize 471 orig_createStructType = bridgesupport._orig_createStructType 472 orig_registerStructAlias = bridgesupport._orig_registerStructAlias 473 474 try: 475 for is32bit in (True, False): 476 for endian in ('little', 'big'): 477 sys.maxsize = 2**63-1 if endian == 'big' else 2**32-1 478 sys.byteorder = endian 479 480 # Reload the bridgesupport module because 481 # it contains conditional definitions 482 objc.createStructType = orig_createStructType 483 objc.registerStructAlias = orig_registerStructAlias 484 imp.reload(bridgesupport) 485 486 self.verify_xml_structure() 487 488 finally: 489 sys.byteorder = orig_byteorder 490 sys.maxsize = orig_maxsize 491 492 # See above 493 objc.createStructType = orig_createStructType 494 objc.registerStructAlias = orig_registerStructAlias 495 imp.reload(bridgesupport) 496 497 def verify_xml_structure(self): 498 prs = self.assert_valid_bridgesupport('TestXML', TEST_XML) 499 500 all_constants = [ 501 ('constant1', b'@', False,), 502 ('constant2', b'I' if sys.maxsize < 2**32 else b'Q' , False,), 503 ('constant5', objc._C_NSBOOL, False,), 504 ('constant6', objc._C_BOOL, False,), 505 ('constant7', b'@', False,), 506 ('constant8', b'@', True,), 507 ] 508 if sys.maxsize > 2**32: 509 all_constants.append( 510 ('constant4', b'Q', False) 511 ) 512 513 all_values = { 514 'strconst1': b'string constant1', 515 'strconst2': b'string constant 2' if sys.maxsize < 2**32 else b'string constant two', 516 'strconst1u': b'string constant1 unicode'.decode('ascii'), 517 'strconst2u': b'string constant 2 unicode'.decode('ascii') if sys.maxsize < 2**32 else b'string constant two unicode'.decode('ascii'), 518 'enum1': 1, 519 'enum2': 3 if sys.maxsize < 2**32 else 4, 520 'enum3': 5 if sys.byteorder == 'little' else 6, 521 'enum4': 7, 522 'enum9': 2.5, 523 'enum10': 10.5, 524 'null1': None, 525 } 526 if sys.maxsize > 2**32: 527 all_values['strconst5'] = b'string five' 528 all_values['strconst6'] = b'string five unicode'.decode('ascii') 529 all_values['enum6'] = 4 530 531 if sys.byteorder == 'little': 532 all_values['enum8'] = 5 533 else: 534 all_values['enum7'] = 6 535 536 all_opaque = [ 537 ('opaque1', b'^{opaque1}'), 538 ('opaque2', b'^{opaque2=f}' if sys.maxsize < 2**32 else b'^{opaque2=d}'), 539 ] 540 if sys.maxsize > 2**32: 541 all_opaque.append( 542 ('opaque4', b'^{opaque4=d}'), 543 ) 544 545 all_func_aliases = [ 546 ('func1', 'orig_function'), 547 ] 548 549 a = objc.lookUpClass('NSArray').alloc().init() 550 CFArrayTypeID = a._cfTypeID() 551 all_cftypes = [ 552 ( 'CFProxy1Ref', b'^{CFProxy}', CFArrayTypeID), 553 ( 'CFProxy2Ref', b'^{CFProxy32}' if sys.maxsize < 2**32 else b'^{CFProxy64}', CFArrayTypeID), 554 ( 'CFProxy3Ref', b'^{CFProxy3}', None, 'NSProxy'), 555 ( 'CFProxy4Ref', b'^{CFProxy4}', None, 'NSProxy2'), 556 ( 'CFProxy5Ref', b'^{CFProxy}', None, 'NSCFType'), 557 ( 'CFProxy6Ref', b'^{CFProxy}', None, 'NSCFType'), 558 ( 'CFProxy7Ref', b'^{CFProxy32}' if sys.maxsize < 2**32 else b'^{CFProxy64}', None, 'NSCFType' ), 559 ] 560 if sys.maxsize > 2**32: 561 all_cftypes.append( 562 ( 'CFProxy9Ref', b'^{CFProxy64}', CFArrayTypeID), 563 ) 564 565 566 all_methods = { 567 (b'MyClass2', b'method2', False): { 'variadic': True }, 568 (b'MyClass2', b'method3', False): { 'variadic': True, 'c_array_delimited_by_null': True }, 569 (b'MyClass2', b'method4', False): { 'variadic': True, 'c_array_length_in_arg': 4+2 }, 570 (b'MyClass2', b'method5', False): { 'retval': { 'type': b'd' } }, 571 (b'MyClass2', b'method6', False): { 'retval': { 'type': b'd' } }, 572 (b'MyClass2', b'method7', False): { 'suggestion': "don't use this method" }, 573 (b'MyClass2', b'method8', False): { 'suggestion': 'ignore me' }, 574 (b'MyClass2', b'method9', False): { 'retval': { 'type': b'd' } }, 575 (b'MyClass2', b'method10', False ): { 'retval': { 'type': b'd' } }, 576 (b'MyClass2', b'method11', False ): { 577 'retval': { 578 'type': b'f' if sys.maxsize < 2**32 else b'd' 579 } 580 }, 581 (b'MyClass2', b'method13', True): { 'retval': { 'type_modifier': b'n' } }, 582 (b'MyClass2', b'method13b', False): { 583 'retval': { 'sel_of_type': b'v@:f', 'c_array_of_fixed_length': 4 }, 584 }, 585 (b'MyClass2', b'method14', False): { 586 'retval': { 'sel_of_type': b'v@:f' if sys.maxsize < 2**32 else b'v@:d' } 587 }, 588 (b'MyClass2', b'method15', False): { 589 'retval': { 'null_accepted': False, 'already_retained': True, } 590 }, 591 (b'MyClass2', b'method16', False): { 592 'retval': { 'c_array_delimited_by_null': True, 'c_array_of_variable_length': True, 'printf_format': True, 593 'free_result': True, 'already_cfretained': True } 594 }, 595 (b'MyClass2', b'method17', False): { 596 'retval': { 'c_array_length_in_arg': 1+2 } 597 }, 598 (b'MyClass2', b'method18', False): { 599 'retval': { 'c_array_length_in_arg': (1+2, 2+2) } 600 }, 601 (b'MyClass2', b'method19', False): { 602 'retval': { 'c_array_length_in_arg': (4+2, 5+2) } 603 }, 604 (b'MyClass2', b'method21', False): { 605 'retval': { 'callable_retained': False, 'callable': { 606 'retval': { 'type': b'v' }, 607 'arguments': { 608 0: { 'type': b'@' }, 609 1: { 'type': b'd' }, 610 } 611 }} 612 }, 613 (b'MyClass2', b'method22', False): { 614 'retval': { 'callable_retained': False, 'callable': { 615 'retval': { 'type': b'v' }, 616 'arguments': { 617 0: { 'type': b'^v' }, 618 1: { 'type': b'@' }, 619 2: { 'type': b'd' }, 620 } 621 }} 622 }, 623 (b'MyClass2', b'method23', False): { 624 'retval': { 'callable_retained': True, 'callable': { 625 'retval': { 'type': b'v' }, 626 'arguments': { 627 0: { 'type': b'@' }, 628 1: { 'type': b'd' }, 629 } 630 }} 631 }, 632 (b'MyClass2', b'method24', False): { 633 'retval': { 'callable_retained': True, 'callable': { 634 'retval': { 'type': b'v' }, 635 'arguments': { 636 0: { 'type': b'^v' }, 637 1: { 'type': b'@' }, 638 2: { 'type': b'd' }, 639 } 640 }} 641 }, 642 (b'MyClass3', b'method7', False): { 643 'retval': { 'type': b'q' }, 644 'arguments': { 645 2+1: { 'type': b'f' }, 646 2+2: { 'type': b'd' }, 647 } 648 }, 649 (b'MyClass3', b'method8', False): { 650 'arguments': { 651 2+1: { 'type': b'd' }, 652 2+2: { 'type': b'd' }, 653 } 654 }, 655 (b'MyClass3', b'method10', False): { 656 'arguments': { 657 2+1: { 'type': b'd' } 658 } 659 }, 660 (b'MyClass3', b'method11', False): { 661 'arguments': { 662 2+1: { 'type': b'f' if sys.maxsize < 2**32 else b'd' } 663 } 664 }, 665 (b'MyClass3', b'method13', False): { 666 'arguments': { 667 2+1: { 'type_modifier': b'n' }, 668 } 669 }, 670 (b'MyClass3', b'method13b', False): { 671 'arguments': { 672 2+1: { 'sel_of_type': b'v@:f', 'c_array_of_fixed_length': 4 } 673 } 674 }, 675 (b'MyClass3', b'method14', False): { 676 'arguments': { 677 2+1: { 'sel_of_type': b'v@:f' if sys.maxsize < 2**32 else b'v@:d' } 678 } 679 }, 680 (b'MyClass3', b'method15', False): { 681 'arguments': { 682 2+1: { 'null_accepted': False, 'already_retained': True, 683 'c_array_length_in_result': True } 684 } 685 }, 686 (b'MyClass3', b'method16', False): { 687 'arguments': { 688 2+1: { 'c_array_delimited_by_null': True, 'c_array_of_variable_length': True, 689 'printf_format': True, 'free_result': True, 'already_cfretained': True } 690 } 691 }, 692 (b'MyClass3', b'method17', False): { 693 'arguments': { 694 2+1: { 'c_array_length_in_arg': 1+2 }, 695 } 696 }, 697 (b'MyClass3', b'method18', False): { 698 'arguments': { 699 2+1: { 'c_array_length_in_arg': (1+2, 2+2) } 700 } 701 }, 702 (b'MyClass3', b'method19', False): { 703 'arguments': { 704 2+1: { 'c_array_length_in_arg': (4+2, 5+2) } 705 } 706 }, 707 (b'MyClass3', b'method21', False): { 708 'arguments': { 709 2+1: { 'callable_retained': False, 'callable': { 710 'retval': { 'type': b'v' }, 711 'arguments': { 712 0: { 'type': b'@' }, 713 1: { 'type': b'd' }, 714 } 715 }} 716 } 717 }, 718 (b'MyClass3', b'method22', False): { 719 'arguments': { 720 2+1: { 'callable_retained': False, 'callable': { 721 'retval': { 'type': b'v' }, 722 'arguments': { 723 0: { 'type': b'^v' }, 724 1: { 'type': b'@' }, 725 2: { 'type': b'd' }, 726 } 727 }} 728 } 729 }, 730 (b'MyClass3', b'method23', False): { 731 'arguments': { 732 2+1: { 'callable_retained': True, 'callable': { 733 'retval': { 'type': b'v' }, 734 'arguments': { 735 0: { 'type': b'@' }, 736 1: { 'type': b'd' }, 737 } 738 }} 739 } 740 }, 741 (b'MyClass3', b'method24', True): { 742 'arguments': { 743 2+1: { 'callable_retained': True, 'callable': { 744 'retval': { 'type': b'v' }, 745 'arguments': { 746 0: { 'type': b'^v' }, 747 1: { 'type': b'@' }, 748 2: { 'type': b'd' }, 749 } 750 }} 751 } 752 }, 753 } 754 755 756 757 all_functions = [ 758 ('function2', b'v', '', { 'variadic': True }), 759 ('function3', b'v', '', { 'variadic': True, 'c_array_delimited_by_null': True }), 760 ('function4', b'v', '', { 'variadic': True, 'c_array_length_in_arg': 4 }), 761 ('function5', b'd', '', { 'retval': { 'type': b'd' }}), 762 ('function6', b'd', '', { 'retval': { 'type': b'd' }}), 763 ('function9', b'd', '', { 'retval': { 'type': b'd' }}), 764 ('function10', b'd', '', { 'retval': { 'type': b'd' }}), 765 ('function11', b'f' if sys.maxsize < 2**32 else b'd' , '', { 'retval': { 'type': b'f' if sys.maxsize < 2**32 else b'd' }}), 766 ('function13', b'i', '', { 'retval': {'type': b'i', 'type_modifier': b'n' }}), 767 ('function14', b':', '', { 'retval': {'type': b':', 'sel_of_type': b'v@:f', 'c_array_of_fixed_length': 4 }}), 768 ('function15', b':', '', { 'retval': {'type': b':', 'sel_of_type': b'v@:f' if sys.maxsize < 2**32 else b'v@:d' }}), 769 ('function16', b'i', '', { 'retval': {'type': b'i', 770 'null_accepted': False, 'already_retained': True, }}), 771 ('function17', b'i', '', { 'retval': {'type': b'i', 772 'already_cfretained': True, 'c_array_delimited_by_null': True, 'c_array_of_variable_length': True, 773 'printf_format': True, 'free_result': True }}), 774 ('function18', b'i', '', { 'retval': { 'type': b'i', 'c_array_length_in_arg': 1 }}), 775 ('function19', b'i', '', { 'retval': { 'type': b'i', 'c_array_length_in_arg': (1,2) }}), 776 ('function20', b'i', '', { 'retval': { 'type': b'i', 'c_array_length_in_arg': (4,5) }}), 777 ('function21', b'?', '', { 'retval': { 'type': b'?', }}), 778 ('function22', b'?', '', { 'retval': { 'type': b'?', 'callable_retained': False, 'callable': { 779 'retval': { 'type': b'v' }, 780 'arguments': { 781 0: { 'type': b'@' }, 782 1: { 'type': b'd' }, 783 } 784 }}}), 785 ('function23', b'@?', '', { 'retval': { 'type': b'@?', 'callable_retained': False, 'callable': { 786 'retval': { 'type': b'v' }, 787 'arguments': { 788 0: { 'type': b'^v' }, 789 1: { 'type': b'@' }, 790 2: { 'type': b'd' }, 791 } 792 }}}), 793 ('function24', b'?', '', { 'retval': { 'type': b'?', 'callable_retained': True, 'callable': { 794 'retval': { 'type': b'v' }, 795 'arguments': { 796 0: { 'type': b'@' }, 797 1: { 'type': b'd' }, 798 } 799 }}}), 800 ('function25', b'@?', '', { 'retval': { 'type': b'@?', 'callable_retained': True, 'callable': { 801 'retval': { 'type': b'v' }, 802 'arguments': { 803 0: { 'type': b'^v' }, 804 1: { 'type': b'@' }, 805 2: { 'type': b'd' }, 806 } 807 }}}), 808 ('function26', b'qfd', '', { 809 'retval': { 'type': b'q' }, 810 'arguments': { 811 0: { 'type': b'f' }, 812 1: { 'type': b'd' } 813 } 814 }), 815 ('function27', b'vdd', '', { 816 'arguments': { 817 0: { 'type': b'd' }, 818 1: { 'type': b'd' } 819 } 820 }), 821 ('function29', b'vd', '', { 822 'arguments': { 823 0: { 'type': b'd' }, 824 } 825 }), 826 ('function30', b'vf' if sys.maxsize < 2**32 else b'vd' , '', { 827 'arguments': { 828 0: { 'type': b'f' if sys.maxsize < 2**32 else b'd' }, 829 } 830 }), 831 ('function32', b'v@', '', { 832 'arguments': { 833 0: { 'type': b'@', 'type_modifier': b'n' } 834 } 835 }), 836 ('function33', b'v:', '', { 837 'arguments': { 838 0: { 'type': b':', 'sel_of_type': b'v@:f', 'c_array_of_fixed_length': 4 } 839 } 840 }), 841 ('function34', b'v:', '', { 842 'arguments': { 843 0: { 'type': b':', 'sel_of_type': b'v@:f' if sys.maxsize < 2**32 else b'v@:d' } 844 } 845 }), 846 ('function35', b'v@', '', { 847 'arguments': { 848 0: { 'type': b'@', 'null_accepted': False, 'already_retained': True, 'c_array_length_in_result': True } 849 } 850 }), 851 ('function36', b'v@', '', { 852 'arguments': { 853 0: { 'type': b'@', 'c_array_delimited_by_null': True, 'already_cfretained': True, 'c_array_of_variable_length': True, 854 'printf_format': True, 'free_result': True } 855 } 856 }), 857 ('function37', b'v@', '', { 858 'arguments': { 859 0: { 'type': b'@', 'c_array_length_in_arg': 1 } 860 } 861 }), 862 ('function38', b'v@', '', { 863 'arguments': { 864 0: { 'type': b'@', 'c_array_length_in_arg': (1,2) } 865 } 866 }), 867 ('function39', b'v@', '', { 868 'arguments': { 869 0: { 'type': b'@', 'c_array_length_in_arg': (4,5) } 870 } 871 }), 872 ('function40', b'v?', '', { 873 'arguments': { 874 0: { 'type': b'?' } 875 } 876 }), 877 ('function41', b'v?', '', { 878 'arguments': { 879 0: { 880 'type': b'?', 881 'callable_retained': False, 882 'callable': { 883 'retval': { 'type': b'v' }, 884 'arguments': { 885 0: { 'type': b'@' }, 886 1: { 'type': b'd' } 887 } 888 } 889 } 890 } 891 }), 892 ('function42', b'v@?', '', { 893 'arguments': { 894 0: { 895 'type': b'@?', 896 'callable_retained': False, 897 'callable': { 898 'retval': { 'type': b'v' }, 899 'arguments': { 900 0: { 'type': b'^v' }, 901 1: { 'type': b'@' }, 902 2: { 'type': b'd' } 903 } 904 } 905 } 906 } 907 }), 908 ('function43', b'v?', '', { 909 'arguments': { 910 0: { 911 'type': b'?', 912 'callable_retained': True, 913 'callable': { 914 'retval': { 'type': b'v' }, 915 'arguments': { 916 0: { 'type': b'@' }, 917 1: { 'type': b'd' } 918 } 919 } 920 } 921 } 922 }), 923 ('function44', b'v@?', '', { 924 'arguments': { 925 0: { 926 'type': b'@?', 927 'callable_retained': True, 928 'callable': { 929 'retval': { 'type': b'v' }, 930 'arguments': { 931 0: { 'type': b'^v' }, 932 1: { 'type': b'@' }, 933 2: { 'type': b'd' } 934 } 935 } 936 } 937 } 938 }), 939 ] 940 941 self.maxDiff = None 942 if sys.maxsize <= 2**32: 943 all_protocols = [ 944 ('protocol2', [ 945 objc.selector(None, b'selector1', b'v@:f' if sys.maxsize < 2**32 else b'v@:d'), 946 objc.selector(None, b'selector2', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d'), 947 objc.selector(None, b'selector3', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d', isClassMethod=True), 948 objc.selector(None, b'selector4', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d'), 949 objc. selector(None, b'selector7', b'v@:f'), 950 objc.selector(None, b'selector8', b'v@:f', isClassMethod=True), 951 ]), 952 ] 953 else: 954 all_protocols = [ 955 ('protocol2', [ 956 objc.selector(None, b'selector1', b'v@:f' if sys.maxsize < 2**32 else b'v@:d'), 957 objc.selector(None, b'selector2', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d'), 958 objc.selector(None, b'selector3', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d', isClassMethod=True), 959 objc.selector(None, b'selector4', b'v@:f' if sys.maxsize < 2 **32 else b'v@:d'), 960 objc.selector(None, b'selector6', b'v@:@'), 961 objc. selector(None, b'selector7', b'v@:f'), 962 objc.selector(None, b'selector8', b'v@:f', isClassMethod=True), 963 ]), 964 ] 965 966 all_structs = [ 967 ('struct3', b'{struct3=@@}', None), 968 ('struct4', b'{struct3=ff}' if sys.maxsize < 2**32 else b'{struct4=dd}', None), 969 ('struct5', b'{struct3=@@}', None), 970 ('struct6', b'{struct6=ZZ}', None), 971 ('struct7', b'{struct7=B@}', None), 972 ('struct8', b'{struct8=@@}', sys.maxsize), 973 ('struct9', b'{struct9=ii}', None), 974 ] 975 976 self.maxDiff = None 977 self.assertItemsEqual(prs.constants, all_constants) 978 self.assertEqual(prs.values, all_values) 979 self.assertItemsEqual(prs.opaque, all_opaque) 980 self.assertItemsEqual(prs.func_aliases, all_func_aliases) 981 self.assertItemsEqual(prs.cftypes, all_cftypes) 982 self.assertItemsEqual(prs.functions, all_functions) 983 self.assertEqual(prs.meta, all_methods) 984 self.assertItemsEqual(prs.informal_protocols, all_protocols) 985 self.assertItemsEqual(prs.structs, all_structs) 986 987 def assertIsIdentifier(self, value): 988 m = IDENTIFIER.match(value) 989 if m is None: 990 self.fail("'%s' is not an identifier"%(value,)) 991 992 993 def assert_valid_callable(self, meta, function): 994 if function: 995 if 'arguments' in meta: 996 indexes = list(sorted(meta["arguments"])) 997 self.assertEqual(indexes, list(range(len(indexes)))) 998 999 valid_keys = { 1000 "type", 1001 "type_modifier", 1002 "already_retained", 1003 "already_cfretained", 1004 "c_array_length_in_result", 1005 "c_array_delimited_by_null", 1006 "printf_format", 1007 "null_accepted", 1008 "c_array_of_variable_length", 1009 "c_array_length_in_arg", 1010 "c_array_of_fixed_length", 1011 "sel_of_type", 1012 "callable", 1013 "callable_retained", 1014 "free_result", 1015 } 1016 1017 if "retval" in meta: 1018 if "type" in meta["retval"]: 1019 self.assertIsInstance(meta["retval"]["type"], bytes) 1020 self.assertEqual(len(objc.splitSignature(meta["retval"]["type"])), 1) 1021 1022 if "type_modifier" in meta["retval"]: 1023 self.assertIsInstance(meta["retval"]["type_modifier"], bytes) 1024 self.assertIn(meta["retval"]["type_modifier"], [b"o", b"n", b"N"]) 1025 1026 if "callable" in meta["retval"]: 1027 self.assert_valid_callable(meta["retval"]["callable"], True) 1028 if "callable_retained" in meta["retval"]: 1029 self.assertIsInstance(meta["retval"]["callable_retained"], bool) 1030 else: 1031 self.assertNotIn("callable_retained", meta["retval"]) 1032 1033 if "sel_of_type" in meta["retval"]: 1034 split = objc.splitSignature(meta["retval"]["sel_of_type"]) 1035 self.assertEqual(split[1], objc._C_ID) 1036 self.assertEqual(split[2], objc._C_SEL) 1037 1038 if "already_retained" in meta["retval"]: 1039 self.assertIsInstance(meta["retval"]["already_retained"], bool) 1040 self.assertNotIn("already_cfretained", meta["retval"]) 1041 1042 if "already_cfretained" in meta["retval"]: 1043 self.assertIsInstance(meta["retval"]["already_cfretained"], bool) 1044 1045 if "free_result" in meta["retval"]: 1046 self.assertIsInstance(meta["retval"]["free_result"], bool) 1047 1048 key = "c_array_of_fixed_length" 1049 if key in meta["retval"]: 1050 self.assertIsInstance(meta["retval"][key], (int, long)) 1051 1052 key = "c_array_length_in_arg" 1053 if key in meta["retval"]: 1054 if isinstance(meta["retval"][key], tuple): 1055 self.assertEqual(len(meta["retval"][key]), 2) 1056 self.assertTrue(all(isinstance(x, (int, long)) for x in meta["retval"][key])) 1057 else: 1058 self.assertIsInstance(meta["retval"][key], (int, long)) 1059 1060 for key in ("c_array_delimited_by_null", "printf_format", "c_array_of_variable_length", "null_accepted"): 1061 if key in meta["retval"]: 1062 self.assertIsInstance(meta["retval"][key], bool) 1063 1064 1065 self.assertNotIn("c_array_length_in_result", meta["retval"]) 1066 self.assertEqual(set(meta["retval"]) - valid_keys, set()) 1067 1068 if 'arguments' in meta: 1069 for idx in meta["arguments"]: 1070 self.assertIsInstance(idx, (int, long)) 1071 arg = meta["arguments"][idx] 1072 1073 if "type" in arg: 1074 self.assertIsInstance(arg["type"], bytes) 1075 self.assertEqual(len(objc.splitSignature(arg["type"])), 1) 1076 1077 if "type_modifier" in arg: 1078 self.assertIsInstance(arg["type_modifier"], bytes) 1079 self.assertIn(arg["type_modifier"], [b"o", b"n", b"N"]) 1080 1081 if "callable" in arg: 1082 self.assert_valid_callable(arg["callable"], True) 1083 if "callable_retained" in arg: 1084 self.assertIsInstance(arg["callable_retained"], bool) 1085 else: 1086 self.assertNotIn("callable_retained", arg) 1087 1088 if "sel_of_type" in arg: 1089 split = objc.splitSignature(arg["sel_of_type"]) 1090 self.assertEqual(split[1], objc._C_ID) 1091 self.assertEqual(split[2], objc._C_SEL) 1092 1093 if "already_retained" in arg: 1094 self.assertIsInstance(arg["already_retained"], bool) 1095 self.assertNotIn("already_cfretained", arg) 1096 1097 if "already_cfretained" in arg: 1098 self.assertIsInstance(arg["already_cfretained"], bool) 1099 1100 if "free_result" in arg: 1101 self.assertIsInstance(arg["free_result"], bool) 1102 1103 if "c_array_of_fixed_length" in arg: 1104 self.assertIsInstance(arg["c_array_of_fixed_length"], (int, long)) 1105 1106 if "c_array_length_in_arg" in arg: 1107 if isinstance(arg["c_array_length_in_arg"], (int, long)): 1108 pass 1109 1110 else: 1111 self.assertIsInstance(arg["c_array_length_in_arg"], tuple) 1112 self.assertEqual(len(arg["c_array_length_in_arg"]), 2) 1113 for x in arg["c_array_length_in_arg"]: 1114 self.assertIsInstance(x, (int, long)) 1115 1116 1117 for key in ("c_array_delimited_by_null", "printf_format", "c_array_of_variable_length", 1118 "null_accepted", "c_array_length_in_result"): 1119 if key in arg: 1120 self.assertIsInstance(arg[key], bool) 1121 1122 self.assertEqual(set(arg) - valid_keys, set()) 1123 1124 if "suggestion" in meta: 1125 self.assertIsInstance(meta["suggestion"], basestring) 1126 1127 if "variadic" in meta: 1128 self.assertIsInstance(meta["variadic"], bool) 1129 1130 if "variadic" in meta and meta["variadic"]: 1131 self.assertEqual(set(meta.keys()) - {"arguments", "retval", "variadic", "classmethod", 1132 "c_array_length_in_arg", "c_array_delimited_by_null", "suggestion"}, set()) 1133 1134 found = False 1135 if "c_array_length_in_arg" in meta: 1136 self.assertIsInstance(meta["c_array_length_in_arg"], (int, long)) 1137 self.assertNotIn("c_array_delimited_by_null", meta) 1138 found = True 1139 1140 if "c_array_delimited_by_null" in meta: 1141 self.assertIsInstance(meta["c_array_delimited_by_null"], bool) 1142 found = False 1143 1144 for idx in meta.get("arguments", {}): 1145 arg = meta["arguments"][idx] 1146 if "printf_format" in arg and arg["printf_format"]: 1147 if found: 1148 self.fail("meta for variadic with two ways to determine size: %s"%(meta,)) 1149 found = True 1150 1151 # NOTE: disabled because having unsupported variadic methods would be fine (e.g. 1152 # metadata says the method is variadic, but it doesn't fall into one of the 1153 # supported categories) 1154 #if not found: 1155 # self.fail("meta for variadic without method for determining size: %s"%(meta,)) 1156 1157 else: 1158 self.assertEqual(set(meta.keys()) - {"arguments", "retval", "variadic", "suggestion", "classmethod" }, set()) 1159 1160 def assert_valid_bridgesupport(self, framework_name, xmldata): 1161 prs = bridgesupport._BridgeSupportParser(xmldata, framework_name) 1162 1163 for item in prs.cftypes: 1164 if len(item) == 3: 1165 name, encoding, typeId = item 1166 tollfreeName = None 1167 1168 elif len(item) == 4: 1169 name, encoding, typeId, tollfreeName = item 1170 self.assertIsNot(tollfreeName, None) 1171 1172 1173 else: 1174 self.fail("Wrong item length in cftypes: %s"%(item,)) 1175 1176 self.assertIsInstance(name, basestring) 1177 self.assertIsInstance(encoding, bytes) 1178 self.assertEqual(len(objc.splitSignature(encoding)), 1) 1179 if tollfreeName is None: 1180 self.assertIsInstance(typeId, (int, long)) 1181 1182 else: 1183 self.assertIs(typeId, None) 1184 self.assertIsInstance(tollfreeName, basestring) 1185 1186 for name, typestr, magic in prs.constants: 1187 self.assertIsInstance(name, basestring) 1188 self.assertIsInstance(typestr, bytes) 1189 self.assertIsInstance(magic, bool) 1190 self.assertEqual(len(objc.splitSignature(typestr)), 1) 1191 1192 for name, orig in prs.func_aliases: 1193 self.assertIsInstance(name, basestring) 1194 self.assertIsInstance(orig, basestring) 1195 self.assertIsIdentifier(name) 1196 1197 for name, encoding, doc, meta in prs.functions: 1198 self.assertIsInstance(name, basestring) 1199 self.assertIsInstance(encoding, bytes) 1200 1201 # check that signature string is well-formed: 1202 objc.splitSignature(encoding) 1203 1204 self.assertEqual(doc, "") 1205 self.assertIsInstance(meta, dict) 1206 self.assert_valid_callable(meta, function=True) 1207 1208 for name, method_list in prs.informal_protocols: 1209 self.assertIsInstance(name, basestring) 1210 self.assertIsInstance(method_list, list) 1211 for sel in method_list: 1212 self.assertIsInstance(sel, objc.selector) 1213 self.assertIs(sel.callable, None) 1214 1215 for clsname, selname, is_class in prs.meta: 1216 meta = prs.meta[(clsname, selname, is_class)] 1217 self.assertIsInstance(clsname, bytes) 1218 self.assertIsInstance(is_class, bool) 1219 self.assertIsInstance(selname, bytes) 1220 self.assertIsInstance(meta, dict) 1221 self.assert_valid_callable(meta, function=False) 1222 1223 for name, typestr in prs.opaque: 1224 self.assertIsInstance(name, basestring) 1225 self.assertIsInstance(typestr, bytes) 1226 1227 self.assertEqual(len(objc.splitSignature(typestr)), 1) 1228 1229 for name, typestr, alias in prs.structs: 1230 self.assertIsInstance(name, basestring) 1231 self.assertIsInstance(typestr, bytes) 1232 self.assertEqual(len(objc.splitSignature(typestr)), 1) 1233 1234 for name in prs.values: 1235 self.assertIsInstance(prs.values[name], (basestring, long, int, float, bytes, type(None))) 1236 1237 return prs 1238 1239class Patcher (object): 1240 def __init__(self): 1241 self._changes = {} 1242 1243 def patch(self, path, value): 1244 if path not in self._changes: 1245 self._changes[path] = self.get(path) 1246 self.set(path, value) 1247 1248 def get(self, path): 1249 module, name = path.rsplit('.', 1) 1250 m = __import__(module) 1251 for p in module.split('.')[1:]: 1252 m = getattr(m, p) 1253 1254 return getattr(m, name) 1255 1256 def set(self, path, value): 1257 module, name = path.rsplit('.', 1) 1258 m = __import__(module) 1259 for p in module.split('.')[1:]: 1260 m = getattr(m, p) 1261 1262 setattr(m, name, value) 1263 1264 def __enter__(self): 1265 return self 1266 1267 def __exit__(self, type, value, tp): 1268 for k in self._changes: 1269 self.set(k, self._changes[k]) 1270 1271class TestParseBridgeSupport (TestCase): 1272 def test_calls(self): 1273 # - Minimal XML with all types of metadata 1274 # - Mock the APIs used by parseBridgeSupport 1275 # (with strict verification of arguments, based on C code) 1276 # - Verify changes to globals where possible 1277 # - Verify 'updatingmetadata' state 1278 1279 class InlineTab (object): pass 1280 def loadConstant(name, typestr, magic): 1281 self.assertIsInstance(name, str) 1282 self.assertIsInstance(typestr, bytes) 1283 self.assertEqual(len(objc.splitSignature(typestr)), 1) 1284 self.assertIsInstance(magic, bool) 1285 1286 if 'raise' in name: 1287 raise AttributeError(name) 1288 1289 return '<constant %r>'%(name,) 1290 1291 SENTINEL=object() 1292 def registerCFSignature(name, encoding, typeId, tollfreeName=SENTINEL): 1293 self.assertIsInstance(name, str) 1294 self.assertIsInstance(encoding, bytes); 1295 self.assertIsInstance(typeId, (int, long, type(None))); 1296 if tollfreeName is not SENTINEL: 1297 self.assertIsInstance(tollfreeName, str) 1298 1299 if typeId is None: 1300 if tollfreeName is SENTINEL: 1301 raise ValueError("Must specify a typeid when not toll-free") 1302 1303 return "<cftype %r>"%(name,) 1304 1305 metadata_registry = {} 1306 def registerMetaDataForSelector(class_, selector, metadata): 1307 self.assertIsInstance(class_, bytes) 1308 self.assertIsInstance(selector, bytes) 1309 self.assertIsInstance(metadata, dict) 1310 1311 # XXX: It might be nice to validate the contents of 1312 # metadata, but that can be added later. 1313 1314 metadata_registry[(class_, selector)] = metadata 1315 1316 def createOpaquePointerType(name, typestr, doc=None): 1317 self.assertIsInstance(name, str) 1318 self.assertIsInstance(typestr, bytes) 1319 self.assertIsInstance(doc, (str, type(None))) 1320 self.assertEqual(len(objc.splitSignature(typestr)), 1) 1321 self.assertTrue(typestr.startswith(objc._C_PTR)) 1322 return '<pointer %r>'%(name,) 1323 1324 def createStructType(name, typestr, fieldnames, doc=None, pack=-1): 1325 self.assertIsInstance(name, str) 1326 self.assertIsInstance(typestr, bytes) 1327 self.assertIsInstance(fieldnames, (list, tuple, type(None))) 1328 self.assertIsInstance(doc, (str, type(None))) 1329 self.assertIsInstance(pack, (int, long)) 1330 self.assertTrue(-1 <= pack <= 32) 1331 if fieldnames is not None: 1332 for nm in fieldnames: 1333 self.assertIsInstance(nm, (str, bytes)) 1334 return '<struct %r>'%(name,) 1335 1336 def createStructAlias(name, typestr, structType): 1337 self.assertIsInstance(name, str) 1338 self.assertIsInstance(typestr, bytes) 1339 1340 def informal_protocol(name, method_list): 1341 self.assertIsInstance(name, str) 1342 for item in method_list: 1343 self.assertIsInstance(item, objc.selector) 1344 self.assertIs(item.callable, None) 1345 1346 return '<informal_protocol %r>'%(name,) 1347 1348 def loadBundleFunctions(bundle, module_globals, functionInfo, skip_undefined=True): 1349 self.assertIs(bundle, None) 1350 self.assertIsInstance(module_globals, dict) 1351 self.assertIsInstance(functionInfo, (list, tuple)) 1352 self.assertIsInstance(skip_undefined, bool) 1353 for item in functionInfo: 1354 self.assertIsInstance(item, (tuple, list)) 1355 self.assertTrue(2 <= len(item) <= 4) 1356 self.assertIsInstance(item[0], str) 1357 self.assertIsInstance(item[1], bytes) 1358 if len(item) > 2: 1359 self.assertIsInstance(item[2], (str, type(None))) 1360 if len(item) > 3: 1361 self.assertIsInstance(item[3], dict) 1362 1363 if 'inline' in item[0]: 1364 continue 1365 1366 module_globals[item[0]] = '<function %r>'%(item[0],) 1367 1368 def loadFunctionList(function_list, module_globals, functionInfo, skip_undefined=True): 1369 self.assertIsInstance(function_list, InlineTab) 1370 self.assertIsInstance(module_globals, dict) 1371 self.assertIsInstance(functionInfo, (list, tuple)) 1372 self.assertIsInstance(skip_undefined, bool) 1373 for item in functionInfo: 1374 self.assertIsInstance(item, (tuple, list)) 1375 self.assertTrue(2 <= len(item) <= 4) 1376 self.assertIsInstance(item[0], str) 1377 self.assertIsInstance(item[1], bytes) 1378 if len(item) > 2: 1379 self.assertIsInstance(item[2], (str, type(None))) 1380 if len(item) > 3: 1381 self.assertIsInstance(item[3], dict) 1382 if item[0] not in module_globals: 1383 module_globals[item[0]] = '<inline_function %r>'%(item[0],) 1384 1385 1386 _meta_updates = [] 1387 def _updatingMetadata(flag): 1388 self.assertIsInstance(flag, bool) 1389 _meta_updates.append(flag) 1390 1391 with Patcher() as p: 1392 p.patch('objc._updatingMetadata', _updatingMetadata) 1393 p.patch('objc._loadConstant', loadConstant) 1394 p.patch('objc.registerCFSignature', registerCFSignature) 1395 p.patch('objc.registerMetaDataForSelector', registerMetaDataForSelector) 1396 p.patch('objc.createOpaquePointerType', createOpaquePointerType) 1397 p.patch('objc.createStructType', createStructType) 1398 p.patch('objc.createStructAlias', createStructAlias) 1399 p.patch('objc.informal_protocol', informal_protocol) 1400 p.patch('objc.loadBundleFunctions', loadBundleFunctions) 1401 p.patch('objc.loadFunctionList', loadFunctionList) 1402 p.patch('sys.modules', sys.modules.copy()) 1403 1404 # 1. Empty metadata 1405 _meta_updates = [] 1406 metadata_registry = {} 1407 module_globals = {} 1408 1409 objc.parseBridgeSupport(b'''\ 1410 <signatures> 1411 </signatures> 1412 ''', module_globals, 'TestFramework') 1413 1414 self.assertEqual(_meta_updates, [True, False]) 1415 self.assertEqual(metadata_registry, {}) 1416 self.assertEqual(module_globals, {}) 1417 1418 # 2. Various metadata 1419 _meta_updates = [] 1420 metadata_registry = {} 1421 module_globals = {} 1422 orig_libraries = list(bridgesupport._libraries) 1423 1424 xml = b'''\ 1425 <signatures> 1426 <opaque name='opaque_type' type='^{opaque}'/> 1427 <struct name='OCPoint' type='{OCPoint=dd}' /> 1428 <struct name='OCPoint2' type='{OCPoint2=dd}' alias='distutils.sysconfig.get_config_var'/> 1429 <enum name='enum_value' value='42' /> 1430 <constant name='const_value' type='@' /> 1431 <constant name='const_raise' type='@' /> 1432 <cftype name='cftype_value' type='^{cftype}' /> 1433 <class name='class1'> 1434 <method selector='sel1:' class_method='false'> 1435 <arg index='0' null_accepted='false' type_modifier='o' /> 1436 </method> 1437 </class> 1438 <function name='function1'> 1439 <retval type='f' /> 1440 <arg type='@' /> 1441 <arg type='d' /> 1442 </function> 1443 <function name='function2'> 1444 <retval type='d' /> 1445 <arg type='d' /> 1446 </function> 1447 <function name='inline_function'> 1448 <retval type='i' /> 1449 </function> 1450 <function_pointer name='function3' original='function2'/> 1451 <function_pointer name='function4' original='no_such_function'/> 1452 <informal_protocol name='protocol1'> 1453 <method selector='sel1:' type='v@:@' /> 1454 </informal_protocol> 1455 <informal_protocol name='protocol2'> 1456 <method selector='sel2:' type='v@:@' /> 1457 </informal_protocol> 1458 </signatures> 1459 ''' 1460 objc.parseBridgeSupport(xml, module_globals, 'TestFramework') 1461 1462 self.assertEqual(_meta_updates, [True, False]) 1463 self.assertEqual(metadata_registry, { 1464 (b'class1', b'sel1:'): { 1465 'arguments': { 1466 2: { 'null_accepted': False, 'type_modifier': b'o' } 1467 } 1468 }, 1469 }) 1470 1471 from distutils.sysconfig import get_config_var 1472 1473 self.assertIn('protocols', module_globals) 1474 m = module_globals.pop('protocols') 1475 self.assertIsInstance(m, type(objc)) 1476 self.assertEqual(m.__name__, 'TestFramework.protocols') 1477 self.assertEqual(m.protocol1, "<informal_protocol 'protocol1'>") 1478 self.assertEqual(m.protocol2, "<informal_protocol 'protocol2'>") 1479 self.assertIs(sys.modules['TestFramework.protocols'], m) 1480 self.assertEqual(module_globals, { 1481 "enum_value": 42, 1482 "const_value": "<constant 'const_value'>", 1483 "cftype_value": "<cftype 'cftype_value'>", 1484 "function1": "<function 'function1'>", 1485 "function2": "<function 'function2'>", 1486 "function3": "<function 'function2'>", 1487 "OCPoint": "<struct 'OCPoint'>", 1488 "OCPoint2": get_config_var, 1489 "opaque_type": "<pointer 'opaque_type'>", 1490 }) 1491 self.assertEqual(orig_libraries, bridgesupport._libraries) 1492 1493 # 3. inlineTab 1494 _meta_updates = [] 1495 metadata_registry = {} 1496 module_globals = {} 1497 orig_libraries = list(bridgesupport._libraries) 1498 1499 xml = b'''\ 1500 <signatures> 1501 <function name='function1'> 1502 <retval type='f' /> 1503 <arg type='@' /> 1504 <arg type='d' /> 1505 </function> 1506 <function name='function2'> 1507 <retval type='d' /> 1508 <arg type='d' /> 1509 </function> 1510 <function name='inline_function_name'> 1511 <retval type='i' /> 1512 </function> 1513 </signatures> 1514 ''' 1515 objc.parseBridgeSupport(xml, module_globals, 'TestFramework2', inlineTab=InlineTab()) 1516 1517 self.assertEqual(_meta_updates, [True, False]) 1518 self.assertEqual(metadata_registry, {}) 1519 self.assertNotIn('protocols', module_globals) 1520 self.assertNotIn('TestFramework2.protocols', sys.modules) 1521 self.assertEqual(module_globals, { 1522 "function1": "<function 'function1'>", 1523 "function2": "<function 'function2'>", 1524 "inline_function_name": "<inline_function 'inline_function_name'>", 1525 }) 1526 self.assertEqual(orig_libraries, bridgesupport._libraries) 1527 1528 # 4. dylib usage 1529 _meta_updates = [] 1530 metadata_registry = {} 1531 module_globals = {} 1532 orig_libraries = list(bridgesupport._libraries) 1533 1534 xml = b'''\ 1535 <signatures> 1536 <function name='function1'> 1537 <retval type='f' /> 1538 <arg type='@' /> 1539 <arg type='d' /> 1540 </function> 1541 <function name='function2'> 1542 <retval type='d' /> 1543 <arg type='d' /> 1544 </function> 1545 <function name='inline_function_name'> 1546 <retval type='i' /> 1547 </function> 1548 </signatures> 1549 ''' 1550 objc.parseBridgeSupport(xml, module_globals, 'TestFramework2', dylib_path='/usr/lib/libxml2.dylib') 1551 1552 self.assertEqual(_meta_updates, [True, False]) 1553 self.assertEqual(metadata_registry, {}) 1554 self.assertNotIn('protocols', module_globals) 1555 self.assertNotIn('TestFramework2.protocols', sys.modules) 1556 self.assertEqual(module_globals, { 1557 "function1": "<function 'function1'>", 1558 "function2": "<function 'function2'>", 1559 }) 1560 self.assertEqual(len(orig_libraries)+1, len(bridgesupport._libraries)) 1561 self.assertIsInstance(bridgesupport._libraries[-1], ctypes.CDLL) 1562 self.assertEqual(bridgesupport._libraries[-1]._name, '/usr/lib/libxml2.dylib') 1563 1564 1565 1566class TestInitFrameworkWrapper (TestCase): 1567 def test_calls_parse_helper(self): 1568 # Test functionality of initFrameworkWrapper and _parseBridgeSupport 1569 # by mocking 'parseBridgeSupport' (and the location of the caller) 1570 with Patcher() as p: 1571 calls = [] 1572 raise_exception = None 1573 update_globals = None 1574 1575 def parseBridgeSupport(xmldata, globals, frameworkName, dylib_path=None, inlineTab=None): 1576 calls.append((xmldata, globals, frameworkName, dylib_path, inlineTab)) 1577 if update_globals is not None: 1578 globals.update(update_globals) 1579 1580 if raise_exception is not None: 1581 raise raise_exception() 1582 1583 class MockModule (object): 1584 pass 1585 1586 1587 p.patch('objc.parseBridgeSupport', parseBridgeSupport) 1588 1589 1590 # 1. Verify that failures to load bridgesupport emit a warning 1591 calls = [] 1592 raise_exception = objc.internal_error 1593 update_globals = None 1594 1595 with filterWarnings("error", RuntimeWarning): 1596 self.assertRaises(RuntimeWarning, bridgesupport._parseBridgeSupport, '', {}, 'TestFramework') 1597 1598 calls = [] 1599 1600 with filterWarnings("ignore", RuntimeWarning): 1601 g = {} 1602 update_globals = {'foo': 42, 'bar': 33, 'protocols': MockModule() } 1603 bridgesupport._parseBridgeSupport('', g, 'TestFramework') 1604 self.assertEqual(g, update_globals) 1605 self.assertEqual(calls, [('', g, 'TestFramework', None, None)]) 1606 1607 self.assertNotEqual(len(g['protocols'].__dict__), 0) 1608 for v in g['protocols'].__dict__.values(): 1609 self.assertIsInstance(v, objc.formal_protocol) 1610 1611 1612 # 2. Run without problems, without 'protocols' in dictionary 1613 raise_exception = None 1614 update_globals = {'foo': 42, 'bar': 33, } 1615 1616 calls = [] 1617 g = {} 1618 bridgesupport._parseBridgeSupport('', g, 'TestFramework', 'a', 'b') 1619 self.assertEqual(g, update_globals) 1620 self.assertEqual(calls, [('', g, 'TestFramework', 'a', 'b')]) 1621 self.assertNotIn('protocols', g) 1622 1623 calls = [] 1624 g = {} 1625 bridgesupport._parseBridgeSupport('', g, 'TestFramework', inlineTab='a') 1626 self.assertEqual(g, update_globals) 1627 self.assertEqual(calls, [('', g, 'TestFramework', None, 'a')]) 1628 self.assertNotIn('protocols', g) 1629 1630 # 3. Run witout problems, with 'protocols' in dictionary 1631 calls = [] 1632 raise_exception = None 1633 update_globals = {'foo': 42, 'bar': 33, 'protocols': MockModule() } 1634 1635 g = {} 1636 bridgesupport._parseBridgeSupport('', g, 'TestFramework', 'a', 'b') 1637 self.assertEqual(g, update_globals) 1638 self.assertEqual(calls, [('', g, 'TestFramework', 'a', 'b')]) 1639 self.assertNotEqual(len(g['protocols'].__dict__), 0) 1640 for v in g['protocols'].__dict__.values(): 1641 self.assertIsInstance(v, objc.formal_protocol) 1642 1643 calls = [] 1644 g = {} 1645 bridgesupport._parseBridgeSupport('', g, 'TestFramework', inlineTab='a') 1646 self.assertEqual(g, update_globals) 1647 self.assertEqual(calls, [('', g, 'TestFramework', None, 'a')]) 1648 self.assertNotEqual(len(g['protocols'].__dict__), 0) 1649 for v in g['protocols'].__dict__.values(): 1650 self.assertIsInstance(v, objc.formal_protocol) 1651 1652 1653 def test_calls_initwrappper(self): 1654 with Patcher() as p: 1655 1656 SENTINEL=object() 1657 1658 class InlineTab (object): pass 1659 1660 bundle_resources = {} 1661 class Bundle (object): 1662 def __init__(self, calls=None): 1663 if calls is None: 1664 calls = [] 1665 self.calls = calls 1666 1667 def pathForResource_ofType_inDirectory_(self, name, type, directory): 1668 self.calls.append((name, type, directory)) 1669 return bundle_resources.get((name, type), None) 1670 1671 def __eq__(self, other): 1672 if type(self) is not type(other): 1673 return False 1674 1675 return self.calls == other.calls 1676 1677 def __repr__(self): 1678 return '<Bundle calls=%r>'%(self.calls,) 1679 1680 1681 load_calls = [] 1682 bundle_exception = None 1683 def loadBundle(module_name, module_globals, bundle_path=SENTINEL, bundle_identifier=SENTINEL, scan_classes=True): 1684 if bundle_exception is not None: 1685 bundle_exception(module_name, bundle_path, bundle_identifier) 1686 self.assertIsInstance(module_name, str) 1687 self.assertIsInstance(module_globals, dict) 1688 if bundle_path is not SENTINEL: 1689 self.assertIsInstance(bundle_path, str) 1690 if bundle_identifier is not SENTINEL: 1691 self.assertIsInstance(bundle_identifier, str) 1692 bool(scan_classes) 1693 bundle = Bundle() 1694 load_calls.append((bundle, module_name, module_globals, bundle_path, bundle_identifier, scan_classes)) 1695 return bundle 1696 1697 resources = {} 1698 def resource_exists(package, name): 1699 return (package, name) in resources 1700 1701 def resource_string(package, name): 1702 return resources[(package, name)] 1703 1704 parse_calls = [] 1705 def parseBridgeSupport(xml, globals, framework, dylib_path=None, inlineTab=None): 1706 parse_calls.append((xml, globals, framework, dylib_path, inlineTab)) 1707 1708 TEST_BRIDGESUPPORT_DIRECTORIES=[] 1709 1710 p.patch("objc.loadBundle", loadBundle) 1711 p.patch("pkg_resources.resource_exists", resource_exists) 1712 p.patch("pkg_resources.resource_string", resource_string) 1713 p.patch("objc._bridgesupport._parseBridgeSupport", parseBridgeSupport) 1714 p.patch("objc._bridgesupport.BRIDGESUPPORT_DIRECTORIES", TEST_BRIDGESUPPORT_DIRECTORIES) 1715 1716 helper_dir = os.path.join(os.path.dirname(__file__), 'data_bridgesupport') 1717 1718 1719 # 1. No resource files, no bundle files, no library files 1720 resources = {} 1721 bundle_resources = {} 1722 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'empty') ] 1723 1724 def basic_verify(g): 1725 self.assertIs(g['objc'], objc) 1726 self.assertIs(g['super'], objc.super) 1727 1728 load_calls = [] 1729 parse_calls = [] 1730 g = {} 1731 objc.initFrameworkWrapper("TestFramework", "/Library/Framework/Test.framework", "com.apple.Test", g) 1732 basic_verify(g) 1733 self.assertEqual(len(g), 2) 1734 self.assertEqual(load_calls, [ 1735 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, SENTINEL, 'com.apple.Test', True) 1736 ]) 1737 self.assertEqual(parse_calls, []) 1738 1739 load_calls = [] 1740 parse_calls = [] 1741 g = {} 1742 objc.initFrameworkWrapper("TestFramework", "/Library/Framework/Test.framework", None, g) 1743 basic_verify(g) 1744 self.assertEqual(len(g), 2) 1745 self.assertEqual(load_calls, [ 1746 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, '/Library/Framework/Test.framework', SENTINEL, True) 1747 ]) 1748 self.assertEqual(parse_calls, []) 1749 1750 load_calls = [] 1751 parse_calls = [] 1752 g = {} 1753 objc.initFrameworkWrapper("TestFramework", "/Library/Framework/Test.framework", None, g, scan_classes=False) 1754 basic_verify(g) 1755 self.assertEqual(len(g), 2) 1756 self.assertEqual(load_calls, [ 1757 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, '/Library/Framework/Test.framework', SENTINEL, False) 1758 ]) 1759 self.assertEqual(parse_calls, []) 1760 1761 load_calls = [] 1762 parse_calls = [] 1763 g = {} 1764 objc.initFrameworkWrapper("TestFramework", None, "com.apple.Test", g) 1765 basic_verify(g) 1766 self.assertEqual(len(g), 2) 1767 self.assertEqual(load_calls, [ 1768 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, SENTINEL, 'com.apple.Test', True) 1769 ]) 1770 self.assertEqual(parse_calls, []) 1771 1772 load_calls = [] 1773 parse_calls = [] 1774 g = {} 1775 objc.initFrameworkWrapper("TestFramework", None, "com.apple.Test", g, scan_classes=False) 1776 basic_verify(g) 1777 self.assertEqual(len(g), 2) 1778 self.assertEqual(load_calls, [ 1779 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, SENTINEL, 'com.apple.Test', False) 1780 ]) 1781 self.assertEqual(parse_calls, []) 1782 1783 1784 load_calls = [] 1785 parse_calls = [] 1786 g = {} 1787 objc.initFrameworkWrapper("TestFramework", "/Library/Framework/Test.framework", "com.apple.Test", g, inlineTab=InlineTab()) 1788 basic_verify(g) 1789 self.assertEqual(len(g), 2) 1790 self.assertEqual(load_calls, [ 1791 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, SENTINEL, 'com.apple.Test', True) 1792 ]) 1793 self.assertEqual(parse_calls, []) 1794 1795 load_calls = [] 1796 parse_calls = [] 1797 g = {} 1798 objc.initFrameworkWrapper("TestFramework", "/Library/Framework/Test.framework", "com.apple.Test", g, 1799 inlineTab=InlineTab(), scan_classes=False) 1800 basic_verify(g) 1801 self.assertEqual(len(g), 2) 1802 self.assertEqual(load_calls, [ 1803 (Bundle([('TestFramework', 'bridgesupport', 'BridgeSupport')]), 'TestFramework', g, SENTINEL, 'com.apple.Test', False) 1804 ]) 1805 self.assertEqual(parse_calls, []) 1806 1807 1808 # 2. Have resource files, bundle files and library files (only first is used) 1809 resources = { 1810 ('Test', 'PyObjC.bridgesupport'): b"<signatures><constant name='test resource' type='@' /></signatures>", 1811 } 1812 bundle_resources = { 1813 'Test': os.path.join(helper_dir, 'bundle_data', 'Test.bridgesupport'), 1814 } 1815 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1816 1817 load_calls = [] 1818 parse_calls = [] 1819 g = {} 1820 inlineTab = InlineTab() 1821 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1822 inlineTab=inlineTab, scan_classes=False) 1823 basic_verify(g) 1824 self.assertEqual(len(g), 2) 1825 self.assertEqual(load_calls, [ 1826 (Bundle([]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1827 ]) 1828 self.assertEqual(parse_calls, [ 1829 (b"<signatures><constant name='test resource' type='@' /></signatures>", g, 'Test', None, inlineTab) 1830 ]) 1831 1832 # 3. No resource files, have bundle files and library files (only bundle one is used) 1833 resources = { 1834 } 1835 bundle_resources = { 1836 ('Test', 'bridgesupport'): os.path.join(helper_dir, 'bundle_data', 'Test.bridgesupport'), 1837 } 1838 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1839 1840 load_calls = [] 1841 parse_calls = [] 1842 g = {} 1843 inlineTab = InlineTab() 1844 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1845 inlineTab=inlineTab, scan_classes=False) 1846 basic_verify(g) 1847 self.assertEqual(len(g), 2) 1848 self.assertEqual(load_calls, [ 1849 (Bundle([('Test', 'bridgesupport', 'BridgeSupport'), ('Test', 'dylib', 'BridgeSupport')]), 1850 'Test', g, SENTINEL, 'com.apple.Test', False) 1851 ]) 1852 self.assertEqual(parse_calls, [ 1853 (b"<signatures><constant name='bundle.test' type='@'/></signatures>\n", g, 'Test', None, None) 1854 ]) 1855 1856 # 4. No resource files, have bundle files (with override) and library files (only bundle one is used) 1857 resources = { 1858 ('Test', 'PyObjCOverrides.bridgesupport'): b"<signatures><constant name='test override' type='@' /></signatures>", 1859 } 1860 bundle_resources = { 1861 ('Test', 'bridgesupport'): os.path.join(helper_dir, 'bundle_data', 'Test.bridgesupport'), 1862 } 1863 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1864 1865 load_calls = [] 1866 parse_calls = [] 1867 g = {} 1868 inlineTab = InlineTab() 1869 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1870 inlineTab=inlineTab, scan_classes=False) 1871 basic_verify(g) 1872 self.assertEqual(len(g), 2) 1873 self.assertEqual(load_calls, [ 1874 (Bundle([('Test', 'bridgesupport', 'BridgeSupport'), ('Test', 'dylib', 'BridgeSupport')]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1875 ]) 1876 self.assertEqual(parse_calls, [ 1877 (b"<signatures><constant name='bundle.test' type='@'/></signatures>\n", g, 'Test', None, None), 1878 (b"<signatures><constant name='test override' type='@' /></signatures>", g, 'Test', None, inlineTab), 1879 ]) 1880 1881 resources = { 1882 ('Test', 'PyObjCOverrides.bridgesupport'): b"<signatures><constant name='test override' type='@' /></signatures>", 1883 } 1884 bundle_resources = { 1885 ('Test', 'bridgesupport'): os.path.join(helper_dir, 'bundle_data', 'Test.bridgesupport'), 1886 ('Test', 'dylib'): os.path.join(helper_dir, 'bundle_data', 'Test.dylib'), 1887 } 1888 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1889 1890 load_calls = [] 1891 parse_calls = [] 1892 g = {} 1893 inlineTab = InlineTab() 1894 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1895 inlineTab=inlineTab, scan_classes=False) 1896 basic_verify(g) 1897 self.assertEqual(len(g), 2) 1898 self.assertEqual(load_calls, [ 1899 (Bundle([('Test', 'bridgesupport', 'BridgeSupport'), ('Test', 'dylib', 'BridgeSupport')]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1900 ]) 1901 self.assertEqual(parse_calls, [ 1902 (b"<signatures><constant name='bundle.test' type='@'/></signatures>\n", g, 'Test', os.path.join(helper_dir, 'bundle_data', 'Test.dylib'), None), 1903 (b"<signatures><constant name='test override' type='@' /></signatures>", g, 'Test', None, inlineTab), 1904 ]) 1905 1906 # 5. No resource file, no bundle file, have library file 1907 resources = {} 1908 bundle_resources = {} 1909 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1910 1911 load_calls = [] 1912 parse_calls = [] 1913 g = {} 1914 inlineTab = InlineTab() 1915 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1916 inlineTab=inlineTab, scan_classes=False) 1917 basic_verify(g) 1918 self.assertEqual(len(g), 2) 1919 self.assertEqual(load_calls, [ 1920 (Bundle([('Test', 'bridgesupport', 'BridgeSupport')]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1921 ]) 1922 self.assertEqual(parse_calls, [ 1923 (b'<signatures version=\'1\'><string_constant name="info" value="system test.bridgesupport" /></signatures>\n', g, 'Test', None, None) 1924 ]) 1925 1926 resources = {} 1927 bundle_resources = {} 1928 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data_dylib') ] 1929 1930 load_calls = [] 1931 parse_calls = [] 1932 g = {} 1933 inlineTab = InlineTab() 1934 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1935 inlineTab=inlineTab, scan_classes=False) 1936 basic_verify(g) 1937 self.assertEqual(len(g), 2) 1938 self.assertEqual(load_calls, [ 1939 (Bundle([('Test', 'bridgesupport', 'BridgeSupport')]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1940 ]) 1941 self.assertEqual(parse_calls, [ 1942 (b'<signatures version=\'1\'><string_constant name="info" value="system test.bridgesupport 2" /></signatures>\n', g, 'Test', os.path.join(helper_dir, 'with_data_dylib', 'Test.dylib'), None) 1943 ]) 1944 1945 # 6. No resource file, no bundle file, have library file (with override) 1946 resources = { 1947 ('Test', 'PyObjCOverrides.bridgesupport'): b'<signatures><contant name="override" type="@"></signatures>', 1948 } 1949 bundle_resources = {} 1950 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [ os.path.join(helper_dir, 'with_data') ] 1951 1952 load_calls = [] 1953 parse_calls = [] 1954 g = {} 1955 inlineTab = InlineTab() 1956 objc.initFrameworkWrapper("Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1957 inlineTab=inlineTab, scan_classes=False) 1958 basic_verify(g) 1959 self.assertEqual(len(g), 2) 1960 self.assertEqual(load_calls, [ 1961 (Bundle([('Test', 'bridgesupport', 'BridgeSupport')]), 'Test', g, SENTINEL, 'com.apple.Test', False) 1962 ]) 1963 self.assertEqual(parse_calls, [ 1964 (b'<signatures version=\'1\'><string_constant name="info" value="system test.bridgesupport" /></signatures>\n', g, 'Test', None, None), 1965 (b'<signatures><contant name="override" type="@"></signatures>', g, 'Test', None, inlineTab) 1966 ]) 1967 1968 # 7. Cannot load bundle (should not look for bridgesupport) 1969 load_calls = [] 1970 parse_calls = [] 1971 g = {} 1972 inlineTab = InlineTab() 1973 def bundle_exception(name, path, identifier): 1974 raise ImportError(name) 1975 1976 self.assertRaises(ImportError, objc.initFrameworkWrapper, 1977 "Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1978 inlineTab=inlineTab, scan_classes=False) 1979 1980 self.assertEquals(load_calls, []) 1981 self.assertEquals(parse_calls, []) 1982 self.assertEquals(g, {}) 1983 1984 # 8. framework_identifier is not None, cannot find through identifier 1985 resources = {} 1986 bundle_resources = {} 1987 TEST_BRIDGESUPPORT_DIRECTORIES[:] = [] 1988 1989 load_calls = [] 1990 parse_calls = [] 1991 g = {} 1992 inlineTab = InlineTab() 1993 def bundle_exception(name, path, identifier): 1994 if identifier is not SENTINEL: 1995 raise ImportError(name) 1996 1997 objc.initFrameworkWrapper( 1998 "Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 1999 inlineTab=inlineTab, scan_classes=False) 2000 2001 self.assertEquals(load_calls, [ 2002 (Bundle(calls=[('Test', 'bridgesupport', 'BridgeSupport')]), 'Test', g, '/Library/Framework/Test.framework', SENTINEL, False), 2003 ]) 2004 self.assertEquals(parse_calls, []) 2005 2006 load_calls = [] 2007 parse_calls = [] 2008 g = {} 2009 inlineTab = InlineTab() 2010 def bundle_exception(name, path, identifier): 2011 if identifier is not SENTINEL: 2012 raise ImportError(name) 2013 2014 objc.initFrameworkWrapper( 2015 "Test", "/Library/Framework/Test.framework", "com.apple.Test", g, 2016 inlineTab=inlineTab) 2017 2018 self.assertEquals(load_calls, [ 2019 (Bundle(calls=[('Test', 'bridgesupport', 'BridgeSupport')]), 'Test', g, '/Library/Framework/Test.framework', SENTINEL, True), 2020 ]) 2021 self.assertEquals(parse_calls, []) 2022 2023 2024 # XXX: The following path's aren't properly tested at the moment: 2025 # 8. Use the 'frameworkResourceName' parameter 2026 2027 2028 def test_safe_resource_exists(self): 2029 with Patcher() as p: 2030 return_value = False 2031 exception = None 2032 2033 def resource_exists(resource, path): 2034 if exception: raise exception 2035 return return_value 2036 p.patch("pkg_resources.resource_exists", resource_exists) 2037 2038 return_value = False 2039 exception = None 2040 self.assertEquals(bridgesupport.safe_resource_exists("a", "b"), False) 2041 2042 return_value = True 2043 exception = None 2044 self.assertEquals(bridgesupport.safe_resource_exists("a", "b"), True) 2045 2046 return_value = True 2047 exception = ImportError 2048 self.assertEquals(bridgesupport.safe_resource_exists("a", "b"), False) 2049 2050 2051 def test_real_loader(self): 2052 script = os.path.join(os.path.dirname(__file__), 'helper_bridgesupport.py') 2053 path_elem = os.path.dirname(objc.__file__) 2054 2055 if sys.byteorder == 'big': 2056 if sys.maxsize < 2**32: 2057 arch = '-ppc' 2058 else: 2059 arch = '-ppc64' 2060 2061 else: 2062 if sys.maxsize < 2**32: 2063 arch = '-i386' 2064 else: 2065 arch = '-x86_64' 2066 2067 return # XXX 2068 p = subprocess.Popen([ 2069 '/usr/bin/arch', arch, 2070 sys.executable, script, path_elem], stdout=subprocess.PIPE) 2071 stdout, _ = p.communicate() 2072 if p.returncode != 0: 2073 self.fail("Selftest failed: %r" % stdout) 2074 2075class TestMisc (TestCase): 2076 def test_struct_alias(self): 2077 tp1 = objc.createStructType('TestStruct1', b'{TestStruct1="f1"d"f2"d}', None) 2078 2079 with filterWarnings("error", DeprecationWarning): 2080 self.assertRaises(DeprecationWarning, objc.registerStructAlias, b'{TestStruct2=dd}', tp1) 2081 2082 with filterWarnings("ignore", DeprecationWarning): 2083 tp2 = objc.registerStructAlias(b'{TestStruct2=dd}', tp1) 2084 self.assertIs(tp1, tp2) 2085 2086 self.assertHasAttr(objc.ivar, 'TestStruct1') 2087 self.assertNotHasAttr(objc.ivar, 'TestStruct2') 2088 2089 tp3 = objc.createStructAlias('TestStruct3', b'{TestStruct3=dd}', tp1) 2090 self.assertIs(tp1, tp3) 2091 self.assertHasAttr(objc.ivar, 'TestStruct3') 2092 2093 2094if __name__ == "__main__": 2095 main() 2096