michael@0: def firstArgType(method): michael@0: return method.signatures()[0][1][0].type michael@0: michael@0: def WebIDLTest(parser, harness): michael@0: parser.parse(""" michael@0: dictionary Dict { michael@0: }; michael@0: callback interface Foo { michael@0: }; michael@0: interface Bar { michael@0: // Bit of a pain to get things that have dictionary types michael@0: void passDict(optional Dict arg); michael@0: void passFoo(Foo arg); michael@0: void passNullableUnion((object? or DOMString) arg); michael@0: void passNullable(Foo? arg); michael@0: }; michael@0: """) michael@0: results = parser.finish() michael@0: michael@0: iface = results[2] michael@0: harness.ok(iface.isInterface(), "Should have interface") michael@0: dictMethod = iface.members[0] michael@0: ifaceMethod = iface.members[1] michael@0: nullableUnionMethod = iface.members[2] michael@0: nullableIfaceMethod = iface.members[3] michael@0: michael@0: dictType = firstArgType(dictMethod) michael@0: ifaceType = firstArgType(ifaceMethod) michael@0: michael@0: harness.ok(dictType.isDictionary(), "Should have dictionary type"); michael@0: harness.ok(ifaceType.isInterface(), "Should have interface type"); michael@0: harness.ok(ifaceType.isCallbackInterface(), "Should have callback interface type"); michael@0: michael@0: harness.ok(not dictType.isDistinguishableFrom(ifaceType), michael@0: "Dictionary not distinguishable from callback interface") michael@0: harness.ok(not ifaceType.isDistinguishableFrom(dictType), michael@0: "Callback interface not distinguishable from dictionary") michael@0: michael@0: nullableUnionType = firstArgType(nullableUnionMethod) michael@0: nullableIfaceType = firstArgType(nullableIfaceMethod) michael@0: michael@0: harness.ok(nullableUnionType.isUnion(), "Should have union type"); michael@0: harness.ok(nullableIfaceType.isInterface(), "Should have interface type"); michael@0: harness.ok(nullableIfaceType.nullable(), "Should have nullable type"); michael@0: michael@0: harness.ok(not nullableUnionType.isDistinguishableFrom(nullableIfaceType), michael@0: "Nullable type not distinguishable from union with nullable " michael@0: "member type") michael@0: harness.ok(not nullableIfaceType.isDistinguishableFrom(nullableUnionType), michael@0: "Union with nullable member type not distinguishable from " michael@0: "nullable type") michael@0: michael@0: parser = parser.reset() michael@0: parser.parse(""" michael@0: interface TestIface { michael@0: void passKid(Kid arg); michael@0: void passParent(Parent arg); michael@0: void passGrandparent(Grandparent arg); michael@0: void passImplemented(Implemented arg); michael@0: void passImplementedParent(ImplementedParent arg); michael@0: void passUnrelated1(Unrelated1 arg); michael@0: void passUnrelated2(Unrelated2 arg); michael@0: void passArrayBuffer(ArrayBuffer arg); michael@0: void passArrayBuffer(ArrayBufferView arg); michael@0: }; michael@0: michael@0: interface Kid : Parent {}; michael@0: interface Parent : Grandparent {}; michael@0: interface Grandparent {}; michael@0: interface Implemented : ImplementedParent {}; michael@0: Parent implements Implemented; michael@0: interface ImplementedParent {}; michael@0: interface Unrelated1 {}; michael@0: interface Unrelated2 {}; michael@0: """) michael@0: results = parser.finish() michael@0: michael@0: iface = results[0] michael@0: harness.ok(iface.isInterface(), "Should have interface") michael@0: argTypes = [firstArgType(method) for method in iface.members] michael@0: unrelatedTypes = [firstArgType(method) for method in iface.members[-3:]] michael@0: michael@0: for type1 in argTypes: michael@0: for type2 in argTypes: michael@0: distinguishable = (type1 is not type2 and michael@0: (type1 in unrelatedTypes or michael@0: type2 in unrelatedTypes)) michael@0: michael@0: harness.check(type1.isDistinguishableFrom(type2), michael@0: distinguishable, michael@0: "Type %s should %sbe distinguishable from type %s" % michael@0: (type1, "" if distinguishable else "not ", type2)) michael@0: harness.check(type2.isDistinguishableFrom(type1), michael@0: distinguishable, michael@0: "Type %s should %sbe distinguishable from type %s" % michael@0: (type2, "" if distinguishable else "not ", type1)) michael@0: michael@0: parser = parser.reset() michael@0: parser.parse(""" michael@0: interface Dummy {}; michael@0: interface TestIface { michael@0: void method(long arg1, TestIface arg2); michael@0: void method(long arg1, long arg2); michael@0: void method(long arg1, Dummy arg2); michael@0: void method(DOMString arg1, DOMString arg2, DOMString arg3); michael@0: }; michael@0: """) michael@0: results = parser.finish() michael@0: harness.check(len(results[1].members), 1, michael@0: "Should look like we have one method") michael@0: harness.check(len(results[1].members[0].signatures()), 4, michael@0: "Should have four signatures") michael@0: michael@0: parser = parser.reset() michael@0: threw = False michael@0: try: michael@0: parser.parse(""" michael@0: interface Dummy {}; michael@0: interface TestIface { michael@0: void method(long arg1, TestIface arg2); michael@0: void method(long arg1, long arg2); michael@0: void method(any arg1, Dummy arg2); michael@0: void method(DOMString arg1, DOMString arg2, DOMString arg3); michael@0: }; michael@0: """) michael@0: results = parser.finish() michael@0: except: michael@0: threw = True michael@0: michael@0: harness.ok(threw, michael@0: "Should throw when args before the distinguishing arg are not " michael@0: "all the same type") michael@0: michael@0: parser = parser.reset() michael@0: threw = False michael@0: try: michael@0: parser.parse(""" michael@0: interface Dummy {}; michael@0: interface TestIface { michael@0: void method(long arg1, TestIface arg2); michael@0: void method(long arg1, long arg2); michael@0: void method(any arg1, DOMString arg2); michael@0: void method(DOMString arg1, DOMString arg2, DOMString arg3); michael@0: }; michael@0: """) michael@0: results = parser.finish() michael@0: except: michael@0: threw = True michael@0: michael@0: harness.ok(threw, "Should throw when there is no distinguishing index") michael@0: michael@0: # Now let's test our whole distinguishability table michael@0: argTypes = [ "long", "short", "long?", "short?", "boolean", michael@0: "boolean?", "DOMString", "ByteString", "Enum", "Enum2", michael@0: "Interface", "Interface?", michael@0: "AncestorInterface", "UnrelatedInterface", michael@0: "ImplementedInterface", "CallbackInterface", michael@0: "CallbackInterface?", "CallbackInterface2", michael@0: "object", "Callback", "Callback2", "optional Dict", michael@0: "optional Dict2", "sequence", "sequence", michael@0: "MozMap", "MozMap", "MozMap", michael@0: "long[]", "short[]", "Date", "Date?", "any" ] michael@0: # When we can parse Date and RegExp, we need to add them here. michael@0: michael@0: # Try to categorize things a bit to keep list lengths down michael@0: def allBut(list1, list2): michael@0: return [a for a in list1 if a not in list2 and a != "any"] michael@0: numerics = [ "long", "short", "long?", "short?" ] michael@0: booleans = [ "boolean", "boolean?" ] michael@0: primitives = numerics + booleans michael@0: nonNumerics = allBut(argTypes, numerics) michael@0: nonBooleans = allBut(argTypes, booleans) michael@0: strings = [ "DOMString", "ByteString", "Enum", "Enum2" ] michael@0: nonStrings = allBut(argTypes, strings) michael@0: nonObjects = primitives + strings michael@0: objects = allBut(argTypes, nonObjects ) michael@0: interfaces = [ "Interface", "Interface?", "AncestorInterface", michael@0: "UnrelatedInterface", "ImplementedInterface" ] michael@0: nullables = ["long?", "short?", "boolean?", "Interface?", michael@0: "CallbackInterface?", "optional Dict", "optional Dict2", michael@0: "Date?", "any"] michael@0: dates = [ "Date", "Date?" ] michael@0: nonUserObjects = nonObjects + interfaces + dates michael@0: otherObjects = allBut(argTypes, nonUserObjects + ["object"]) michael@0: notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + michael@0: otherObjects + dates) michael@0: michael@0: # Build a representation of the distinguishability table as a dict michael@0: # of dicts, holding True values where needed, holes elsewhere. michael@0: data = dict(); michael@0: for type in argTypes: michael@0: data[type] = dict() michael@0: def setDistinguishable(type, types): michael@0: for other in types: michael@0: data[type][other] = True michael@0: michael@0: setDistinguishable("long", nonNumerics) michael@0: setDistinguishable("short", nonNumerics) michael@0: setDistinguishable("long?", allBut(nonNumerics, nullables)) michael@0: setDistinguishable("short?", allBut(nonNumerics, nullables)) michael@0: setDistinguishable("boolean", nonBooleans) michael@0: setDistinguishable("boolean?", allBut(nonBooleans, nullables)) michael@0: setDistinguishable("DOMString", nonStrings) michael@0: setDistinguishable("ByteString", nonStrings) michael@0: setDistinguishable("Enum", nonStrings) michael@0: setDistinguishable("Enum2", nonStrings) michael@0: setDistinguishable("Interface", notRelatedInterfaces) michael@0: setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables)) michael@0: setDistinguishable("AncestorInterface", notRelatedInterfaces) michael@0: setDistinguishable("UnrelatedInterface", michael@0: allBut(argTypes, ["object", "UnrelatedInterface"])) michael@0: setDistinguishable("ImplementedInterface", notRelatedInterfaces) michael@0: setDistinguishable("CallbackInterface", nonUserObjects) michael@0: setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables)) michael@0: setDistinguishable("CallbackInterface2", nonUserObjects) michael@0: setDistinguishable("object", nonObjects) michael@0: setDistinguishable("Callback", nonUserObjects) michael@0: setDistinguishable("Callback2", nonUserObjects) michael@0: setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) michael@0: setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) michael@0: setDistinguishable("sequence", nonUserObjects) michael@0: setDistinguishable("sequence", nonUserObjects) michael@0: setDistinguishable("MozMap", nonUserObjects) michael@0: setDistinguishable("MozMap", nonUserObjects) michael@0: setDistinguishable("MozMap", nonUserObjects) michael@0: setDistinguishable("long[]", nonUserObjects) michael@0: setDistinguishable("short[]", nonUserObjects) michael@0: setDistinguishable("Date", allBut(argTypes, dates + ["object"])) michael@0: setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) michael@0: setDistinguishable("any", []) michael@0: michael@0: def areDistinguishable(type1, type2): michael@0: return data[type1].get(type2, False) michael@0: michael@0: def checkDistinguishability(parser, type1, type2): michael@0: idlTemplate = """ michael@0: enum Enum { "a", "b" }; michael@0: enum Enum2 { "c", "d" }; michael@0: interface Interface : AncestorInterface {}; michael@0: interface AncestorInterface {}; michael@0: interface UnrelatedInterface {}; michael@0: interface ImplementedInterface {}; michael@0: Interface implements ImplementedInterface; michael@0: callback interface CallbackInterface {}; michael@0: callback interface CallbackInterface2 {}; michael@0: callback Callback = any(); michael@0: callback Callback2 = long(short arg); michael@0: dictionary Dict {}; michael@0: dictionary Dict2 {}; michael@0: interface TestInterface {%s michael@0: }; michael@0: """ michael@0: methodTemplate = """ michael@0: void myMethod(%s arg);""" michael@0: methods = (methodTemplate % type1) + (methodTemplate % type2) michael@0: idl = idlTemplate % methods michael@0: parser = parser.reset() michael@0: threw = False michael@0: try: michael@0: parser.parse(idl) michael@0: results = parser.finish() michael@0: except: michael@0: threw = True michael@0: michael@0: if areDistinguishable(type1, type2): michael@0: harness.ok(not threw, michael@0: "Should not throw for '%s' and '%s' because they are distinguishable" % (type1, type2)) michael@0: else: michael@0: harness.ok(threw, michael@0: "Should throw for '%s' and '%s' because they are not distinguishable" % (type1, type2)) michael@0: michael@0: # Enumerate over everything in both orders, since order matters in michael@0: # terms of our implementation of distinguishability checks michael@0: for type1 in argTypes: michael@0: for type2 in argTypes: michael@0: checkDistinguishability(parser, type1, type2)