diff options
author | AgostonSzepessy <agszepp@gmail.com> | 2016-03-06 18:47:35 -0500 |
---|---|---|
committer | AgostonSzepessy <agszepp@gmail.com> | 2016-03-22 23:13:30 -0400 |
commit | d3528ffce4092e0b28b9494f96555368bf8945b9 (patch) | |
tree | af13c09d65a3a61e6131b96e4aa45e6bab27905b /components/script/dom/bindings/codegen/parser | |
parent | 003fdd41769652188a5954e6499f3cb44eef6b10 (diff) | |
download | servo-d3528ffce4092e0b28b9494f96555368bf8945b9.tar.gz servo-d3528ffce4092e0b28b9494f96555368bf8945b9.zip |
components/script/dom/bindings/codegen/parser/update.sh now downloads all
the latest *.py tests from
https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/
Diffstat (limited to 'components/script/dom/bindings/codegen/parser')
29 files changed, 2899 insertions, 59 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index e653ad7e9ac..09fab2e7a74 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -508,6 +508,9 @@ class IDLExposureMixins(): def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 + def isExposedInWorkerDebugger(self): + return len(self.getWorkerDebuggerExposureSet()) > 0 + def isExposedInSystemGlobals(self): return 'BackstagePass' in self.exposureSet @@ -527,6 +530,10 @@ class IDLExposureMixins(): workerScopes = self._globalScope.globalNameMapping["Worker"] return workerScopes.intersection(self.exposureSet) + def getWorkerDebuggerExposureSet(self): + workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"] + return workerDebuggerScopes.intersection(self.exposureSet) + class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def __init__(self, location, parentScope, identifier): @@ -978,7 +985,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): (member.getExtendedAttribute("StoreInSlot") or member.getExtendedAttribute("Cached"))) or member.isMaplikeOrSetlike()): - member.slotIndex = self.totalMembersInSlots + if member.slotIndices is None: + member.slotIndices = dict() + member.slotIndices[self.identifier.name] = self.totalMembersInSlots self.totalMembersInSlots += 1 if member.getExtendedAttribute("StoreInSlot"): self._ownMembersInSlots += 1 @@ -1102,7 +1111,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): def validate(self): # We don't support consequential unforgeable interfaces. Need to check - # this here, becaue in finish() an interface might not know yet that + # this here, because in finish() an interface might not know yet that # it's consequential. if self.getExtendedAttribute("Unforgeable") and self.isConsequential(): raise WebIDLError( @@ -1121,6 +1130,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): self.identifier.name, locations) + indexedGetter = None + hasLengthAttribute = False for member in self.members: member.validate() @@ -1131,8 +1142,13 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): [self.location, member.location]) # Check that PutForwards refers to another attribute and that no - # cycles exist in forwarded assignments. + # cycles exist in forwarded assignments. Also check for a + # integer-typed "length" attribute. if member.isAttr(): + if (member.identifier.name == "length" and + member.type.isInteger()): + hasLengthAttribute = True + iface = self attr = member putForwards = attr.getExtendedAttribute("PutForwards") @@ -1170,8 +1186,11 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): putForwards = attr.getExtendedAttribute("PutForwards") # Check that the name of an [Alias] doesn't conflict with an - # interface member. + # interface member and whether we support indexed properties. if member.isMethod(): + if member.isGetter() and member.isIndexed(): + indexedGetter = member + for alias in member.aliases: if self.isOnGlobalProtoChain(): raise WebIDLError("[Alias] must not be used on a " @@ -1232,6 +1251,35 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): "exposed conditionally", [self.location]) + # Value iterators are only allowed on interfaces with indexed getters, + # and pair iterators are only allowed on interfaces without indexed + # getters. + if self.isIterable(): + iterableDecl = self.maplikeOrSetlikeOrIterable + if iterableDecl.isValueIterator(): + if not indexedGetter: + raise WebIDLError("Interface with value iterator does not " + "support indexed properties", + [self.location]) + + if iterableDecl.valueType != indexedGetter.signatures()[0][0]: + raise WebIDLError("Iterable type does not match indexed " + "getter type", + [iterableDecl.location, + indexedGetter.location]) + + if not hasLengthAttribute: + raise WebIDLError('Interface with value iterator does not ' + 'have an integer-typed "length" attribute', + [self.location]) + else: + assert iterableDecl.isPairIterator() + if indexedGetter: + raise WebIDLError("Interface with pair iterator supports " + "indexed properties", + [self.location, iterableDecl.location, + indexedGetter.location]) + def isInterface(self): return True @@ -3432,7 +3480,10 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) - assert isinstance(keyType, IDLType) + if keyType is not None: + assert isinstance(keyType, IDLType) + else: + assert valueType is not None assert ifaceType in ['maplike', 'setlike', 'iterable'] if valueType is not None: assert isinstance(valueType, IDLType) @@ -3451,6 +3502,9 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): def isIterable(self): return self.maplikeOrSetlikeOrIterableType == "iterable" + def hasKeyType(self): + return self.keyType is not None + def hasValueType(self): return self.valueType is not None @@ -3475,7 +3529,8 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): [self.location, member.location]) def addMethod(self, name, members, allowExistingOperations, returnType, args=[], - chromeOnly=False, isPure=False, affectsNothing=False, newObject=False): + chromeOnly=False, isPure=False, affectsNothing=False, newObject=False, + isIteratorAlias=False): """ Create an IDLMethod based on the parameters passed in. @@ -3535,16 +3590,20 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): if newObject: method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("NewObject",))]) + if isIteratorAlias: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))]) members.append(method) def resolve(self, parentScope): - self.keyType.resolveType(parentScope) + if self.keyType: + self.keyType.resolveType(parentScope) if self.valueType: self.valueType.resolveType(parentScope) def finish(self, scope): IDLInterfaceMember.finish(self, scope) - if not self.keyType.isComplete(): + if self.keyType and not self.keyType.isComplete(): t = self.keyType.complete(scope) assert not isinstance(t, IDLUnresolvedType) @@ -3566,9 +3625,23 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): IDLInterfaceMember.handleExtendedAttribute(self, attr) def _getDependentObjects(self): + deps = set() + if self.keyType: + deps.add(self.keyType) if self.valueType: - return set([self.keyType, self.valueType]) - return set([self.keyType]) + deps.add(self.valueType) + return deps + + def getForEachArguments(self): + return [IDLArgument(self.location, + IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), + "callback"), + BuiltinTypes[IDLBuiltinType.Types.object]), + IDLArgument(self.location, + IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), + "thisArg"), + BuiltinTypes[IDLBuiltinType.Types.any], + optional=True)] # Iterable adds ES6 iterator style functions and traits # (keys/values/entries/@@iterator) to an interface. @@ -3589,9 +3662,15 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): we generate our functions as if they were part of the interface specification during parsing. """ + # We only need to add entries/keys/values here if we're a pair iterator. + # Value iterators just copy these from %ArrayPrototype% instead. + if not self.isPairIterator(): + return + # object entries() self.addMethod("entries", members, False, self.iteratorType, - affectsNothing=True, newObject=True) + affectsNothing=True, newObject=True, + isIteratorAlias=True) # object keys() self.addMethod("keys", members, False, self.iteratorType, affectsNothing=True, newObject=True) @@ -3599,6 +3678,17 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): self.addMethod("values", members, False, self.iteratorType, affectsNothing=True, newObject=True) + # void forEach(callback(valueType, keyType), optional any thisArg) + self.addMethod("forEach", members, False, + BuiltinTypes[IDLBuiltinType.Types.void], + self.getForEachArguments()) + + def isValueIterator(self): + return not self.isPairIterator() + + def isPairIterator(self): + return self.hasKeyType() + # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): @@ -3607,7 +3697,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType, keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike) self.readonly = readonly - self.slotIndex = None + self.slotIndices = None # When generating JSAPI access code, we need to know the backing object # type prefix to create the correct function. Generate here for reuse. @@ -3635,26 +3725,17 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): # object entries() self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + affectsNothing=True, isIteratorAlias=self.isMaplike()) # object keys() self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object], affectsNothing=True) # object values() self.addMethod("values", members, False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + affectsNothing=True, isIteratorAlias=self.isSetlike()) # void forEach(callback(valueType, keyType), thisVal) - foreachArguments = [IDLArgument(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "callback"), - BuiltinTypes[IDLBuiltinType.Types.object]), - IDLArgument(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "thisArg"), - BuiltinTypes[IDLBuiltinType.Types.any], - optional=True)] self.addMethod("forEach", members, False, BuiltinTypes[IDLBuiltinType.Types.void], - foreachArguments) + self.getForEachArguments()) def getKeyArg(): return IDLArgument(self.location, @@ -3801,7 +3882,7 @@ class IDLAttribute(IDLInterfaceMember): self.stringifier = stringifier self.enforceRange = False self.clamp = False - self.slotIndex = None + self.slotIndices = None assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike) self.maplikeOrSetlike = maplikeOrSetlike self.dependsOn = "Everything" @@ -5444,10 +5525,13 @@ class Parser(Tokenizer): location = self.getLocation(p, 2) identifier = IDLUnresolvedIdentifier(location, "__iterable", allowDoubleUnderscore=True) - keyType = p[3] - valueType = None if (len(p) > 6): + keyType = p[3] valueType = p[5] + else: + keyType = None + valueType = p[3] + p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope()) def p_Setlike(self, p): @@ -6518,7 +6602,7 @@ class Parser(Tokenizer): if isinstance(m, IDLIterable): iterable = m break - if iterable: + if iterable and iterable.isPairIterator(): def simpleExtendedAttr(str): return IDLExtendedAttribute(iface.location, (str, )) nextMethod = IDLMethod( diff --git a/components/script/dom/bindings/codegen/parser/tests/test_array.py b/components/script/dom/bindings/codegen/parser/tests/test_array.py new file mode 100644 index 00000000000..8f9e9c96854 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_array.py @@ -0,0 +1,18 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + dictionary Foo { + short a; + }; + + dictionary Foo1 { + Foo[] b; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Array must not contain dictionary " + "as element type.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py b/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py new file mode 100644 index 00000000000..d73455f8812 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py @@ -0,0 +1,72 @@ +# -*- coding: UTF-8 -*- + +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestByteString { + attribute ByteString bs; + attribute DOMString ds; + }; + """) + + results = parser.finish(); + + harness.ok(True, "TestByteString interface parsed without error.") + + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + iface = results[0] + harness.check(iface.identifier.QName(), "::TestByteString", "Interface has the right QName") + harness.check(iface.identifier.name, "TestByteString", "Interface has the right name") + harness.check(iface.parent, None, "Interface has no parent") + + members = iface.members + harness.check(len(members), 2, "Should be two productions") + + attr = members[0] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute") + harness.check(attr.identifier.QName(), "::TestByteString::bs", "Attr has correct QName") + harness.check(attr.identifier.name, "bs", "Attr has correct name") + harness.check(str(attr.type), "ByteString", "Attr type is the correct name") + harness.ok(attr.type.isByteString(), "Should be ByteString type") + harness.ok(attr.type.isString(), "Should be String collective type") + harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type") + + # now check we haven't broken DOMStrings in the process. + attr = members[1] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute") + harness.check(attr.identifier.QName(), "::TestByteString::ds", "Attr has correct QName") + harness.check(attr.identifier.name, "ds", "Attr has correct name") + harness.check(str(attr.type), "String", "Attr type is the correct name") + harness.ok(attr.type.isDOMString(), "Should be DOMString type") + harness.ok(attr.type.isString(), "Should be String collective type") + harness.ok(not attr.type.isByteString(), "Should be not be ByteString type") + + # Cannot represent constant ByteString in IDL. + threw = False + try: + parser.parse(""" + interface ConstByteString { + const ByteString foo = "hello" + }; + """) + except WebIDL.WebIDLError: + threw = True + harness.ok(threw, "Should have thrown a WebIDL error") + + # Cannot have optional ByteStrings with default values + threw = False + try: + parser.parse(""" + interface OptionalByteString { + void passByteString(optional ByteString arg = "hello"); + }; + """) + results2 = parser.finish(); + except WebIDL.WebIDLError: + threw = True + + harness.ok(threw, "Should have thrown a WebIDL error") + diff --git a/components/script/dom/bindings/codegen/parser/tests/test_callback.py b/components/script/dom/bindings/codegen/parser/tests/test_callback.py index 267d27dc087..4dfda1c3c76 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_callback.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_callback.py @@ -12,7 +12,7 @@ def WebIDLTest(parser, harness): results = parser.finish() harness.ok(True, "TestCallback interface parsed without error.") - harness.check(len(results), 2, "Should be one production.") + harness.check(len(results), 2, "Should be two productions.") iface = results[0] harness.ok(isinstance(iface, WebIDL.IDLInterface), "Should be an IDLInterface") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_callback_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_callback_interface.py index 80896ca1edb..e4789dae168 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_callback_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_callback_interface.py @@ -45,3 +45,50 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow callback parent of non-callback interface") + parser = parser.reset() + parser.parse(""" + callback interface TestCallbackInterface1 { + void foo(); + }; + callback interface TestCallbackInterface2 { + void foo(DOMString arg); + void foo(TestCallbackInterface1 arg); + }; + callback interface TestCallbackInterface3 { + void foo(DOMString arg); + void foo(TestCallbackInterface1 arg); + static void bar(); + }; + callback interface TestCallbackInterface4 { + void foo(DOMString arg); + void foo(TestCallbackInterface1 arg); + static void bar(); + const long baz = 5; + }; + callback interface TestCallbackInterface5 { + static attribute boolean bool; + void foo(); + }; + callback interface TestCallbackInterface6 { + void foo(DOMString arg); + void foo(TestCallbackInterface1 arg); + void bar(); + }; + callback interface TestCallbackInterface7 { + static attribute boolean bool; + }; + callback interface TestCallbackInterface8 { + attribute boolean bool; + }; + callback interface TestCallbackInterface9 : TestCallbackInterface1 { + void foo(); + }; + callback interface TestCallbackInterface10 : TestCallbackInterface1 { + void bar(); + }; + """) + results = parser.finish() + for (i, iface) in enumerate(results): + harness.check(iface.isSingleOperationInterface(), i < 4, + "Interface %s should be a single operation interface" % + iface.identifier.name) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_const.py b/components/script/dom/bindings/codegen/parser/tests/test_const.py index 12f411363fb..80b6fb0e9c8 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_const.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_const.py @@ -1,5 +1,30 @@ import WebIDL +expected = [ + ("::TestConsts::zero", "zero", "Byte", 0), + ("::TestConsts::b", "b", "Byte", -1), + ("::TestConsts::o", "o", "Octet", 2), + ("::TestConsts::s", "s", "Short", -3), + ("::TestConsts::us", "us", "UnsignedShort", 4), + ("::TestConsts::l", "l", "Long", -5), + ("::TestConsts::ul", "ul", "UnsignedLong", 6), + ("::TestConsts::ull", "ull", "UnsignedLongLong", 7), + ("::TestConsts::ll", "ll", "LongLong", -8), + ("::TestConsts::t", "t", "Boolean", True), + ("::TestConsts::f", "f", "Boolean", False), + ("::TestConsts::n", "n", "BooleanOrNull", None), + ("::TestConsts::nt", "nt", "BooleanOrNull", True), + ("::TestConsts::nf", "nf", "BooleanOrNull", False), + ("::TestConsts::fl", "fl", "Float", 0.2), + ("::TestConsts::db", "db", "Double", 0.2), + ("::TestConsts::ufl", "ufl", "UnrestrictedFloat", 0.2), + ("::TestConsts::udb", "udb", "UnrestrictedDouble", 0.2), + ("::TestConsts::fli", "fli", "Float", 2), + ("::TestConsts::dbi", "dbi", "Double", 2), + ("::TestConsts::ufli", "ufli", "UnrestrictedFloat", 2), + ("::TestConsts::udbi", "udbi", "UnrestrictedDouble", 2), +] + def WebIDLTest(parser, harness): parser.parse(""" interface TestConsts { @@ -17,6 +42,14 @@ def WebIDLTest(parser, harness): const boolean? n = null; const boolean? nt = true; const boolean? nf = false; + const float fl = 0.2; + const double db = 0.2; + const unrestricted float ufl = 0.2; + const unrestricted double udb = 0.2; + const float fli = 2; + const double dbi = 2; + const unrestricted float ufli = 2; + const unrestricted double udbi = 2; }; """) @@ -29,11 +62,9 @@ def WebIDLTest(parser, harness): "Should be an IDLInterface") harness.check(iface.identifier.QName(), "::TestConsts", "Interface has the right QName") harness.check(iface.identifier.name, "TestConsts", "Interface has the right name") - harness.check(len(iface.members), 14, "Expect 14 members") - - consts = iface.members + harness.check(len(iface.members), len(expected), "Expect %s members" % len(expected)) - def checkConst(const, QName, name, type, value): + for (const, (QName, name, type, value)) in zip(iface.members, expected): harness.ok(isinstance(const, WebIDL.IDLConst), "Should be an IDLConst") harness.ok(const.isConst(), "Const is a const") @@ -47,18 +78,3 @@ def WebIDLTest(parser, harness): "Const's value has the same type as the type") harness.check(const.value.value, value, "Const value has the right value.") - checkConst(consts[0], "::TestConsts::zero", "zero", "Byte", 0) - checkConst(consts[1], "::TestConsts::b", "b", "Byte", -1) - checkConst(consts[2], "::TestConsts::o", "o", "Octet", 2) - checkConst(consts[3], "::TestConsts::s", "s", "Short", -3) - checkConst(consts[4], "::TestConsts::us", "us", "UnsignedShort", 4) - checkConst(consts[5], "::TestConsts::l", "l", "Long", -5) - checkConst(consts[6], "::TestConsts::ul", "ul", "UnsignedLong", 6) - checkConst(consts[7], "::TestConsts::ull", "ull", "UnsignedLongLong", 7) - checkConst(consts[8], "::TestConsts::ll", "ll", "LongLong", -8) - checkConst(consts[9], "::TestConsts::t", "t", "Boolean", True) - checkConst(consts[10], "::TestConsts::f", "f", "Boolean", False) - checkConst(consts[11], "::TestConsts::n", "n", "BooleanOrNull", None) - checkConst(consts[12], "::TestConsts::nt", "nt", "BooleanOrNull", True) - checkConst(consts[13], "::TestConsts::nf", "nf", "BooleanOrNull", False) - diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py index 192c5f6f97b..2b09ae71e69 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py @@ -26,3 +26,11 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + parser.parse(""" + [NoInterfaceObject, NamedConstructor=FooBar] + interface TestNamedConstructorNoInterfaceObject { + }; + """) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_date.py b/components/script/dom/bindings/codegen/parser/tests/test_date.py new file mode 100644 index 00000000000..2bdfc95e14f --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_date.py @@ -0,0 +1,15 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + interface WithDates { + attribute Date foo; + void bar(Date arg); + void baz(sequence<Date> arg); + }; + """) + + results = parser.finish() + harness.ok(results[0].members[0].type.isDate(), "Should have Date") + harness.ok(results[0].members[1].signatures()[0][1][0].type.isDate(), + "Should have Date argument") + harness.ok(not results[0].members[2].signatures()[0][1][0].type.isDate(), + "Should have non-Date argument") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py index 9ae9eb2b66f..2c0fa61239d 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py @@ -113,14 +113,16 @@ def WebIDLTest(parser, harness): try: parser.parse(""" dictionary A { - [TreatUndefinedAs=EmptyString] DOMString foo; + }; + interface X { + void doFoo(A arg); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Should not allow [TreatUndefinedAs] on dictionary members"); + harness.ok(threw, "Trailing dictionary arg must be optional") parser = parser.reset() threw = False @@ -129,14 +131,15 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo(A arg); + void doFoo((A or DOMString) arg); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Trailing dictionary arg must be optional") + harness.ok(threw, + "Trailing union arg containing a dictionary must be optional") parser = parser.reset() threw = False @@ -155,6 +158,41 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Dictionary arg followed by optional arg must be optional") parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(A arg1, optional long arg2, long arg3); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, + "Dictionary arg followed by non-optional arg doesn't have to be optional") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo((A or DOMString) arg1, optional long arg2); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Union arg containing dictionary followed by optional arg must " + "be optional") + + parser = parser.reset() parser.parse(""" dictionary A { }; @@ -188,7 +226,7 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo((A or long)? arg1); + void doFoo(optional (A or long)? arg1); }; """) results = parser.finish() @@ -196,3 +234,322 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Dictionary arg must not be in a nullable union") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional (A or long?) arg1); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Dictionary must not be in a union with a nullable type") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional (long? or A) arg1); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "A nullable type must not be in a union with a dictionary") + + parser = parser.reset() + parser.parse(""" + dictionary A { + }; + interface X { + A? doFoo(); + }; + """) + results = parser.finish() + harness.ok(True, "Dictionary return value can be nullable") + + parser = parser.reset() + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional A arg); + }; + """) + results = parser.finish() + harness.ok(True, "Dictionary arg should actually parse") + + parser = parser.reset() + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional (A or DOMString) arg); + }; + """) + results = parser.finish() + harness.ok(True, "Union arg containing a dictionary should actually parse") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + Foo foo; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo3 : Foo { + short d; + }; + + dictionary Foo2 : Foo3 { + boolean c; + }; + + dictionary Foo1 : Foo2 { + long a; + }; + + dictionary Foo { + Foo1 b; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a Dictionary that " + "inherits from its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + (Foo or DOMString)[]? b; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a Nullable type " + "whose inner type includes its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + (DOMString or Foo) b; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a Union type, one of " + "whose member types includes its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + sequence<sequence<sequence<Foo>>> c; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a Sequence type " + "whose element type includes its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + (DOMString or Foo)[] d; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be an Array type " + "whose element type includes its Dictionary.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Foo { + Foo1 b; + }; + + dictionary Foo3 { + Foo d; + }; + + dictionary Foo2 : Foo3 { + short c; + }; + + dictionary Foo1 : Foo2 { + long a; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a Dictionary, one of whose " + "members or inherited members has a type that includes " + "its Dictionary.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + }; + + dictionary Bar { + Foo? d; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Member type must not be a nullable dictionary") + + parser = parser.reset(); + parser.parse(""" + dictionary Foo { + unrestricted float urFloat = 0; + unrestricted float urFloat2 = 1.1; + unrestricted float urFloat3 = -1.1; + unrestricted float? urFloat4 = null; + unrestricted float infUrFloat = Infinity; + unrestricted float negativeInfUrFloat = -Infinity; + unrestricted float nanUrFloat = NaN; + + unrestricted double urDouble = 0; + unrestricted double urDouble2 = 1.1; + unrestricted double urDouble3 = -1.1; + unrestricted double? urDouble4 = null; + unrestricted double infUrDouble = Infinity; + unrestricted double negativeInfUrDouble = -Infinity; + unrestricted double nanUrDouble = NaN; + }; + """) + results = parser.finish() + harness.ok(True, "Parsing default values for unrestricted types succeeded.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + double f = Infinity; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to Infinity") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + double f = -Infinity; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to -Infinity") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + double f = NaN; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to NaN") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + float f = Infinity; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to Infinity") + + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + float f = -Infinity; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to -Infinity") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + float f = NaN; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Only unrestricted values can be initialized to NaN") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py index 86847800631..866816f2e0c 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -148,3 +148,149 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should throw when there is no distinguishing index") + + # Now let's test our whole distinguishability table + argTypes = [ "long", "short", "long?", "short?", "boolean", + "boolean?", "DOMString", "ByteString", "Enum", "Enum2", + "Interface", "Interface?", + "AncestorInterface", "UnrelatedInterface", + "ImplementedInterface", "CallbackInterface", + "CallbackInterface?", "CallbackInterface2", + "object", "Callback", "Callback2", "optional Dict", + "optional Dict2", "sequence<long>", "sequence<short>", + "MozMap<object>", "MozMap<Dict>", "MozMap<long>", + "long[]", "short[]", "Date", "Date?", "any", + "Promise<any>", "Promise<any>?", + "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", + "Uint8Array", "Uint16Array" ] + # When we can parse Date and RegExp, we need to add them here. + + # Try to categorize things a bit to keep list lengths down + def allBut(list1, list2): + return [a for a in list1 if a not in list2 and + (a != "any" and a != "Promise<any>" and a != "Promise<any>?")] + numerics = [ "long", "short", "long?", "short?" ] + booleans = [ "boolean", "boolean?" ] + primitives = numerics + booleans + nonNumerics = allBut(argTypes, numerics) + nonBooleans = allBut(argTypes, booleans) + strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ] + nonStrings = allBut(argTypes, strings) + nonObjects = primitives + strings + objects = allBut(argTypes, nonObjects ) + bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"] + sharedBufferSourceTypes = ["SharedArrayBuffer"] + interfaces = [ "Interface", "Interface?", "AncestorInterface", + "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes + nullables = ["long?", "short?", "boolean?", "Interface?", + "CallbackInterface?", "optional Dict", "optional Dict2", + "Date?", "any", "Promise<any>?"] + dates = [ "Date", "Date?" ] + sequences = [ "sequence<long>", "sequence<short>" ] + arrays = [ "long[]", "short[]" ] + nonUserObjects = nonObjects + interfaces + dates + sequences + otherObjects = allBut(argTypes, nonUserObjects + ["object"]) + notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + + otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes) + mozMaps = [ "MozMap<object>", "MozMap<Dict>", "MozMap<long>" ] + + # Build a representation of the distinguishability table as a dict + # of dicts, holding True values where needed, holes elsewhere. + data = dict(); + for type in argTypes: + data[type] = dict() + def setDistinguishable(type, types): + for other in types: + data[type][other] = True + + setDistinguishable("long", nonNumerics) + setDistinguishable("short", nonNumerics) + setDistinguishable("long?", allBut(nonNumerics, nullables)) + setDistinguishable("short?", allBut(nonNumerics, nullables)) + setDistinguishable("boolean", nonBooleans) + setDistinguishable("boolean?", allBut(nonBooleans, nullables)) + setDistinguishable("DOMString", nonStrings) + setDistinguishable("ByteString", nonStrings) + setDistinguishable("USVString", nonStrings) + setDistinguishable("Enum", nonStrings) + setDistinguishable("Enum2", nonStrings) + setDistinguishable("Interface", notRelatedInterfaces) + setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables)) + setDistinguishable("AncestorInterface", notRelatedInterfaces) + setDistinguishable("UnrelatedInterface", + allBut(argTypes, ["object", "UnrelatedInterface"])) + setDistinguishable("ImplementedInterface", notRelatedInterfaces) + setDistinguishable("CallbackInterface", nonUserObjects) + setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables)) + setDistinguishable("CallbackInterface2", nonUserObjects) + setDistinguishable("object", nonObjects) + setDistinguishable("Callback", nonUserObjects) + setDistinguishable("Callback2", nonUserObjects) + setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) + setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) + setDistinguishable("sequence<long>", + allBut(argTypes, sequences + arrays + ["object"])) + setDistinguishable("sequence<short>", + allBut(argTypes, sequences + arrays + ["object"])) + setDistinguishable("MozMap<object>", nonUserObjects) + setDistinguishable("MozMap<Dict>", nonUserObjects) + setDistinguishable("MozMap<long>", nonUserObjects) + setDistinguishable("long[]", allBut(nonUserObjects, sequences)) + setDistinguishable("short[]", allBut(nonUserObjects, sequences)) + setDistinguishable("Date", allBut(argTypes, dates + ["object"])) + setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) + setDistinguishable("any", []) + setDistinguishable("Promise<any>", []) + setDistinguishable("Promise<any>?", []) + setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"])) + setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"])) + setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"])) + setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"])) + setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"])) + + def areDistinguishable(type1, type2): + return data[type1].get(type2, False) + + def checkDistinguishability(parser, type1, type2): + idlTemplate = """ + enum Enum { "a", "b" }; + enum Enum2 { "c", "d" }; + interface Interface : AncestorInterface {}; + interface AncestorInterface {}; + interface UnrelatedInterface {}; + interface ImplementedInterface {}; + Interface implements ImplementedInterface; + callback interface CallbackInterface {}; + callback interface CallbackInterface2 {}; + callback Callback = any(); + callback Callback2 = long(short arg); + dictionary Dict {}; + dictionary Dict2 {}; + interface _Promise {}; + interface TestInterface {%s + }; + """ + methodTemplate = """ + void myMethod(%s arg);""" + methods = (methodTemplate % type1) + (methodTemplate % type2) + idl = idlTemplate % methods + parser = parser.reset() + threw = False + try: + parser.parse(idl) + results = parser.finish() + except: + threw = True + + if areDistinguishable(type1, type2): + harness.ok(not threw, + "Should not throw for '%s' and '%s' because they are distinguishable" % (type1, type2)) + else: + harness.ok(threw, + "Should throw for '%s' and '%s' because they are not distinguishable" % (type1, type2)) + + # Enumerate over everything in both orders, since order matters in + # terms of our implementation of distinguishability checks + for type1 in argTypes: + for type2 in argTypes: + checkDistinguishability(parser, type1, type2) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py b/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py new file mode 100644 index 00000000000..350ae72f022 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py @@ -0,0 +1,45 @@ +import WebIDL + +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface X { + const sequence<long> foo = []; + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Constant cannot have [] as a default value") + + parser = parser.reset() + + parser.parse(""" + interface X { + void foo(optional sequence<long> arg = []); + }; + """) + results = parser.finish(); + + harness.ok(isinstance( + results[0].members[0].signatures()[0][1][0].defaultValue, + WebIDL.IDLEmptySequenceValue), + "Should have IDLEmptySequenceValue as default value of argument") + + parser = parser.reset() + + parser.parse(""" + dictionary X { + sequence<long> foo = []; + }; + """) + results = parser.finish(); + + harness.ok(isinstance(results[0].members[0].defaultValue, + WebIDL.IDLEmptySequenceValue), + "Should have IDLEmptySequenceValue as default value of " + "dictionary member") + diff --git a/components/script/dom/bindings/codegen/parser/tests/test_enum.py b/components/script/dom/bindings/codegen/parser/tests/test_enum.py index 69a6932062d..86228939181 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_enum.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_enum.py @@ -79,3 +79,15 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow a bogus default value for an enum") + + # Now reset our parser + parser = parser.reset() + parser.parse(""" + enum Enum { + "a", + "b", + "c", + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should allow trailing comma in enum") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py b/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py new file mode 100644 index 00000000000..48957098bfe --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py @@ -0,0 +1,222 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + [PrimaryGlobal] interface Foo {}; + [Global=(Bar1,Bar2)] interface Bar {}; + [Global=Baz2] interface Baz {}; + + [Exposed=(Foo,Bar1)] + interface Iface { + void method1(); + + [Exposed=Bar1] + readonly attribute any attr; + }; + + [Exposed=Foo] + partial interface Iface { + void method2(); + }; + """) + + results = parser.finish() + + harness.check(len(results), 5, "Should know about five things"); + iface = results[3] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should have an interface here"); + members = iface.members + harness.check(len(members), 3, "Should have three members") + + harness.ok(members[0].exposureSet == set(["Foo", "Bar"]), + "method1 should have the right exposure set") + harness.ok(members[0]._exposureGlobalNames == set(["Foo", "Bar1"]), + "method1 should have the right exposure global names") + + harness.ok(members[1].exposureSet == set(["Bar"]), + "attr should have the right exposure set") + harness.ok(members[1]._exposureGlobalNames == set(["Bar1"]), + "attr should have the right exposure global names") + + harness.ok(members[2].exposureSet == set(["Foo"]), + "method2 should have the right exposure set") + harness.ok(members[2]._exposureGlobalNames == set(["Foo"]), + "method2 should have the right exposure global names") + + harness.ok(iface.exposureSet == set(["Foo", "Bar"]), + "Iface should have the right exposure set") + harness.ok(iface._exposureGlobalNames == set(["Foo", "Bar1"]), + "Iface should have the right exposure global names") + + parser = parser.reset() + parser.parse(""" + [PrimaryGlobal] interface Foo {}; + [Global=(Bar1,Bar2)] interface Bar {}; + [Global=Baz2] interface Baz {}; + + interface Iface2 { + void method3(); + }; + """) + results = parser.finish() + + harness.check(len(results), 4, "Should know about four things"); + iface = results[3] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should have an interface here"); + members = iface.members + harness.check(len(members), 1, "Should have one member") + + harness.ok(members[0].exposureSet == set(["Foo"]), + "method3 should have the right exposure set") + harness.ok(members[0]._exposureGlobalNames == set(["Foo"]), + "method3 should have the right exposure global names") + + harness.ok(iface.exposureSet == set(["Foo"]), + "Iface2 should have the right exposure set") + harness.ok(iface._exposureGlobalNames == set(["Foo"]), + "Iface2 should have the right exposure global names") + + parser = parser.reset() + parser.parse(""" + [PrimaryGlobal] interface Foo {}; + [Global=(Bar1,Bar2)] interface Bar {}; + [Global=Baz2] interface Baz {}; + + [Exposed=Foo] + interface Iface3 { + void method4(); + }; + + [Exposed=(Foo,Bar1)] + interface Mixin { + void method5(); + }; + + Iface3 implements Mixin; + """) + results = parser.finish() + harness.check(len(results), 6, "Should know about six things"); + iface = results[3] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should have an interface here"); + members = iface.members + harness.check(len(members), 2, "Should have two members") + + harness.ok(members[0].exposureSet == set(["Foo"]), + "method4 should have the right exposure set") + harness.ok(members[0]._exposureGlobalNames == set(["Foo"]), + "method4 should have the right exposure global names") + + harness.ok(members[1].exposureSet == set(["Foo", "Bar"]), + "method5 should have the right exposure set") + harness.ok(members[1]._exposureGlobalNames == set(["Foo", "Bar1"]), + "method5 should have the right exposure global names") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Exposed=Foo] + interface Bar { + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on invalid Exposed value on interface.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Bar { + [Exposed=Foo] + readonly attribute bool attr; + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on invalid Exposed value on attribute.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Bar { + [Exposed=Foo] + void operation(); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on invalid Exposed value on operation.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Bar { + [Exposed=Foo] + const long constant = 5; + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on invalid Exposed value on constant.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] interface Foo {}; + [Global] interface Bar {}; + + [Exposed=Foo] + interface Baz { + [Exposed=Bar] + void method(); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on member exposed where its interface is not.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] interface Foo {}; + [Global] interface Bar {}; + + [Exposed=Foo] + interface Baz { + void method(); + }; + + [Exposed=Bar] + interface Mixin {}; + + Baz implements Mixin; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown on LHS of implements being exposed where RHS is not.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_float_types.py b/components/script/dom/bindings/codegen/parser/tests/test_float_types.py new file mode 100644 index 00000000000..718f09c114b --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_float_types.py @@ -0,0 +1,125 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + typedef float myFloat; + typedef unrestricted float myUnrestrictedFloat; + interface FloatTypes { + attribute float f; + attribute unrestricted float uf; + attribute double d; + attribute unrestricted double ud; + [LenientFloat] + attribute float lf; + [LenientFloat] + attribute double ld; + + void m1(float arg1, double arg2, float? arg3, double? arg4, + myFloat arg5, unrestricted float arg6, + unrestricted double arg7, unrestricted float? arg8, + unrestricted double? arg9, myUnrestrictedFloat arg10); + [LenientFloat] + void m2(float arg1, double arg2, float? arg3, double? arg4, + myFloat arg5, unrestricted float arg6, + unrestricted double arg7, unrestricted float? arg8, + unrestricted double? arg9, myUnrestrictedFloat arg10); + [LenientFloat] + void m3(float arg); + [LenientFloat] + void m4(double arg); + [LenientFloat] + void m5((float or FloatTypes) arg); + [LenientFloat] + void m6(sequence<float> arg); + }; + """) + + results = parser.finish() + + harness.check(len(results), 3, "Should be two typedefs and one interface.") + iface = results[2] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + types = [a.type for a in iface.members if a.isAttr()] + harness.ok(types[0].isFloat(), "'float' is a float") + harness.ok(not types[0].isUnrestricted(), "'float' is not unrestricted") + harness.ok(types[1].isFloat(), "'unrestricted float' is a float") + harness.ok(types[1].isUnrestricted(), "'unrestricted float' is unrestricted") + harness.ok(types[2].isFloat(), "'double' is a float") + harness.ok(not types[2].isUnrestricted(), "'double' is not unrestricted") + harness.ok(types[3].isFloat(), "'unrestricted double' is a float") + harness.ok(types[3].isUnrestricted(), "'unrestricted double' is unrestricted") + + method = iface.members[6] + harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") + argtypes = [a.type for a in method.signatures()[0][1]] + for (idx, type) in enumerate(argtypes): + harness.ok(type.isFloat(), "Type %d should be float" % idx) + harness.check(type.isUnrestricted(), idx >= 5, + "Type %d should %sbe unrestricted" % ( + idx, "" if idx >= 4 else "not ")) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface FloatTypes { + [LenientFloat] + long m(float arg); + }; + """) + except Exception, x: + threw = True + harness.ok(threw, "[LenientFloat] only allowed on void methods") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface FloatTypes { + [LenientFloat] + void m(unrestricted float arg); + }; + """) + except Exception, x: + threw = True + harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface FloatTypes { + [LenientFloat] + void m(sequence<unrestricted float> arg); + }; + """) + except Exception, x: + threw = True + harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (2)") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface FloatTypes { + [LenientFloat] + void m((unrestricted float or FloatTypes) arg); + }; + """) + except Exception, x: + threw = True + harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (3)") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface FloatTypes { + [LenientFloat] + readonly attribute float foo; + }; + """) + except Exception, x: + threw = True + harness.ok(threw, "[LenientFloat] only allowed on writable attributes") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py new file mode 100644 index 00000000000..c752cecd298 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py @@ -0,0 +1,122 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + [Global] + interface Foo : Bar { + getter any(DOMString name); + }; + interface Bar {}; + """) + + results = parser.finish() + + harness.ok(results[0].isOnGlobalProtoChain(), + "[Global] interface should be on global's proto chain") + harness.ok(results[1].isOnGlobalProtoChain(), + "[Global] interface should be on global's proto chain") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + setter void(DOMString name, any arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named setter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + creator void(DOMString name, any arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named creator") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + deleter void(DOMString name); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named deleter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global, OverrideBuiltins] + interface Foo { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "[OverrideBuiltins]") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo : Bar { + }; + [OverrideBuiltins] + interface Bar { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with an " + "[OverrideBuiltins] ancestor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + }; + interface Bar : Foo { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "descendant") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_interface.py index 5b07172c636..e8ed67b54b3 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -186,3 +186,220 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow inheriting from an interface that is only forward declared") + + parser = parser.reset() + parser.parse(""" + [Constructor(long arg)] + interface A { + readonly attribute boolean x; + void foo(); + }; + [Constructor] + partial interface A { + readonly attribute boolean y; + void foo(long arg); + }; + """); + results = parser.finish(); + harness.check(len(results), 2, + "Should have two results with partial interface") + iface = results[0] + harness.check(len(iface.members), 3, + "Should have three members with partial interface") + harness.check(iface.members[0].identifier.name, "x", + "First member should be x with partial interface") + harness.check(iface.members[1].identifier.name, "foo", + "Second member should be foo with partial interface") + harness.check(len(iface.members[1].signatures()), 2, + "Should have two foo signatures with partial interface") + harness.check(iface.members[2].identifier.name, "y", + "Third member should be y with partial interface") + harness.check(len(iface.ctor().signatures()), 2, + "Should have two constructors with partial interface") + + parser = parser.reset() + parser.parse(""" + [Constructor] + partial interface A { + readonly attribute boolean y; + void foo(long arg); + }; + [Constructor(long arg)] + interface A { + readonly attribute boolean x; + void foo(); + }; + """); + results = parser.finish(); + harness.check(len(results), 2, + "Should have two results with reversed partial interface") + iface = results[1] + harness.check(len(iface.members), 3, + "Should have three members with reversed partial interface") + harness.check(iface.members[0].identifier.name, "x", + "First member should be x with reversed partial interface") + harness.check(iface.members[1].identifier.name, "foo", + "Second member should be foo with reversed partial interface") + harness.check(len(iface.members[1].signatures()), 2, + "Should have two foo signatures with reversed partial interface") + harness.check(iface.members[2].identifier.name, "y", + "Third member should be y with reversed partial interface") + harness.check(len(iface.ctor().signatures()), 2, + "Should have two constructors with reversed partial interface") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + readonly attribute boolean x; + }; + interface A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow two non-partial interfaces with the same name") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + partial interface A { + readonly attribute boolean x; + }; + partial interface A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Must have a non-partial interface for a given name") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + boolean x; + }; + partial interface A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between partial interface " + "and other object") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + boolean x; + }; + interface A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between interface " + "and other object") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + boolean x; + }; + interface A; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between external interface " + "and other object") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + readonly attribute boolean x; + }; + interface A; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between external interface " + "and interface") + + parser = parser.reset() + parser.parse(""" + interface A; + interface A; + """) + results = parser.finish() + harness.ok(len(results) == 1 and + isinstance(results[0], WebIDL.IDLExternalInterface), + "Should allow name collisions between external interface " + "declarations") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SomeRandomAnnotation] + interface A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow unknown extended attributes on interfaces") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface B {}; + [ArrayClass] + interface A : B { + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [ArrayClass] on interfaces with parents") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ArrayClass] + interface A { + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, + "Should allow [ArrayClass] on interfaces without parents") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py b/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py new file mode 100644 index 00000000000..159b50f84ff --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py @@ -0,0 +1,594 @@ +import WebIDL +import traceback +def WebIDLTest(parser, harness): + + def shouldPass(prefix, iface, expectedMembers, numProductions=1): + p = parser.reset() + p.parse(iface) + results = p.finish() + harness.check(len(results), numProductions, + "%s - Should have production count %d" % (prefix, numProductions)) + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "%s - Should be an IDLInterface" % (prefix)) + # Make a copy, since we plan to modify it + expectedMembers = list(expectedMembers) + for m in results[0].members: + name = m.identifier.name + if (name, type(m)) in expectedMembers: + harness.ok(True, "%s - %s - Should be a %s" % (prefix, name, + type(m))) + expectedMembers.remove((name, type(m))) + else: + harness.ok(False, "%s - %s - Unknown symbol of type %s" % + (prefix, name, type(m))) + # A bit of a hoop because we can't generate the error string if we pass + if len(expectedMembers) == 0: + harness.ok(True, "Found all the members") + else: + harness.ok(False, + "Expected member not found: %s of type %s" % + (expectedMembers[0][0], expectedMembers[0][1])) + return results + + def shouldFail(prefix, iface): + try: + p = parser.reset() + p.parse(iface) + p.finish() + harness.ok(False, + prefix + " - Interface passed when should've failed") + except WebIDL.WebIDLError, e: + harness.ok(True, + prefix + " - Interface failed as expected") + except Exception, e: + harness.ok(False, + prefix + " - Interface failed but not as a WebIDLError exception: %s" % e) + + iterableMembers = [(x, WebIDL.IDLMethod) for x in ["entries", "keys", + "values", "forEach"]] + setROMembers = ([(x, WebIDL.IDLMethod) for x in ["has"]] + + [("__setlike", WebIDL.IDLMaplikeOrSetlike)] + + iterableMembers) + setROMembers.extend([("size", WebIDL.IDLAttribute)]) + setRWMembers = ([(x, WebIDL.IDLMethod) for x in ["add", + "clear", + "delete"]] + + setROMembers) + setROChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add", + "__clear", + "__delete"]] + + setROMembers) + setRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add", + "__clear", + "__delete"]] + + setRWMembers) + mapROMembers = ([(x, WebIDL.IDLMethod) for x in ["get", "has"]] + + [("__maplike", WebIDL.IDLMaplikeOrSetlike)] + + iterableMembers) + mapROMembers.extend([("size", WebIDL.IDLAttribute)]) + mapRWMembers = ([(x, WebIDL.IDLMethod) for x in ["set", + "clear", + "delete"]] + mapROMembers) + mapRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__set", + "__clear", + "__delete"]] + + mapRWMembers) + + # OK, now that we've used iterableMembers to set up the above, append + # __iterable to it for the iterable<> case. + iterableMembers.append(("__iterable", WebIDL.IDLIterable)) + + valueIterableMembers = [("__iterable", WebIDL.IDLIterable)] + valueIterableMembers.append(("__indexedgetter", WebIDL.IDLMethod)) + valueIterableMembers.append(("length", WebIDL.IDLAttribute)) + + disallowedIterableNames = ["keys", "entries", "values"] + disallowedMemberNames = ["forEach", "has", "size"] + disallowedIterableNames + mapDisallowedMemberNames = ["get"] + disallowedMemberNames + disallowedNonMethodNames = ["clear", "delete"] + mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames + setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames + + # + # Simple Usage Tests + # + + shouldPass("Iterable (key only)", + """ + interface Foo1 { + iterable<long>; + readonly attribute unsigned long length; + getter long(unsigned long index); + }; + """, valueIterableMembers) + + shouldPass("Iterable (key and value)", + """ + interface Foo1 { + iterable<long, long>; + }; + """, iterableMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2) + + shouldPass("Maplike (readwrite)", + """ + interface Foo1 { + maplike<long, long>; + }; + """, mapRWMembers) + + shouldPass("Maplike (readwrite)", + """ + interface Foo1 { + maplike<long, long>; + }; + """, mapRWMembers) + + shouldPass("Maplike (readonly)", + """ + interface Foo1 { + readonly maplike<long, long>; + }; + """, mapROMembers) + + shouldPass("Setlike (readwrite)", + """ + interface Foo1 { + setlike<long>; + }; + """, setRWMembers) + + shouldPass("Setlike (readonly)", + """ + interface Foo1 { + readonly setlike<long>; + }; + """, setROMembers) + + shouldPass("Inheritance of maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + }; + """, mapRWMembers, numProductions=2) + + shouldPass("Implements with maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + }; + Foo2 implements Foo1; + """, mapRWMembers, numProductions=3) + + shouldPass("JS Implemented maplike interface", + """ + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", + Constructor()] + interface Foo1 { + setlike<long>; + }; + """, setRWChromeMembers) + + shouldPass("JS Implemented maplike interface", + """ + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", + Constructor()] + interface Foo1 { + maplike<long, long>; + }; + """, mapRWChromeMembers) + + # + # Multiple maplike/setlike tests + # + + shouldFail("Two maplike/setlikes on same interface", + """ + interface Foo1 { + setlike<long>; + maplike<long, long>; + }; + """) + + shouldFail("Two iterable/setlikes on same interface", + """ + interface Foo1 { + iterable<long>; + maplike<long, long>; + }; + """) + + shouldFail("Two iterables on same interface", + """ + interface Foo1 { + iterable<long>; + iterable<long, long>; + }; + """) + + shouldFail("Two maplike/setlikes in partials", + """ + interface Foo1 { + maplike<long, long>; + }; + partial interface Foo1 { + setlike<long>; + }; + """) + + shouldFail("Conflicting maplike/setlikes across inheritance", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + setlike<long>; + }; + """) + + shouldFail("Conflicting maplike/iterable across inheritance", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + iterable<long>; + }; + """) + + shouldFail("Conflicting maplike/setlikes across multistep inheritance", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + setlike<long>; + }; + """) + + shouldFail("Consequential interface with conflicting maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + setlike<long>; + }; + Foo2 implements Foo1; + """) + + shouldFail("Consequential interfaces with conflicting maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + setlike<long>; + }; + interface Foo3 { + }; + Foo3 implements Foo1; + Foo3 implements Foo2; + """) + + # + # Member name collision tests + # + + def testConflictingMembers(likeMember, conflictName, expectedMembers, methodPasses): + """ + Tests for maplike/setlike member generation against conflicting member + names. If methodPasses is True, this means we expect the interface to + pass in the case of method shadowing, and expectedMembers should be the + list of interface members to check against on the passing interface. + + """ + if methodPasses: + shouldPass("Conflicting method: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s; + [Throws] + void %s(long test1, double test2, double test3); + }; + """ % (likeMember, conflictName), expectedMembers) + else: + shouldFail("Conflicting method: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s; + [Throws] + void %s(long test1, double test2, double test3); + }; + """ % (likeMember, conflictName)) + # Inherited conflicting methods should ALWAYS fail + shouldFail("Conflicting inherited method: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + void %s(long test1, double test2, double test3); + }; + interface Foo2 : Foo1 { + %s; + }; + """ % (conflictName, likeMember)) + shouldFail("Conflicting static method: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s; + static void %s(long test1, double test2, double test3); + }; + """ % (likeMember, conflictName)) + shouldFail("Conflicting attribute: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s + attribute double %s; + }; + """ % (likeMember, conflictName)) + shouldFail("Conflicting const: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s; + const double %s = 0; + }; + """ % (likeMember, conflictName)) + shouldFail("Conflicting static attribute: %s and %s" % (likeMember, conflictName), + """ + interface Foo1 { + %s; + static attribute long %s; + }; + """ % (likeMember, conflictName)) + + for member in disallowedIterableNames: + testConflictingMembers("iterable<long, long>", member, iterableMembers, False) + for member in mapDisallowedMemberNames: + testConflictingMembers("maplike<long, long>", member, mapRWMembers, False) + for member in disallowedMemberNames: + testConflictingMembers("setlike<long>", member, setRWMembers, False) + for member in mapDisallowedNonMethodNames: + testConflictingMembers("maplike<long, long>", member, mapRWMembers, True) + for member in setDisallowedNonMethodNames: + testConflictingMembers("setlike<long>", member, setRWMembers, True) + + shouldPass("Inheritance of maplike/setlike with child member collision", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + void entries(); + }; + """, mapRWMembers, numProductions=2) + + shouldPass("Inheritance of multi-level maplike/setlike with child member collision", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + void entries(); + }; + """, mapRWMembers, numProductions=3) + + shouldFail("Interface with consequential maplike/setlike interface member collision", + """ + interface Foo1 { + void entries(); + }; + interface Foo2 { + maplike<long, long>; + }; + Foo1 implements Foo2; + """) + + shouldFail("Maplike interface with consequential interface member collision", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + void entries(); + }; + Foo1 implements Foo2; + """) + + shouldPass("Consequential Maplike interface with inherited interface member collision", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + void entries(); + }; + interface Foo3 : Foo2 { + }; + Foo3 implements Foo1; + """, mapRWMembers, numProductions=4) + + shouldPass("Inherited Maplike interface with consequential interface member collision", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 { + void entries(); + }; + interface Foo3 : Foo1 { + }; + Foo3 implements Foo2; + """, mapRWMembers, numProductions=4) + + shouldFail("Inheritance of name collision with child maplike/setlike", + """ + interface Foo1 { + void entries(); + }; + interface Foo2 : Foo1 { + maplike<long, long>; + }; + """) + + shouldFail("Inheritance of multi-level name collision with child maplike/setlike", + """ + interface Foo1 { + void entries(); + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + maplike<long, long>; + }; + """) + + shouldPass("Inheritance of attribute collision with parent maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + attribute double size; + }; + """, mapRWMembers, numProductions=2) + + shouldPass("Inheritance of multi-level attribute collision with parent maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + attribute double size; + }; + """, mapRWMembers, numProductions=3) + + shouldFail("Inheritance of attribute collision with child maplike/setlike", + """ + interface Foo1 { + attribute double size; + }; + interface Foo2 : Foo1 { + maplike<long, long>; + }; + """) + + shouldFail("Inheritance of multi-level attribute collision with child maplike/setlike", + """ + interface Foo1 { + attribute double size; + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + maplike<long, long>; + }; + """) + + shouldFail("Inheritance of attribute/rw function collision with child maplike/setlike", + """ + interface Foo1 { + attribute double set; + }; + interface Foo2 : Foo1 { + maplike<long, long>; + }; + """) + + shouldFail("Inheritance of const/rw function collision with child maplike/setlike", + """ + interface Foo1 { + const double set = 0; + }; + interface Foo2 : Foo1 { + maplike<long, long>; + }; + """) + + shouldPass("Inheritance of rw function with same name in child maplike/setlike", + """ + interface Foo1 { + maplike<long, long>; + }; + interface Foo2 : Foo1 { + void clear(); + }; + """, mapRWMembers, numProductions=2) + + shouldFail("Inheritance of unforgeable attribute collision with child maplike/setlike", + """ + interface Foo1 { + [Unforgeable] + attribute double size; + }; + interface Foo2 : Foo1 { + maplike<long, long>; + }; + """) + + shouldFail("Inheritance of multi-level unforgeable attribute collision with child maplike/setlike", + """ + interface Foo1 { + [Unforgeable] + attribute double size; + }; + interface Foo2 : Foo1 { + }; + interface Foo3 : Foo2 { + maplike<long, long>; + }; + """) + + shouldPass("Implemented interface with readonly allowable overrides", + """ + interface Foo1 { + readonly setlike<long>; + readonly attribute boolean clear; + }; + """, setROMembers + [("clear", WebIDL.IDLAttribute)]) + + shouldPass("JS Implemented read-only interface with readonly allowable overrides", + """ + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", + Constructor()] + interface Foo1 { + readonly setlike<long>; + readonly attribute boolean clear; + }; + """, setROChromeMembers + [("clear", WebIDL.IDLAttribute)]) + + shouldFail("JS Implemented read-write interface with non-readwrite allowable overrides", + """ + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", + Constructor()] + interface Foo1 { + setlike<long>; + readonly attribute boolean clear; + }; + """) + + r = shouldPass("Check proper override of clear/delete/set", + """ + interface Foo1 { + maplike<long, long>; + long clear(long a, long b, double c, double d); + long set(long a, long b, double c, double d); + long delete(long a, long b, double c, double d); + }; + """, mapRWMembers) + + for m in r[0].members: + if m.identifier.name in ["clear", "set", "delete"]: + harness.ok(m.isMethod(), "%s should be a method" % m.identifier.name) + harness.check(m.maxArgCount, 4, "%s should have 4 arguments" % m.identifier.name) + harness.ok(not m.isMaplikeOrSetlikeOrIterableMethod(), + "%s should not be a maplike/setlike function" % m.identifier.name) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_method.py b/components/script/dom/bindings/codegen/parser/tests/test_method.py index 40b2d2cf8b9..f6f54c33ab6 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_method.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_method.py @@ -123,23 +123,62 @@ def WebIDLTest(parser, harness): try: parser.parse(""" interface A { - [GetterInfallible] void foo(); + void foo(optional float bar = 1); }; """) results = parser.finish() except Exception, x: threw = True - harness.ok(threw, "Should not allow [GetterInfallible] on methods") + harness.ok(not threw, "Should allow integer to float type corecion") parser = parser.reset() threw = False try: parser.parse(""" interface A { - [SetterInfallible] void foo(); + [GetterThrows] void foo(); }; """) results = parser.finish() except Exception, x: threw = True - harness.ok(threw, "Should not allow [SetterInfallible] on methods") + harness.ok(threw, "Should not allow [GetterThrows] on methods") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [SetterThrows] void foo(); + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should not allow [SetterThrows] on methods") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throw] void foo(); + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should spell [Throws] correctly on methods") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + void __noSuchMethod__(); + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should not allow __noSuchMethod__ methods") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py b/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py new file mode 100644 index 00000000000..1a36fdd62c4 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py @@ -0,0 +1,39 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict {}; + interface MozMapArg { + void foo(MozMap<Dict> arg); + }; + """) + + results = parser.finish() + + harness.check(len(results), 2, "Should know about two things"); + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should have an interface here"); + members = results[1].members + harness.check(len(members), 1, "Should have one member") + harness.ok(members[0].isMethod(), "Should have method") + signature = members[0].signatures()[0] + args = signature[1] + harness.check(len(args), 1, "Should have one arg") + harness.ok(args[0].type.isMozMap(), "Should have a MozMap type here") + harness.ok(args[0].type.inner.isDictionary(), + "Should have a dictionary inner type") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface MozMapVoidArg { + void foo(MozMap<void> arg); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_overload.py b/components/script/dom/bindings/codegen/parser/tests/test_overload.py index 59d9be54e53..3c680ad5233 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_overload.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_overload.py @@ -8,6 +8,11 @@ def WebIDLTest(parser, harness): boolean abitharder(TestOverloads foo); boolean abitharder(boolean foo); void abitharder(ArrayBuffer? foo); + void withVariadics(long... numbers); + void withVariadics(TestOverloads iface); + void withVariadics(long num, TestOverloads iface); + void optionalTest(); + void optionalTest(optional long num1, long num2); }; """) @@ -20,7 +25,7 @@ def WebIDLTest(parser, harness): "Should be an IDLInterface") harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName") harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name") - harness.check(len(iface.members), 2, "Expect %s members" % 2) + harness.check(len(iface.members), 4, "Expect %s members" % 4) member = iface.members[0] harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName") @@ -45,3 +50,11 @@ def WebIDLTest(parser, harness): harness.check(argument.identifier.QName(), "::TestOverloads::basic::arg1", "Argument has the right QName") harness.check(argument.identifier.name, "arg1", "Argument has the right name") harness.check(str(argument.type), "Long", "Argument has the right type") + + member = iface.members[3] + harness.check(len(member.overloadsForArgCount(0)), 1, + "Only one overload for no args") + harness.check(len(member.overloadsForArgCount(1)), 0, + "No overloads for one arg") + harness.check(len(member.overloadsForArgCount(2)), 1, + "Only one overload for two args") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_promise.py b/components/script/dom/bindings/codegen/parser/tests/test_promise.py new file mode 100644 index 00000000000..55bc0768092 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_promise.py @@ -0,0 +1,63 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface _Promise {}; + interface A { + legacycaller Promise<any> foo(); + }; + """) + results = parser.finish() + + except: + threw = True + harness.ok(threw, + "Should not allow Promise return values for legacycaller.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface _Promise {}; + interface A { + Promise<any> foo(); + long foo(long arg); + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow overloads which have both Promise and " + "non-Promise return types.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface _Promise {}; + interface A { + long foo(long arg); + Promise<any> foo(); + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow overloads which have both Promise and " + "non-Promise return types.") + + parser = parser.reset() + parser.parse(""" + interface _Promise {}; + interface A { + Promise<any> foo(); + Promise<any> foo(long arg); + }; + """) + results = parser.finish(); + + harness.ok(True, + "Should allow overloads which only have Promise and return " + "types.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_prototype_ident.py b/components/script/dom/bindings/codegen/parser/tests/test_prototype_ident.py new file mode 100644 index 00000000000..d3932b54f8b --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_prototype_ident.py @@ -0,0 +1,80 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface TestIface { + static attribute boolean prototype; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "The identifier of a static attribute must not be 'prototype'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestIface { + static boolean prototype(); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "The identifier of a static operation must not be 'prototype'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestIface { + const boolean prototype = true; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "The identifier of a constant must not be 'prototype'") + + # Make sure that we can parse non-static attributes with 'prototype' as identifier. + parser = parser.reset() + parser.parse(""" + interface TestIface { + attribute boolean prototype; + }; + """) + results = parser.finish() + + testIface = results[0]; + harness.check(testIface.members[0].isStatic(), False, "Attribute should not be static") + harness.check(testIface.members[0].identifier.name, "prototype", "Attribute identifier should be 'prototype'") + + # Make sure that we can parse non-static operations with 'prototype' as identifier. + parser = parser.reset() + parser.parse(""" + interface TestIface { + boolean prototype(); + }; + """) + results = parser.finish() + + testIface = results[0]; + harness.check(testIface.members[0].isStatic(), False, "Operation should not be static") + harness.check(testIface.members[0].identifier.name, "prototype", "Operation identifier should be 'prototype'") + + # Make sure that we can parse dictionary members with 'prototype' as identifier. + parser = parser.reset() + parser.parse(""" + dictionary TestDict { + boolean prototype; + }; + """) + results = parser.finish() + + testDict = results[0]; + harness.check(testDict.members[0].identifier.name, "prototype", "Dictionary member should be 'prototype'") + diff --git a/components/script/dom/bindings/codegen/parser/tests/test_putForwards.py b/components/script/dom/bindings/codegen/parser/tests/test_putForwards.py new file mode 100644 index 00000000000..86a1bf115b6 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_putForwards.py @@ -0,0 +1,107 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface I { + [PutForwards=B] readonly attribute long A; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface I { + [PutForwards=B] readonly attribute J A; + }; + interface J { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface I { + [PutForwards=B] attribute J A; + }; + interface J { + attribute long B; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface I { + [PutForwards=B] static readonly attribute J A; + }; + interface J { + attribute long B; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + callback interface I { + [PutForwards=B] readonly attribute J A; + }; + interface J { + attribute long B; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface I { + [PutForwards=C] readonly attribute J A; + [PutForwards=C] readonly attribute J B; + }; + interface J { + [PutForwards=D] readonly attribute K C; + }; + interface K { + [PutForwards=A] readonly attribute I D; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py new file mode 100644 index 00000000000..93ee42ed919 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py @@ -0,0 +1,58 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +def should_throw(parser, harness, message, code): + parser = parser.reset(); + threw = False + try: + parser.parse(code) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown: %s" % message) + + +def WebIDLTest(parser, harness): + # The [Replaceable] extended attribute MUST take no arguments. + should_throw(parser, harness, "no arguments", """ + interface I { + [Replaceable=X] readonly attribute long A; + }; + """) + + # An attribute with the [Replaceable] extended attribute MUST NOT also be + # declared with the [PutForwards] extended attribute. + should_throw(parser, harness, "PutForwards", """ + interface I { + [PutForwards=B, Replaceable] readonly attribute J A; + }; + interface J { + attribute long B; + }; + """) + + # The [Replaceable] extended attribute MUST NOT be used on an attribute + # that is not read only. + should_throw(parser, harness, "writable attribute", """ + interface I { + [Replaceable] attribute long A; + }; + """) + + # The [Replaceable] extended attribute MUST NOT be used on a static + # attribute. + should_throw(parser, harness, "static attribute", """ + interface I { + [Replaceable] static readonly attribute long A; + }; + """) + + # The [Replaceable] extended attribute MUST NOT be used on an attribute + # declared on a callback interface. + should_throw(parser, harness, "callback interface", """ + callback interface I { + [Replaceable] readonly attribute long A; + }; + """) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py new file mode 100644 index 00000000000..14c2c5226fc --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py @@ -0,0 +1,46 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestStringifier { + stringifier; + }; + """) + + results = parser.finish() + + harness.ok(isinstance(results[0].members[0], WebIDL.IDLMethod), + "Stringifer should be method") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + interface TestStringifier { + stringifier; + stringifier; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow two 'stringifier;'") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + interface TestStringifier { + stringifier; + stringifier DOMString foo(); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow a 'stringifier;' and a 'stringifier()'") + diff --git a/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py b/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py new file mode 100644 index 00000000000..3787e8c6af1 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py @@ -0,0 +1,253 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + interface Child : Parent { + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, + "Should be able to inherit from an interface with " + "[Unforgeable] properties.") + + parser = parser.reset(); + parser.parse(""" + interface Child : Parent { + const short foo = 10; + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, + "Should be able to inherit from an interface with " + "[Unforgeable] properties even if we have a constant with " + "the same name.") + + parser = parser.reset(); + parser.parse(""" + interface Child : Parent { + static attribute short foo; + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, + "Should be able to inherit from an interface with " + "[Unforgeable] properties even if we have a static attribute " + "with the same name.") + + parser = parser.reset(); + parser.parse(""" + interface Child : Parent { + static void foo(); + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, + "Should be able to inherit from an interface with " + "[Unforgeable] properties even if we have a static operation " + "with the same name.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + void foo(); + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable attribute on " + "parent with operation.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + void foo(); + }; + interface Parent { + [Unforgeable] void foo(); + }; + """) + + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable operation on " + "parent with operation.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + attribute short foo; + }; + interface Parent { + [Unforgeable] readonly attribute long foo; + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable attribute on " + "parent with attribute.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + attribute short foo; + }; + interface Parent { + [Unforgeable] void foo(); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable operation on " + "parent with attribute.") + + parser = parser.reset(); + parser.parse(""" + interface Child : Parent { + }; + interface Parent {}; + interface Consequential { + [Unforgeable] readonly attribute long foo; + }; + Parent implements Consequential; + """) + + results = parser.finish() + harness.check(len(results), 4, + "Should be able to inherit from an interface with a " + "consequential interface with [Unforgeable] properties.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + void foo(); + }; + interface Parent {}; + interface Consequential { + [Unforgeable] readonly attribute long foo; + }; + Parent implements Consequential; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown when shadowing unforgeable attribute " + "of parent's consequential interface.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + }; + interface Parent : GrandParent {}; + interface GrandParent {}; + interface Consequential { + [Unforgeable] readonly attribute long foo; + }; + GrandParent implements Consequential; + interface ChildConsequential { + void foo(); + }; + Child implements ChildConsequential; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown when our consequential interface shadows unforgeable attribute " + "of ancestor's consequential interface.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + }; + interface Parent : GrandParent {}; + interface GrandParent {}; + interface Consequential { + [Unforgeable] void foo(); + }; + GrandParent implements Consequential; + interface ChildConsequential { + void foo(); + }; + Child implements ChildConsequential; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown when our consequential interface shadows unforgeable operation " + "of ancestor's consequential interface.") + + parser = parser.reset(); + parser.parse(""" + interface iface { + [Unforgeable] attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 1, + "Should allow writable [Unforgeable] attribute.") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface iface { + [Unforgeable] static readonly attribute long foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for static [Unforgeable] attribute.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_union.py b/components/script/dom/bindings/codegen/parser/tests/test_union.py index 68c2bcade8c..36cacf3ccf4 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_union.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_union.py @@ -62,6 +62,8 @@ def WebIDLTest(parser, harness): "byte", "octet", "DOMString", + "ByteString", + "USVString", #"sequence<float>", "object", "ArrayBuffer", diff --git a/components/script/dom/bindings/codegen/parser/tests/test_usvstring.py b/components/script/dom/bindings/codegen/parser/tests/test_usvstring.py new file mode 100644 index 00000000000..3a1369abd02 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_usvstring.py @@ -0,0 +1,36 @@ +# -*- coding: UTF-8 -*- + +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestUSVString { + attribute USVString svs; + }; + """) + + results = parser.finish(); + + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + iface = results[0] + harness.check(iface.identifier.QName(), "::TestUSVString", + "Interface has the right QName") + harness.check(iface.identifier.name, "TestUSVString", + "Interface has the right name") + harness.check(iface.parent, None, "Interface has no parent") + + members = iface.members + harness.check(len(members), 1, "Should be one member") + + attr = members[0] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute") + harness.check(attr.identifier.QName(), "::TestUSVString::svs", + "Attr has correct QName") + harness.check(attr.identifier.name, "svs", "Attr has correct name") + harness.check(str(attr.type), "USVString", + "Attr type is the correct name") + harness.ok(attr.type.isUSVString(), "Should be USVString type") + harness.ok(attr.type.isString(), "Should be String collective type") + harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type") diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 21491e6c02c..fc764d2300c 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -3,4 +3,8 @@ patch < abstract.patch patch < debug.patch patch < legacy-unenumerable-named-properties.patch -# TODO: update test files from https://dxr.mozilla.org/mozilla-central/source/dom/bindings/parser/tests +wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz +rm -r tests +mkdir tests +tar xvpf tests.tar.gz -C tests --strip-components=5 +rm tests.tar.gz WebIDL.py.orig |