1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/parser/tests/test_distinguishability.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,276 @@ 1.4 +def firstArgType(method): 1.5 + return method.signatures()[0][1][0].type 1.6 + 1.7 +def WebIDLTest(parser, harness): 1.8 + parser.parse(""" 1.9 + dictionary Dict { 1.10 + }; 1.11 + callback interface Foo { 1.12 + }; 1.13 + interface Bar { 1.14 + // Bit of a pain to get things that have dictionary types 1.15 + void passDict(optional Dict arg); 1.16 + void passFoo(Foo arg); 1.17 + void passNullableUnion((object? or DOMString) arg); 1.18 + void passNullable(Foo? arg); 1.19 + }; 1.20 + """) 1.21 + results = parser.finish() 1.22 + 1.23 + iface = results[2] 1.24 + harness.ok(iface.isInterface(), "Should have interface") 1.25 + dictMethod = iface.members[0] 1.26 + ifaceMethod = iface.members[1] 1.27 + nullableUnionMethod = iface.members[2] 1.28 + nullableIfaceMethod = iface.members[3] 1.29 + 1.30 + dictType = firstArgType(dictMethod) 1.31 + ifaceType = firstArgType(ifaceMethod) 1.32 + 1.33 + harness.ok(dictType.isDictionary(), "Should have dictionary type"); 1.34 + harness.ok(ifaceType.isInterface(), "Should have interface type"); 1.35 + harness.ok(ifaceType.isCallbackInterface(), "Should have callback interface type"); 1.36 + 1.37 + harness.ok(not dictType.isDistinguishableFrom(ifaceType), 1.38 + "Dictionary not distinguishable from callback interface") 1.39 + harness.ok(not ifaceType.isDistinguishableFrom(dictType), 1.40 + "Callback interface not distinguishable from dictionary") 1.41 + 1.42 + nullableUnionType = firstArgType(nullableUnionMethod) 1.43 + nullableIfaceType = firstArgType(nullableIfaceMethod) 1.44 + 1.45 + harness.ok(nullableUnionType.isUnion(), "Should have union type"); 1.46 + harness.ok(nullableIfaceType.isInterface(), "Should have interface type"); 1.47 + harness.ok(nullableIfaceType.nullable(), "Should have nullable type"); 1.48 + 1.49 + harness.ok(not nullableUnionType.isDistinguishableFrom(nullableIfaceType), 1.50 + "Nullable type not distinguishable from union with nullable " 1.51 + "member type") 1.52 + harness.ok(not nullableIfaceType.isDistinguishableFrom(nullableUnionType), 1.53 + "Union with nullable member type not distinguishable from " 1.54 + "nullable type") 1.55 + 1.56 + parser = parser.reset() 1.57 + parser.parse(""" 1.58 + interface TestIface { 1.59 + void passKid(Kid arg); 1.60 + void passParent(Parent arg); 1.61 + void passGrandparent(Grandparent arg); 1.62 + void passImplemented(Implemented arg); 1.63 + void passImplementedParent(ImplementedParent arg); 1.64 + void passUnrelated1(Unrelated1 arg); 1.65 + void passUnrelated2(Unrelated2 arg); 1.66 + void passArrayBuffer(ArrayBuffer arg); 1.67 + void passArrayBuffer(ArrayBufferView arg); 1.68 + }; 1.69 + 1.70 + interface Kid : Parent {}; 1.71 + interface Parent : Grandparent {}; 1.72 + interface Grandparent {}; 1.73 + interface Implemented : ImplementedParent {}; 1.74 + Parent implements Implemented; 1.75 + interface ImplementedParent {}; 1.76 + interface Unrelated1 {}; 1.77 + interface Unrelated2 {}; 1.78 + """) 1.79 + results = parser.finish() 1.80 + 1.81 + iface = results[0] 1.82 + harness.ok(iface.isInterface(), "Should have interface") 1.83 + argTypes = [firstArgType(method) for method in iface.members] 1.84 + unrelatedTypes = [firstArgType(method) for method in iface.members[-3:]] 1.85 + 1.86 + for type1 in argTypes: 1.87 + for type2 in argTypes: 1.88 + distinguishable = (type1 is not type2 and 1.89 + (type1 in unrelatedTypes or 1.90 + type2 in unrelatedTypes)) 1.91 + 1.92 + harness.check(type1.isDistinguishableFrom(type2), 1.93 + distinguishable, 1.94 + "Type %s should %sbe distinguishable from type %s" % 1.95 + (type1, "" if distinguishable else "not ", type2)) 1.96 + harness.check(type2.isDistinguishableFrom(type1), 1.97 + distinguishable, 1.98 + "Type %s should %sbe distinguishable from type %s" % 1.99 + (type2, "" if distinguishable else "not ", type1)) 1.100 + 1.101 + parser = parser.reset() 1.102 + parser.parse(""" 1.103 + interface Dummy {}; 1.104 + interface TestIface { 1.105 + void method(long arg1, TestIface arg2); 1.106 + void method(long arg1, long arg2); 1.107 + void method(long arg1, Dummy arg2); 1.108 + void method(DOMString arg1, DOMString arg2, DOMString arg3); 1.109 + }; 1.110 + """) 1.111 + results = parser.finish() 1.112 + harness.check(len(results[1].members), 1, 1.113 + "Should look like we have one method") 1.114 + harness.check(len(results[1].members[0].signatures()), 4, 1.115 + "Should have four signatures") 1.116 + 1.117 + parser = parser.reset() 1.118 + threw = False 1.119 + try: 1.120 + parser.parse(""" 1.121 + interface Dummy {}; 1.122 + interface TestIface { 1.123 + void method(long arg1, TestIface arg2); 1.124 + void method(long arg1, long arg2); 1.125 + void method(any arg1, Dummy arg2); 1.126 + void method(DOMString arg1, DOMString arg2, DOMString arg3); 1.127 + }; 1.128 + """) 1.129 + results = parser.finish() 1.130 + except: 1.131 + threw = True 1.132 + 1.133 + harness.ok(threw, 1.134 + "Should throw when args before the distinguishing arg are not " 1.135 + "all the same type") 1.136 + 1.137 + parser = parser.reset() 1.138 + threw = False 1.139 + try: 1.140 + parser.parse(""" 1.141 + interface Dummy {}; 1.142 + interface TestIface { 1.143 + void method(long arg1, TestIface arg2); 1.144 + void method(long arg1, long arg2); 1.145 + void method(any arg1, DOMString arg2); 1.146 + void method(DOMString arg1, DOMString arg2, DOMString arg3); 1.147 + }; 1.148 + """) 1.149 + results = parser.finish() 1.150 + except: 1.151 + threw = True 1.152 + 1.153 + harness.ok(threw, "Should throw when there is no distinguishing index") 1.154 + 1.155 + # Now let's test our whole distinguishability table 1.156 + argTypes = [ "long", "short", "long?", "short?", "boolean", 1.157 + "boolean?", "DOMString", "ByteString", "Enum", "Enum2", 1.158 + "Interface", "Interface?", 1.159 + "AncestorInterface", "UnrelatedInterface", 1.160 + "ImplementedInterface", "CallbackInterface", 1.161 + "CallbackInterface?", "CallbackInterface2", 1.162 + "object", "Callback", "Callback2", "optional Dict", 1.163 + "optional Dict2", "sequence<long>", "sequence<short>", 1.164 + "MozMap<object>", "MozMap<Dict>", "MozMap<long>", 1.165 + "long[]", "short[]", "Date", "Date?", "any" ] 1.166 + # When we can parse Date and RegExp, we need to add them here. 1.167 + 1.168 + # Try to categorize things a bit to keep list lengths down 1.169 + def allBut(list1, list2): 1.170 + return [a for a in list1 if a not in list2 and a != "any"] 1.171 + numerics = [ "long", "short", "long?", "short?" ] 1.172 + booleans = [ "boolean", "boolean?" ] 1.173 + primitives = numerics + booleans 1.174 + nonNumerics = allBut(argTypes, numerics) 1.175 + nonBooleans = allBut(argTypes, booleans) 1.176 + strings = [ "DOMString", "ByteString", "Enum", "Enum2" ] 1.177 + nonStrings = allBut(argTypes, strings) 1.178 + nonObjects = primitives + strings 1.179 + objects = allBut(argTypes, nonObjects ) 1.180 + interfaces = [ "Interface", "Interface?", "AncestorInterface", 1.181 + "UnrelatedInterface", "ImplementedInterface" ] 1.182 + nullables = ["long?", "short?", "boolean?", "Interface?", 1.183 + "CallbackInterface?", "optional Dict", "optional Dict2", 1.184 + "Date?", "any"] 1.185 + dates = [ "Date", "Date?" ] 1.186 + nonUserObjects = nonObjects + interfaces + dates 1.187 + otherObjects = allBut(argTypes, nonUserObjects + ["object"]) 1.188 + notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + 1.189 + otherObjects + dates) 1.190 + 1.191 + # Build a representation of the distinguishability table as a dict 1.192 + # of dicts, holding True values where needed, holes elsewhere. 1.193 + data = dict(); 1.194 + for type in argTypes: 1.195 + data[type] = dict() 1.196 + def setDistinguishable(type, types): 1.197 + for other in types: 1.198 + data[type][other] = True 1.199 + 1.200 + setDistinguishable("long", nonNumerics) 1.201 + setDistinguishable("short", nonNumerics) 1.202 + setDistinguishable("long?", allBut(nonNumerics, nullables)) 1.203 + setDistinguishable("short?", allBut(nonNumerics, nullables)) 1.204 + setDistinguishable("boolean", nonBooleans) 1.205 + setDistinguishable("boolean?", allBut(nonBooleans, nullables)) 1.206 + setDistinguishable("DOMString", nonStrings) 1.207 + setDistinguishable("ByteString", nonStrings) 1.208 + setDistinguishable("Enum", nonStrings) 1.209 + setDistinguishable("Enum2", nonStrings) 1.210 + setDistinguishable("Interface", notRelatedInterfaces) 1.211 + setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables)) 1.212 + setDistinguishable("AncestorInterface", notRelatedInterfaces) 1.213 + setDistinguishable("UnrelatedInterface", 1.214 + allBut(argTypes, ["object", "UnrelatedInterface"])) 1.215 + setDistinguishable("ImplementedInterface", notRelatedInterfaces) 1.216 + setDistinguishable("CallbackInterface", nonUserObjects) 1.217 + setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables)) 1.218 + setDistinguishable("CallbackInterface2", nonUserObjects) 1.219 + setDistinguishable("object", nonObjects) 1.220 + setDistinguishable("Callback", nonUserObjects) 1.221 + setDistinguishable("Callback2", nonUserObjects) 1.222 + setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) 1.223 + setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) 1.224 + setDistinguishable("sequence<long>", nonUserObjects) 1.225 + setDistinguishable("sequence<short>", nonUserObjects) 1.226 + setDistinguishable("MozMap<object>", nonUserObjects) 1.227 + setDistinguishable("MozMap<Dict>", nonUserObjects) 1.228 + setDistinguishable("MozMap<long>", nonUserObjects) 1.229 + setDistinguishable("long[]", nonUserObjects) 1.230 + setDistinguishable("short[]", nonUserObjects) 1.231 + setDistinguishable("Date", allBut(argTypes, dates + ["object"])) 1.232 + setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) 1.233 + setDistinguishable("any", []) 1.234 + 1.235 + def areDistinguishable(type1, type2): 1.236 + return data[type1].get(type2, False) 1.237 + 1.238 + def checkDistinguishability(parser, type1, type2): 1.239 + idlTemplate = """ 1.240 + enum Enum { "a", "b" }; 1.241 + enum Enum2 { "c", "d" }; 1.242 + interface Interface : AncestorInterface {}; 1.243 + interface AncestorInterface {}; 1.244 + interface UnrelatedInterface {}; 1.245 + interface ImplementedInterface {}; 1.246 + Interface implements ImplementedInterface; 1.247 + callback interface CallbackInterface {}; 1.248 + callback interface CallbackInterface2 {}; 1.249 + callback Callback = any(); 1.250 + callback Callback2 = long(short arg); 1.251 + dictionary Dict {}; 1.252 + dictionary Dict2 {}; 1.253 + interface TestInterface {%s 1.254 + }; 1.255 + """ 1.256 + methodTemplate = """ 1.257 + void myMethod(%s arg);""" 1.258 + methods = (methodTemplate % type1) + (methodTemplate % type2) 1.259 + idl = idlTemplate % methods 1.260 + parser = parser.reset() 1.261 + threw = False 1.262 + try: 1.263 + parser.parse(idl) 1.264 + results = parser.finish() 1.265 + except: 1.266 + threw = True 1.267 + 1.268 + if areDistinguishable(type1, type2): 1.269 + harness.ok(not threw, 1.270 + "Should not throw for '%s' and '%s' because they are distinguishable" % (type1, type2)) 1.271 + else: 1.272 + harness.ok(threw, 1.273 + "Should throw for '%s' and '%s' because they are not distinguishable" % (type1, type2)) 1.274 + 1.275 + # Enumerate over everything in both orders, since order matters in 1.276 + # terms of our implementation of distinguishability checks 1.277 + for type1 in argTypes: 1.278 + for type2 in argTypes: 1.279 + checkDistinguishability(parser, type1, type2)