test_nullable_equivalency.py (4191B)
1 import WebIDL 2 3 4 def WebIDLTest(parser, harness): 5 parser.parse( 6 """ 7 interface TestNullableEquivalency1 { 8 attribute long a; 9 attribute long? b; 10 }; 11 12 interface TestNullableEquivalency2 { 13 attribute ArrayBuffer a; 14 attribute ArrayBuffer? b; 15 }; 16 17 /* Can't have dictionary-valued attributes, so can't test that here */ 18 19 enum TestNullableEquivalency4Enum { 20 "Foo", 21 "Bar" 22 }; 23 24 interface TestNullableEquivalency4 { 25 attribute TestNullableEquivalency4Enum a; 26 attribute TestNullableEquivalency4Enum? b; 27 }; 28 29 interface TestNullableEquivalency5 { 30 attribute TestNullableEquivalency4 a; 31 attribute TestNullableEquivalency4? b; 32 }; 33 34 interface TestNullableEquivalency6 { 35 attribute boolean a; 36 attribute boolean? b; 37 }; 38 39 interface TestNullableEquivalency7 { 40 attribute DOMString a; 41 attribute DOMString? b; 42 }; 43 44 interface TestNullableEquivalency8 { 45 attribute float a; 46 attribute float? b; 47 }; 48 49 interface TestNullableEquivalency9 { 50 attribute double a; 51 attribute double? b; 52 }; 53 54 interface TestNullableEquivalency10 { 55 attribute object a; 56 attribute object? b; 57 }; 58 """ 59 ) 60 61 for decl in parser.finish(): 62 if decl.isInterface(): 63 checkEquivalent(decl, harness) 64 65 66 def checkEquivalent(iface, harness): 67 type1 = iface.members[0].type 68 type2 = iface.members[1].type 69 70 harness.check(type1.nullable(), False, "attr1 should not be nullable") 71 harness.check(type2.nullable(), True, "attr2 should be nullable") 72 73 # We don't know about type1, but type2, the nullable type, definitely 74 # shouldn't be builtin. 75 harness.check(type2.builtin, False, "attr2 should not be builtin") 76 77 # Ensure that all attributes of type2 match those in type1, except for: 78 # - names on an ignore list, 79 # - names beginning with '_', 80 # - functions which throw when called with no args, and 81 # - class-level non-callables ("static variables"). 82 # 83 # Yes, this is an ugly, fragile hack. But it finds bugs... 84 for attr in dir(type1): 85 if ( 86 attr.startswith("_") 87 or attr 88 in [ 89 "nullable", 90 "builtin", 91 "filename", 92 "location", 93 "inner", 94 "QName", 95 "getDeps", 96 "name", 97 "prettyName", 98 ] 99 or (hasattr(type(type1), attr) and not callable(getattr(type1, attr))) 100 ): 101 continue 102 103 a1 = getattr(type1, attr) 104 105 if callable(a1): 106 try: 107 v1 = a1() 108 except AssertionError: 109 # Various methods assert that they're called on objects of 110 # the right type, skip them if the assert fails. 111 continue 112 except TypeError: 113 # a1 requires positional arguments, so skip this attribute. 114 continue 115 116 try: 117 a2 = getattr(type2, attr) 118 except WebIDL.WebIDLError: 119 harness.ok( 120 False, 121 "Missing %s attribute on type %s in %s" % (attr, type2, iface), 122 ) 123 continue 124 125 if not callable(a2): 126 harness.ok( 127 False, 128 "%s attribute on type %s in %s wasn't callable" 129 % (attr, type2, iface), 130 ) 131 continue 132 133 v2 = a2() 134 harness.check(v2, v1, "%s method return value" % attr) 135 else: 136 try: 137 a2 = getattr(type2, attr) 138 except WebIDL.WebIDLError: 139 harness.ok( 140 False, 141 "Missing %s attribute on type %s in %s" % (attr, type2, iface), 142 ) 143 continue 144 145 harness.check(a2, a1, "%s attribute should match" % attr)