diff options
Diffstat (limited to 'dom/bindings/parser/tests')
69 files changed, 6978 insertions, 0 deletions
diff --git a/dom/bindings/parser/tests/test_any_null.py b/dom/bindings/parser/tests/test_any_null.py new file mode 100644 index 000000000..e3b690bf6 --- /dev/null +++ b/dom/bindings/parser/tests/test_any_null.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface DoubleNull { + attribute any? foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_argument_identifier_conflicts.py b/dom/bindings/parser/tests/test_argument_identifier_conflicts.py new file mode 100644 index 000000000..eb1f6d3c9 --- /dev/null +++ b/dom/bindings/parser/tests/test_argument_identifier_conflicts.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface ArgumentIdentifierConflict { + void foo(boolean arg1, boolean arg1); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_argument_novoid.py b/dom/bindings/parser/tests/test_argument_novoid.py new file mode 100644 index 000000000..ef8c2229a --- /dev/null +++ b/dom/bindings/parser/tests/test_argument_novoid.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface VoidArgument1 { + void foo(void arg2); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_arraybuffer.py b/dom/bindings/parser/tests/test_arraybuffer.py new file mode 100644 index 000000000..4a96c0ff5 --- /dev/null +++ b/dom/bindings/parser/tests/test_arraybuffer.py @@ -0,0 +1,81 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestArrayBuffer { + attribute ArrayBuffer bufferAttr; + void bufferMethod(ArrayBuffer arg1, ArrayBuffer? arg2, sequence<ArrayBuffer> arg3); + + attribute ArrayBufferView viewAttr; + void viewMethod(ArrayBufferView arg1, ArrayBufferView? arg2, sequence<ArrayBufferView> arg3); + + attribute Int8Array int8ArrayAttr; + void int8ArrayMethod(Int8Array arg1, Int8Array? arg2, sequence<Int8Array> arg3); + + attribute Uint8Array uint8ArrayAttr; + void uint8ArrayMethod(Uint8Array arg1, Uint8Array? arg2, sequence<Uint8Array> arg3); + + attribute Uint8ClampedArray uint8ClampedArrayAttr; + void uint8ClampedArrayMethod(Uint8ClampedArray arg1, Uint8ClampedArray? arg2, sequence<Uint8ClampedArray> arg3); + + attribute Int16Array int16ArrayAttr; + void int16ArrayMethod(Int16Array arg1, Int16Array? arg2, sequence<Int16Array> arg3); + + attribute Uint16Array uint16ArrayAttr; + void uint16ArrayMethod(Uint16Array arg1, Uint16Array? arg2, sequence<Uint16Array> arg3); + + attribute Int32Array int32ArrayAttr; + void int32ArrayMethod(Int32Array arg1, Int32Array? arg2, sequence<Int32Array> arg3); + + attribute Uint32Array uint32ArrayAttr; + void uint32ArrayMethod(Uint32Array arg1, Uint32Array? arg2, sequence<Uint32Array> arg3); + + attribute Float32Array float32ArrayAttr; + void float32ArrayMethod(Float32Array arg1, Float32Array? arg2, sequence<Float32Array> arg3); + + attribute Float64Array float64ArrayAttr; + void float64ArrayMethod(Float64Array arg1, Float64Array? arg2, sequence<Float64Array> arg3); + }; + """) + + results = parser.finish() + + iface = results[0] + + harness.ok(True, "TestArrayBuffer interface parsed without error") + harness.check(len(iface.members), 22, "Interface should have twenty two members") + + members = iface.members + + def checkStuff(attr, method, t): + harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Expect an IDLAttribute") + harness.ok(isinstance(method, WebIDL.IDLMethod), "Expect an IDLMethod") + + harness.check(str(attr.type), t, "Expect an ArrayBuffer type") + harness.ok(attr.type.isSpiderMonkeyInterface(), "Should test as a js interface") + + (retType, arguments) = method.signatures()[0] + harness.ok(retType.isVoid(), "Should have a void return type") + harness.check(len(arguments), 3, "Expect 3 arguments") + + harness.check(str(arguments[0].type), t, "Expect an ArrayBuffer type") + harness.ok(arguments[0].type.isSpiderMonkeyInterface(), "Should test as a js interface") + + harness.check(str(arguments[1].type), t + "OrNull", "Expect an ArrayBuffer type") + harness.ok(arguments[1].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface") + + harness.check(str(arguments[2].type), t + "Sequence", "Expect an ArrayBuffer type") + harness.ok(arguments[2].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface") + + + checkStuff(members[0], members[1], "ArrayBuffer") + checkStuff(members[2], members[3], "ArrayBufferView") + checkStuff(members[4], members[5], "Int8Array") + checkStuff(members[6], members[7], "Uint8Array") + checkStuff(members[8], members[9], "Uint8ClampedArray") + checkStuff(members[10], members[11], "Int16Array") + checkStuff(members[12], members[13], "Uint16Array") + checkStuff(members[14], members[15], "Int32Array") + checkStuff(members[16], members[17], "Uint32Array") + checkStuff(members[18], members[19], "Float32Array") + checkStuff(members[20], members[21], "Float64Array") diff --git a/dom/bindings/parser/tests/test_attr.py b/dom/bindings/parser/tests/test_attr.py new file mode 100644 index 000000000..ad7aabc19 --- /dev/null +++ b/dom/bindings/parser/tests/test_attr.py @@ -0,0 +1,177 @@ +import WebIDL + +def WebIDLTest(parser, harness): + testData = [("::TestAttr%s::b", "b", "Byte%s", False), + ("::TestAttr%s::rb", "rb", "Byte%s", True), + ("::TestAttr%s::o", "o", "Octet%s", False), + ("::TestAttr%s::ro", "ro", "Octet%s", True), + ("::TestAttr%s::s", "s", "Short%s", False), + ("::TestAttr%s::rs", "rs", "Short%s", True), + ("::TestAttr%s::us", "us", "UnsignedShort%s", False), + ("::TestAttr%s::rus", "rus", "UnsignedShort%s", True), + ("::TestAttr%s::l", "l", "Long%s", False), + ("::TestAttr%s::rl", "rl", "Long%s", True), + ("::TestAttr%s::ul", "ul", "UnsignedLong%s", False), + ("::TestAttr%s::rul", "rul", "UnsignedLong%s", True), + ("::TestAttr%s::ll", "ll", "LongLong%s", False), + ("::TestAttr%s::rll", "rll", "LongLong%s", True), + ("::TestAttr%s::ull", "ull", "UnsignedLongLong%s", False), + ("::TestAttr%s::rull", "rull", "UnsignedLongLong%s", True), + ("::TestAttr%s::str", "str", "String%s", False), + ("::TestAttr%s::rstr", "rstr", "String%s", True), + ("::TestAttr%s::obj", "obj", "Object%s", False), + ("::TestAttr%s::robj", "robj", "Object%s", True), + ("::TestAttr%s::object", "object", "Object%s", False), + ("::TestAttr%s::f", "f", "Float%s", False), + ("::TestAttr%s::rf", "rf", "Float%s", True)] + + parser.parse(""" + interface TestAttr { + attribute byte b; + readonly attribute byte rb; + attribute octet o; + readonly attribute octet ro; + attribute short s; + readonly attribute short rs; + attribute unsigned short us; + readonly attribute unsigned short rus; + attribute long l; + readonly attribute long rl; + attribute unsigned long ul; + readonly attribute unsigned long rul; + attribute long long ll; + readonly attribute long long rll; + attribute unsigned long long ull; + readonly attribute unsigned long long rull; + attribute DOMString str; + readonly attribute DOMString rstr; + attribute object obj; + readonly attribute object robj; + attribute object _object; + attribute float f; + readonly attribute float rf; + }; + + interface TestAttrNullable { + attribute byte? b; + readonly attribute byte? rb; + attribute octet? o; + readonly attribute octet? ro; + attribute short? s; + readonly attribute short? rs; + attribute unsigned short? us; + readonly attribute unsigned short? rus; + attribute long? l; + readonly attribute long? rl; + attribute unsigned long? ul; + readonly attribute unsigned long? rul; + attribute long long? ll; + readonly attribute long long? rll; + attribute unsigned long long? ull; + readonly attribute unsigned long long? rull; + attribute DOMString? str; + readonly attribute DOMString? rstr; + attribute object? obj; + readonly attribute object? robj; + attribute object? _object; + attribute float? f; + readonly attribute float? rf; + }; + """) + + results = parser.finish() + + def checkAttr(attr, QName, name, type, readonly): + harness.ok(isinstance(attr, WebIDL.IDLAttribute), + "Should be an IDLAttribute") + harness.ok(attr.isAttr(), "Attr is an Attr") + harness.ok(not attr.isMethod(), "Attr is not an method") + harness.ok(not attr.isConst(), "Attr is not a const") + harness.check(attr.identifier.QName(), QName, "Attr has the right QName") + harness.check(attr.identifier.name, name, "Attr has the right name") + harness.check(str(attr.type), type, "Attr has the right type") + harness.check(attr.readonly, readonly, "Attr's readonly state is correct") + + harness.ok(True, "TestAttr interface parsed without error.") + harness.check(len(results), 2, "Should be two productions.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestAttr", "Interface has the right QName") + harness.check(iface.identifier.name, "TestAttr", "Interface has the right name") + harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) + + attrs = iface.members + + for i in range(len(attrs)): + data = testData[i] + attr = attrs[i] + (QName, name, type, readonly) = data + checkAttr(attr, QName % "", name, type % "", readonly) + + iface = results[1] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestAttrNullable", "Interface has the right QName") + harness.check(iface.identifier.name, "TestAttrNullable", "Interface has the right name") + harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) + + attrs = iface.members + + for i in range(len(attrs)): + data = testData[i] + attr = attrs[i] + (QName, name, type, readonly) = data + checkAttr(attr, QName % "Nullable", name, type % "OrNull", readonly) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [SetterThrows] readonly attribute boolean foo; + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should not allow [SetterThrows] on readonly attributes") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throw] readonly attribute boolean foo; + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should spell [Throws] correctly") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [SameObject] readonly attribute boolean foo; + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should not allow [SameObject] on attributes not of interface type") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [SameObject] readonly attribute A foo; + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(not threw, "Should allow [SameObject] on attributes of interface type") diff --git a/dom/bindings/parser/tests/test_attr_sequence_type.py b/dom/bindings/parser/tests/test_attr_sequence_type.py new file mode 100644 index 000000000..fb1b97812 --- /dev/null +++ b/dom/bindings/parser/tests/test_attr_sequence_type.py @@ -0,0 +1,67 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface AttrSequenceType { + attribute sequence<object> foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Attribute type must not be a sequence type") + + parser.reset() + + threw = False + try: + parser.parse(""" + interface AttrUnionWithSequenceType { + attribute (sequence<object> or DOMString) foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Attribute type must not be a union with a sequence member type") + + parser.reset() + + threw = False + try: + parser.parse(""" + interface AttrNullableUnionWithSequenceType { + attribute (sequence<object>? or DOMString) foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Attribute type must not be a union with a nullable sequence " + "member type") + + parser.reset() + + threw = False + try: + parser.parse(""" + interface AttrUnionWithUnionWithSequenceType { + attribute ((sequence<object> or DOMString) or AttrUnionWithUnionWithSequenceType) foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Attribute type must not be a union type with a union member " + "type that has a sequence member type") diff --git a/dom/bindings/parser/tests/test_builtin_filename.py b/dom/bindings/parser/tests/test_builtin_filename.py new file mode 100644 index 000000000..631e52eba --- /dev/null +++ b/dom/bindings/parser/tests/test_builtin_filename.py @@ -0,0 +1,11 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface Test { + attribute long b; + }; + """); + + attr = parser.finish()[0].members[0] + harness.check(attr.type.filename(), '<builtin>', 'Filename on builtin type') diff --git a/dom/bindings/parser/tests/test_builtins.py b/dom/bindings/parser/tests/test_builtins.py new file mode 100644 index 000000000..f8563fc2d --- /dev/null +++ b/dom/bindings/parser/tests/test_builtins.py @@ -0,0 +1,41 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestBuiltins { + attribute boolean b; + attribute byte s8; + attribute octet u8; + attribute short s16; + attribute unsigned short u16; + attribute long s32; + attribute unsigned long u32; + attribute long long s64; + attribute unsigned long long u64; + attribute DOMTimeStamp ts; + }; + """) + + results = parser.finish() + + harness.ok(True, "TestBuiltins 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(), "::TestBuiltins", "Interface has the right QName") + harness.check(iface.identifier.name, "TestBuiltins", "Interface has the right name") + harness.check(iface.parent, None, "Interface has no parent") + + members = iface.members + harness.check(len(members), 10, "Should be one production") + + names = ["b", "s8", "u8", "s16", "u16", "s32", "u32", "s64", "u64", "ts"] + types = ["Boolean", "Byte", "Octet", "Short", "UnsignedShort", "Long", "UnsignedLong", "LongLong", "UnsignedLongLong", "UnsignedLongLong"] + for i in range(10): + attr = members[i] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute") + harness.check(attr.identifier.QName(), "::TestBuiltins::" + names[i], "Attr has correct QName") + harness.check(attr.identifier.name, names[i], "Attr has correct name") + harness.check(str(attr.type), types[i], "Attr type is the correct name") + harness.ok(attr.type.isPrimitive(), "Should be a primitive type") diff --git a/dom/bindings/parser/tests/test_bytestring.py b/dom/bindings/parser/tests/test_bytestring.py new file mode 100644 index 000000000..fa83e9e2d --- /dev/null +++ b/dom/bindings/parser/tests/test_bytestring.py @@ -0,0 +1,99 @@ +# -*- 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 for ByteString default in interface") + + # Can have optional ByteStrings with default values + try: + parser.parse(""" + interface OptionalByteString { + void passByteString(optional ByteString arg = "hello"); + }; + """) + results2 = parser.finish(); + except WebIDL.WebIDLError as e: + harness.ok(False, + "Should not have thrown a WebIDL error for ByteString " + "default in dictionary. " + str(e)) + + # Can have a default ByteString value in a dictionary + try: + parser.parse(""" + dictionary OptionalByteStringDict { + ByteString item = "some string"; + }; + """) + results3 = parser.finish(); + except WebIDL.WebIDLError as e: + harness.ok(False, + "Should not have thrown a WebIDL error for ByteString " + "default in dictionary. " + str(e)) + + # Don't allow control characters in ByteString literals + threw = False + try: + parser.parse(""" + dictionary OptionalByteStringDict2 { + ByteString item = "\x03"; + }; + """) + results4 = parser.finish() + except WebIDL.WebIDLError as e: + threw = True + + harness.ok(threw, + "Should have thrown a WebIDL error for invalid ByteString " + "default in dictionary") diff --git a/dom/bindings/parser/tests/test_callback.py b/dom/bindings/parser/tests/test_callback.py new file mode 100644 index 000000000..4dfda1c3c --- /dev/null +++ b/dom/bindings/parser/tests/test_callback.py @@ -0,0 +1,34 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestCallback { + attribute CallbackType? listener; + }; + + callback CallbackType = boolean (unsigned long arg); + """) + + results = parser.finish() + + harness.ok(True, "TestCallback interface parsed without error.") + harness.check(len(results), 2, "Should be two productions.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestCallback", "Interface has the right QName") + harness.check(iface.identifier.name, "TestCallback", "Interface has the right name") + harness.check(len(iface.members), 1, "Expect %s members" % 1) + + attr = iface.members[0] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), + "Should be an IDLAttribute") + harness.ok(attr.isAttr(), "Should be an attribute") + harness.ok(not attr.isMethod(), "Attr is not an method") + harness.ok(not attr.isConst(), "Attr is not a const") + harness.check(attr.identifier.QName(), "::TestCallback::listener", "Attr has the right QName") + harness.check(attr.identifier.name, "listener", "Attr has the right name") + t = attr.type + harness.ok(not isinstance(t, WebIDL.IDLWrapperType), "Attr has the right type") + harness.ok(isinstance(t, WebIDL.IDLNullableType), "Attr has the right type") + harness.ok(t.isCallback(), "Attr has the right type") diff --git a/dom/bindings/parser/tests/test_callback_interface.py b/dom/bindings/parser/tests/test_callback_interface.py new file mode 100644 index 000000000..e4789dae1 --- /dev/null +++ b/dom/bindings/parser/tests/test_callback_interface.py @@ -0,0 +1,94 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + callback interface TestCallbackInterface { + attribute boolean bool; + }; + """) + + results = parser.finish() + + iface = results[0] + + harness.ok(iface.isCallback(), "Interface should be a callback") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface { + }; + callback interface TestCallbackInterface : TestInterface { + attribute boolean bool; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow non-callback parent of callback interface") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface : TestCallbackInterface { + }; + callback interface TestCallbackInterface { + attribute boolean bool; + }; + """) + results = parser.finish() + except: + threw = True + + 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/dom/bindings/parser/tests/test_conditional_dictionary_member.py b/dom/bindings/parser/tests/test_conditional_dictionary_member.py new file mode 100644 index 000000000..433b7e501 --- /dev/null +++ b/dom/bindings/parser/tests/test_conditional_dictionary_member.py @@ -0,0 +1,110 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict { + any foo; + [ChromeOnly] any bar; + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should have a dictionary") + members = results[0].members; + harness.check(len(members), 2, "Should have two members") + # Note that members are ordered lexicographically, so "bar" comes + # before "foo". + harness.ok(members[0].getExtendedAttribute("ChromeOnly"), + "First member is not ChromeOnly") + harness.ok(not members[1].getExtendedAttribute("ChromeOnly"), + "Second member is ChromeOnly") + + parser = parser.reset() + parser.parse(""" + dictionary Dict { + any foo; + any bar; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + harness.check(len(results), 2, "Should have a dictionary and an interface") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary Dict { + any foo; + [ChromeOnly] any bar; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown.") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary ParentDict { + [ChromeOnly] any bar; + }; + + dictionary Dict : ParentDict { + any foo; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown (2).") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception (2)") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary GrandParentDict { + [ChromeOnly] any baz; + }; + + dictionary ParentDict : GrandParentDict { + any bar; + }; + + dictionary Dict : ParentDict { + any foo; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown (3).") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception (3)") diff --git a/dom/bindings/parser/tests/test_const.py b/dom/bindings/parser/tests/test_const.py new file mode 100644 index 000000000..80b6fb0e9 --- /dev/null +++ b/dom/bindings/parser/tests/test_const.py @@ -0,0 +1,80 @@ +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 { + const byte zero = 0; + const byte b = -1; + const octet o = 2; + const short s = -3; + const unsigned short us = 0x4; + const long l = -0X5; + const unsigned long ul = 6; + const unsigned long long ull = 7; + const long long ll = -010; + const boolean t = true; + const boolean f = false; + 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; + }; + """) + + results = parser.finish() + + harness.ok(True, "TestConsts interface parsed without error.") + harness.check(len(results), 1, "Should be one production.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "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), len(expected), "Expect %s members" % len(expected)) + + 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") + harness.ok(not const.isAttr(), "Const is not an attr") + harness.ok(not const.isMethod(), "Const is not a method") + harness.check(const.identifier.QName(), QName, "Const has the right QName") + harness.check(const.identifier.name, name, "Const has the right name") + harness.check(str(const.type), type, "Const has the right type") + harness.ok(const.type.isPrimitive(), "All consts should be primitive") + harness.check(str(const.value.type), str(const.type), + "Const's value has the same type as the type") + harness.check(const.value.value, value, "Const value has the right value.") + diff --git a/dom/bindings/parser/tests/test_constructor.py b/dom/bindings/parser/tests/test_constructor.py new file mode 100644 index 000000000..348204c7d --- /dev/null +++ b/dom/bindings/parser/tests/test_constructor.py @@ -0,0 +1,109 @@ +import WebIDL + +def WebIDLTest(parser, harness): + def checkArgument(argument, QName, name, type, optional, variadic): + harness.ok(isinstance(argument, WebIDL.IDLArgument), + "Should be an IDLArgument") + harness.check(argument.identifier.QName(), QName, "Argument has the right QName") + harness.check(argument.identifier.name, name, "Argument has the right name") + harness.check(str(argument.type), type, "Argument has the right return type") + harness.check(argument.optional, optional, "Argument has the right optional value") + harness.check(argument.variadic, variadic, "Argument has the right variadic value") + + def checkMethod(method, QName, name, signatures, + static=True, getter=False, setter=False, creator=False, + deleter=False, legacycaller=False, stringifier=False, + chromeOnly=False): + harness.ok(isinstance(method, WebIDL.IDLMethod), + "Should be an IDLMethod") + harness.ok(method.isMethod(), "Method is a method") + harness.ok(not method.isAttr(), "Method is not an attr") + harness.ok(not method.isConst(), "Method is not a const") + harness.check(method.identifier.QName(), QName, "Method has the right QName") + harness.check(method.identifier.name, name, "Method has the right name") + harness.check(method.isStatic(), static, "Method has the correct static value") + harness.check(method.isGetter(), getter, "Method has the correct getter value") + harness.check(method.isSetter(), setter, "Method has the correct setter value") + harness.check(method.isCreator(), creator, "Method has the correct creator value") + harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") + harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") + harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") + harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") + harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") + + sigpairs = zip(method.signatures(), signatures) + for (gotSignature, expectedSignature) in sigpairs: + (gotRetType, gotArgs) = gotSignature + (expectedRetType, expectedArgs) = expectedSignature + + harness.check(str(gotRetType), expectedRetType, + "Method has the expected return type.") + + for i in range(0, len(gotArgs)): + (QName, name, type, optional, variadic) = expectedArgs[i] + checkArgument(gotArgs[i], QName, name, type, optional, variadic) + + parser.parse(""" + [Constructor] + interface TestConstructorNoArgs { + }; + + [Constructor(DOMString name)] + interface TestConstructorWithArgs { + }; + + [Constructor(object foo), Constructor(boolean bar)] + interface TestConstructorOverloads { + }; + """) + results = parser.finish() + harness.check(len(results), 3, "Should be three productions") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.ok(isinstance(results[2], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor", + "constructor", [("TestConstructorNoArgs (Wrapper)", [])]) + checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor", + "constructor", + [("TestConstructorWithArgs (Wrapper)", + [("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])]) + checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor", + "constructor", + [("TestConstructorOverloads (Wrapper)", + [("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]), + ("TestConstructorOverloads (Wrapper)", + [("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])]) + + parser = parser.reset() + parser.parse(""" + [ChromeConstructor()] + interface TestChromeConstructor { + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestChromeConstructor::constructor", + "constructor", [("TestChromeConstructor (Wrapper)", [])], + chromeOnly=True) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor(), + ChromeConstructor(DOMString a)] + interface TestChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") diff --git a/dom/bindings/parser/tests/test_constructor_no_interface_object.py b/dom/bindings/parser/tests/test_constructor_no_interface_object.py new file mode 100644 index 000000000..2b09ae71e --- /dev/null +++ b/dom/bindings/parser/tests/test_constructor_no_interface_object.py @@ -0,0 +1,36 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + [Constructor, NoInterfaceObject] + interface TestConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + [NoInterfaceObject, Constructor] + interface TestConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + parser.parse(""" + [NoInterfaceObject, NamedConstructor=FooBar] + interface TestNamedConstructorNoInterfaceObject { + }; + """) diff --git a/dom/bindings/parser/tests/test_date.py b/dom/bindings/parser/tests/test_date.py new file mode 100644 index 000000000..2bdfc95e1 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_deduplicate.py b/dom/bindings/parser/tests/test_deduplicate.py new file mode 100644 index 000000000..6249d36fb --- /dev/null +++ b/dom/bindings/parser/tests/test_deduplicate.py @@ -0,0 +1,15 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface Foo; + interface Bar; + interface Foo; + """); + + results = parser.finish() + + # There should be no duplicate interfaces in the result. + expectedNames = sorted(['Foo', 'Bar']) + actualNames = sorted(map(lambda iface: iface.identifier.name, results)) + harness.check(actualNames, expectedNames, "Parser shouldn't output duplicate names.") diff --git a/dom/bindings/parser/tests/test_dictionary.py b/dom/bindings/parser/tests/test_dictionary.py new file mode 100644 index 000000000..2c0fa6123 --- /dev/null +++ b/dom/bindings/parser/tests/test_dictionary.py @@ -0,0 +1,555 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict2 : Dict1 { + long child = 5; + Dict1 aaandAnother; + }; + dictionary Dict1 { + long parent; + double otherParent; + }; + """) + results = parser.finish() + + dict1 = results[1]; + dict2 = results[0]; + + harness.check(len(dict1.members), 2, "Dict1 has two members") + harness.check(len(dict2.members), 2, "Dict2 has four members") + + harness.check(dict1.members[0].identifier.name, "otherParent", + "'o' comes before 'p'") + harness.check(dict1.members[1].identifier.name, "parent", + "'o' really comes before 'p'") + harness.check(dict2.members[0].identifier.name, "aaandAnother", + "'a' comes before 'c'") + harness.check(dict2.members[1].identifier.name, "child", + "'a' really comes before 'c'") + + # Now reset our parser + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Dict { + long prop = 5; + long prop; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow name duplication in a dictionary") + + # Now reset our parser again + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Dict1 : Dict2 { + long prop = 5; + }; + dictionary Dict2 : Dict3 { + long prop2; + }; + dictionary Dict3 { + double prop; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow name duplication in a dictionary and " + "its ancestor") + + # More reset + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Iface {}; + dictionary Dict : Iface { + long prop; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow non-dictionary parents for dictionaries") + + # Even more reset + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A : B {}; + dictionary B : A {}; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow cycles in dictionary inheritance chains") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + [TreatNullAs=EmptyString] DOMString foo; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [TreatNullAs] on dictionary members"); + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(A arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Trailing dictionary arg must be optional") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo((A or DOMString) arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Trailing union arg containing a dictionary must be optional") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(A arg1, optional long arg2); + }; + """) + results = parser.finish() + except: + threw = True + + 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 { + }; + interface X { + void doFoo(A arg1, long arg2); + }; + """) + results = parser.finish() + harness.ok(True, "Dictionary arg followed by required arg can be required") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional A? arg1); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Dictionary arg must not be nullable") + + 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 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/dom/bindings/parser/tests/test_distinguishability.py b/dom/bindings/parser/tests/test_distinguishability.py new file mode 100644 index 000000000..d7780c1ff --- /dev/null +++ b/dom/bindings/parser/tests/test_distinguishability.py @@ -0,0 +1,293 @@ +def firstArgType(method): + return method.signatures()[0][1][0].type + +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict { + }; + callback interface Foo { + }; + interface Bar { + // Bit of a pain to get things that have dictionary types + void passDict(optional Dict arg); + void passFoo(Foo arg); + void passNullableUnion((object? or DOMString) arg); + void passNullable(Foo? arg); + }; + """) + results = parser.finish() + + iface = results[2] + harness.ok(iface.isInterface(), "Should have interface") + dictMethod = iface.members[0] + ifaceMethod = iface.members[1] + nullableUnionMethod = iface.members[2] + nullableIfaceMethod = iface.members[3] + + dictType = firstArgType(dictMethod) + ifaceType = firstArgType(ifaceMethod) + + harness.ok(dictType.isDictionary(), "Should have dictionary type"); + harness.ok(ifaceType.isInterface(), "Should have interface type"); + harness.ok(ifaceType.isCallbackInterface(), "Should have callback interface type"); + + harness.ok(not dictType.isDistinguishableFrom(ifaceType), + "Dictionary not distinguishable from callback interface") + harness.ok(not ifaceType.isDistinguishableFrom(dictType), + "Callback interface not distinguishable from dictionary") + + nullableUnionType = firstArgType(nullableUnionMethod) + nullableIfaceType = firstArgType(nullableIfaceMethod) + + harness.ok(nullableUnionType.isUnion(), "Should have union type"); + harness.ok(nullableIfaceType.isInterface(), "Should have interface type"); + harness.ok(nullableIfaceType.nullable(), "Should have nullable type"); + + harness.ok(not nullableUnionType.isDistinguishableFrom(nullableIfaceType), + "Nullable type not distinguishable from union with nullable " + "member type") + harness.ok(not nullableIfaceType.isDistinguishableFrom(nullableUnionType), + "Union with nullable member type not distinguishable from " + "nullable type") + + parser = parser.reset() + parser.parse(""" + interface TestIface { + void passKid(Kid arg); + void passParent(Parent arg); + void passGrandparent(Grandparent arg); + void passImplemented(Implemented arg); + void passImplementedParent(ImplementedParent arg); + void passUnrelated1(Unrelated1 arg); + void passUnrelated2(Unrelated2 arg); + void passArrayBuffer(ArrayBuffer arg); + void passArrayBuffer(ArrayBufferView arg); + }; + + interface Kid : Parent {}; + interface Parent : Grandparent {}; + interface Grandparent {}; + interface Implemented : ImplementedParent {}; + Parent implements Implemented; + interface ImplementedParent {}; + interface Unrelated1 {}; + interface Unrelated2 {}; + """) + results = parser.finish() + + iface = results[0] + harness.ok(iface.isInterface(), "Should have interface") + argTypes = [firstArgType(method) for method in iface.members] + unrelatedTypes = [firstArgType(method) for method in iface.members[-3:]] + + for type1 in argTypes: + for type2 in argTypes: + distinguishable = (type1 is not type2 and + (type1 in unrelatedTypes or + type2 in unrelatedTypes)) + + harness.check(type1.isDistinguishableFrom(type2), + distinguishable, + "Type %s should %sbe distinguishable from type %s" % + (type1, "" if distinguishable else "not ", type2)) + harness.check(type2.isDistinguishableFrom(type1), + distinguishable, + "Type %s should %sbe distinguishable from type %s" % + (type2, "" if distinguishable else "not ", type1)) + + parser = parser.reset() + parser.parse(""" + interface Dummy {}; + interface TestIface { + void method(long arg1, TestIface arg2); + void method(long arg1, long arg2); + void method(long arg1, Dummy arg2); + void method(DOMString arg1, DOMString arg2, DOMString arg3); + }; + """) + results = parser.finish() + harness.check(len(results[1].members), 1, + "Should look like we have one method") + harness.check(len(results[1].members[0].signatures()), 4, + "Should have four signatures") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Dummy {}; + interface TestIface { + void method(long arg1, TestIface arg2); + void method(long arg1, long arg2); + void method(any arg1, Dummy arg2); + void method(DOMString arg1, DOMString arg2, DOMString arg3); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should throw when args before the distinguishing arg are not " + "all the same type") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Dummy {}; + interface TestIface { + void method(long arg1, TestIface arg2); + void method(long arg1, long arg2); + void method(any arg1, DOMString arg2); + void method(DOMString arg1, DOMString arg2, DOMString arg3); + }; + """) + results = parser.finish() + except: + 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>", + "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>" ] + 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 + ["object"])) + setDistinguishable("sequence<short>", + allBut(argTypes, sequences + ["object"])) + setDistinguishable("MozMap<object>", nonUserObjects) + setDistinguishable("MozMap<Dict>", nonUserObjects) + setDistinguishable("MozMap<long>", nonUserObjects) + 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/dom/bindings/parser/tests/test_double_null.py b/dom/bindings/parser/tests/test_double_null.py new file mode 100644 index 000000000..700c7eade --- /dev/null +++ b/dom/bindings/parser/tests/test_double_null.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface DoubleNull { + attribute byte?? foo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_duplicate_qualifiers.py b/dom/bindings/parser/tests/test_duplicate_qualifiers.py new file mode 100644 index 000000000..799f2e0e0 --- /dev/null +++ b/dom/bindings/parser/tests/test_duplicate_qualifiers.py @@ -0,0 +1,84 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface DuplicateQualifiers1 { + getter getter byte foo(unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface DuplicateQualifiers2 { + setter setter byte foo(unsigned long index, byte value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface DuplicateQualifiers3 { + creator creator byte foo(unsigned long index, byte value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface DuplicateQualifiers4 { + deleter deleter byte foo(unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface DuplicateQualifiers5 { + getter deleter getter byte foo(unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + results = parser.parse(""" + interface DuplicateQualifiers6 { + creator setter creator byte foo(unsigned long index, byte value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_empty_enum.py b/dom/bindings/parser/tests/test_empty_enum.py new file mode 100644 index 000000000..ee0079f06 --- /dev/null +++ b/dom/bindings/parser/tests/test_empty_enum.py @@ -0,0 +1,14 @@ +import WebIDL + +def WebIDLTest(parser, harness): + try: + parser.parse(""" + enum TestEmptyEnum { + }; + """) + + harness.ok(False, "Should have thrown!") + except: + harness.ok(True, "Parsing TestEmptyEnum enum should fail") + + results = parser.finish() diff --git a/dom/bindings/parser/tests/test_empty_sequence_default_value.py b/dom/bindings/parser/tests/test_empty_sequence_default_value.py new file mode 100644 index 000000000..350ae72f0 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_enum.py b/dom/bindings/parser/tests/test_enum.py new file mode 100644 index 000000000..862289391 --- /dev/null +++ b/dom/bindings/parser/tests/test_enum.py @@ -0,0 +1,93 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + enum TestEnum { + "", + "foo", + "bar" + }; + + interface TestEnumInterface { + TestEnum doFoo(boolean arg); + readonly attribute TestEnum foo; + }; + """) + + results = parser.finish() + + harness.ok(True, "TestEnumInterfaces interface parsed without error.") + harness.check(len(results), 2, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLEnum), + "Should be an IDLEnum") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should be an IDLInterface") + + enum = results[0] + harness.check(enum.identifier.QName(), "::TestEnum", "Enum has the right QName") + harness.check(enum.identifier.name, "TestEnum", "Enum has the right name") + harness.check(enum.values(), ["", "foo", "bar"], "Enum has the right values") + + iface = results[1] + + harness.check(iface.identifier.QName(), "::TestEnumInterface", "Interface has the right QName") + harness.check(iface.identifier.name, "TestEnumInterface", "Interface has the right name") + harness.check(iface.parent, None, "Interface has no parent") + + members = iface.members + harness.check(len(members), 2, "Should be one production") + harness.ok(isinstance(members[0], WebIDL.IDLMethod), + "Should be an IDLMethod") + method = members[0] + harness.check(method.identifier.QName(), "::TestEnumInterface::doFoo", + "Method has correct QName") + harness.check(method.identifier.name, "doFoo", "Method has correct name") + + signatures = method.signatures() + harness.check(len(signatures), 1, "Expect one signature") + + (returnType, arguments) = signatures[0] + harness.check(str(returnType), "TestEnum (Wrapper)", "Method type is the correct name") + harness.check(len(arguments), 1, "Method has the right number of arguments") + arg = arguments[0] + harness.ok(isinstance(arg, WebIDL.IDLArgument), "Should be an IDLArgument") + harness.check(str(arg.type), "Boolean", "Argument has the right type") + + attr = members[1] + harness.check(attr.identifier.QName(), "::TestEnumInterface::foo", + "Attr has correct QName") + harness.check(attr.identifier.name, "foo", "Attr has correct name") + + harness.check(str(attr.type), "TestEnum (Wrapper)", "Attr type is the correct name") + + # Now reset our parser + parser = parser.reset() + threw = False + try: + parser.parse(""" + enum Enum { + "a", + "b", + "c" + }; + interface TestInterface { + void foo(optional Enum e = "d"); + }; + """) + results = parser.finish() + except: + 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/dom/bindings/parser/tests/test_enum_duplicate_values.py b/dom/bindings/parser/tests/test_enum_duplicate_values.py new file mode 100644 index 000000000..51205d209 --- /dev/null +++ b/dom/bindings/parser/tests/test_enum_duplicate_values.py @@ -0,0 +1,13 @@ +import WebIDL + +def WebIDLTest(parser, harness): + try: + parser.parse(""" + enum TestEnumDuplicateValue { + "", + "" + }; + """) + harness.ok(False, "Should have thrown!") + except: + harness.ok(True, "Enum TestEnumDuplicateValue should throw") diff --git a/dom/bindings/parser/tests/test_error_colno.py b/dom/bindings/parser/tests/test_error_colno.py new file mode 100644 index 000000000..ca0674aec --- /dev/null +++ b/dom/bindings/parser/tests/test_error_colno.py @@ -0,0 +1,20 @@ +import WebIDL + +def WebIDLTest(parser, harness): + # Check that error messages put the '^' in the right place. + + threw = False + input = 'interface ?' + try: + parser.parse(input) + results = parser.finish() + except WebIDL.WebIDLError, e: + threw = True + lines = str(e).split('\n') + + harness.check(len(lines), 3, 'Expected number of lines in error message') + harness.check(lines[1], input, 'Second line shows error') + harness.check(lines[2], ' ' * (len(input) - 1) + '^', + 'Correct column pointer in error message') + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_error_lineno.py b/dom/bindings/parser/tests/test_error_lineno.py new file mode 100644 index 000000000..f11222e7a --- /dev/null +++ b/dom/bindings/parser/tests/test_error_lineno.py @@ -0,0 +1,28 @@ +import WebIDL + +def WebIDLTest(parser, harness): + # Check that error messages put the '^' in the right place. + + threw = False + input = """\ +// This is a comment. +interface Foo { +}; + +/* This is also a comment. */ +interface ?""" + try: + parser.parse(input) + results = parser.finish() + except WebIDL.WebIDLError, e: + threw = True + lines = str(e).split('\n') + + harness.check(len(lines), 3, 'Expected number of lines in error message') + harness.ok(lines[0].endswith('line 6:10'), 'First line of error should end with "line 6:10", but was "%s".' % lines[0]) + harness.check(lines[1], 'interface ?', 'Second line of error message is the line which caused the error.') + harness.check(lines[2], ' ' * (len('interface ?') - 1) + '^', + 'Correct column pointer in error message.') + + harness.ok(threw, "Should have thrown.") + diff --git a/dom/bindings/parser/tests/test_exposed_extended_attribute.py b/dom/bindings/parser/tests/test_exposed_extended_attribute.py new file mode 100644 index 000000000..48957098b --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_extended_attributes.py b/dom/bindings/parser/tests/test_extended_attributes.py new file mode 100644 index 000000000..85a70d98f --- /dev/null +++ b/dom/bindings/parser/tests/test_extended_attributes.py @@ -0,0 +1,107 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + [NoInterfaceObject] + interface TestExtendedAttr { + [Unforgeable] readonly attribute byte b; + }; + """) + + results = parser.finish() + + parser = parser.reset() + parser.parse(""" + [Pref="foo.bar",Pref=flop] + interface TestExtendedAttr { + [Pref="foo.bar"] attribute byte b; + }; + """) + + results = parser.finish() + + parser = parser.reset() + parser.parse(""" + interface TestLenientThis { + [LenientThis] attribute byte b; + }; + """) + + results = parser.finish() + harness.ok(results[0].members[0].hasLenientThis(), + "Should have a lenient this") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestLenientThis2 { + [LenientThis=something] attribute byte b; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "[LenientThis] must take no arguments") + + parser = parser.reset() + parser.parse(""" + interface TestClamp { + void testClamp([Clamp] long foo); + void testNotClamp(long foo); + }; + """) + + results = parser.finish() + # Pull out the first argument out of the arglist of the first (and + # only) signature. + harness.ok(results[0].members[0].signatures()[0][1][0].clamp, + "Should be clamped") + harness.ok(not results[0].members[1].signatures()[0][1][0].clamp, + "Should not be clamped") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestClamp2 { + void testClamp([Clamp=something] long foo); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "[Clamp] must take no arguments") + + parser = parser.reset() + parser.parse(""" + interface TestEnforceRange { + void testEnforceRange([EnforceRange] long foo); + void testNotEnforceRange(long foo); + }; + """) + + results = parser.finish() + # Pull out the first argument out of the arglist of the first (and + # only) signature. + harness.ok(results[0].members[0].signatures()[0][1][0].enforceRange, + "Should be enforceRange") + harness.ok(not results[0].members[1].signatures()[0][1][0].enforceRange, + "Should not be enforceRange") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestEnforceRange2 { + void testEnforceRange([EnforceRange=something] long foo); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "[EnforceRange] must take no arguments") + diff --git a/dom/bindings/parser/tests/test_float_types.py b/dom/bindings/parser/tests/test_float_types.py new file mode 100644 index 000000000..718f09c11 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_forward_decl.py b/dom/bindings/parser/tests/test_forward_decl.py new file mode 100644 index 000000000..cac24c832 --- /dev/null +++ b/dom/bindings/parser/tests/test_forward_decl.py @@ -0,0 +1,15 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface ForwardDeclared; + interface ForwardDeclared; + + interface TestForwardDecl { + attribute ForwardDeclared foo; + }; + """) + + results = parser.finish() + + harness.ok(True, "TestForwardDeclared interface parsed without error.") diff --git a/dom/bindings/parser/tests/test_global_extended_attr.py b/dom/bindings/parser/tests/test_global_extended_attr.py new file mode 100644 index 000000000..c752cecd2 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_identifier_conflict.py b/dom/bindings/parser/tests/test_identifier_conflict.py new file mode 100644 index 000000000..b510a30c0 --- /dev/null +++ b/dom/bindings/parser/tests/test_identifier_conflict.py @@ -0,0 +1,39 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + try: + parser.parse(""" + enum Foo { "a" }; + interface Foo; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, e: + harness.ok("Name collision" in e.message, + "Should have name collision for interface") + + parser = parser.reset() + try: + parser.parse(""" + dictionary Foo { long x; }; + enum Foo { "a" }; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, e: + harness.ok("Name collision" in e.message, + "Should have name collision for dictionary") + + parser = parser.reset() + try: + parser.parse(""" + enum Foo { "a" }; + enum Foo { "b" }; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, e: + harness.ok("Multiple unresolvable definitions" in e.message, + "Should have name collision for dictionary") + diff --git a/dom/bindings/parser/tests/test_implements.py b/dom/bindings/parser/tests/test_implements.py new file mode 100644 index 000000000..04c47d92a --- /dev/null +++ b/dom/bindings/parser/tests/test_implements.py @@ -0,0 +1,216 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + # Basic functionality + threw = False + try: + parser.parse(""" + A implements B; + interface B { + attribute long x; + }; + interface A { + attribute long y; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, "Should not have thrown on implements statement " + "before interfaces") + harness.check(len(results), 3, "We have three statements") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), "B is an interface") + harness.check(len(results[1].members), 1, "B has one member") + A = results[2] + harness.ok(isinstance(A, WebIDL.IDLInterface), "A is an interface") + harness.check(len(A.members), 2, "A has two members") + harness.check(A.members[0].identifier.name, "y", "First member is 'y'") + harness.check(A.members[1].identifier.name, "x", "Second member is 'x'") + + # Duplicated member names not allowed + threw = False + try: + parser.parse(""" + C implements D; + interface D { + attribute long x; + }; + interface C { + attribute long x; + }; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on implemented interface duplicating " + "a name on base interface") + + # Same, but duplicated across implemented interfaces + threw = False + try: + parser.parse(""" + E implements F; + E implements G; + interface F { + attribute long x; + }; + interface G { + attribute long x; + }; + interface E {}; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on implemented interfaces " + "duplicating each other's member names") + + # Same, but duplicated across indirectly implemented interfaces + threw = False + try: + parser.parse(""" + H implements I; + H implements J; + I implements K; + interface K { + attribute long x; + }; + interface L { + attribute long x; + }; + interface I {}; + interface J : L {}; + interface H {}; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on indirectly implemented interfaces " + "duplicating each other's member names") + + # Same, but duplicated across an implemented interface and its parent + threw = False + try: + parser.parse(""" + M implements N; + interface O { + attribute long x; + }; + interface N : O { + attribute long x; + }; + interface M {}; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on implemented interface and its " + "ancestor duplicating member names") + + # Reset the parser so we can actually find things where we expect + # them in the list + parser = parser.reset() + + # Diamonds should be allowed + threw = False + try: + parser.parse(""" + P implements Q; + P implements R; + Q implements S; + R implements S; + interface Q {}; + interface R {}; + interface S { + attribute long x; + }; + interface P {}; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, "Diamond inheritance is fine") + harness.check(results[6].identifier.name, "S", "We should be looking at 'S'") + harness.check(len(results[6].members), 1, "S should have one member") + harness.check(results[6].members[0].identifier.name, "x", + "S's member should be 'x'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface { + }; + callback interface TestCallbackInterface { + }; + TestInterface implements TestCallbackInterface; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should not allow callback interfaces on the right-hand side " + "of 'implements'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface { + }; + callback interface TestCallbackInterface { + }; + TestCallbackInterface implements TestInterface; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should not allow callback interfaces on the left-hand side of " + "'implements'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface { + }; + dictionary Dict { + }; + Dict implements TestInterface; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should not allow non-interfaces on the left-hand side " + "of 'implements'") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestInterface { + }; + dictionary Dict { + }; + TestInterface implements Dict; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should not allow non-interfaces on the right-hand side " + "of 'implements'") + diff --git a/dom/bindings/parser/tests/test_incomplete_parent.py b/dom/bindings/parser/tests/test_incomplete_parent.py new file mode 100644 index 000000000..1f520a28e --- /dev/null +++ b/dom/bindings/parser/tests/test_incomplete_parent.py @@ -0,0 +1,18 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestIncompleteParent : NotYetDefined { + void foo(); + }; + + interface NotYetDefined : EvenHigherOnTheChain { + }; + + interface EvenHigherOnTheChain { + }; + """) + + parser.finish() + + harness.ok(True, "TestIncompleteParent interface parsed without error.") diff --git a/dom/bindings/parser/tests/test_incomplete_types.py b/dom/bindings/parser/tests/test_incomplete_types.py new file mode 100644 index 000000000..fdc396040 --- /dev/null +++ b/dom/bindings/parser/tests/test_incomplete_types.py @@ -0,0 +1,44 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestIncompleteTypes { + attribute FooInterface attr1; + + FooInterface method1(FooInterface arg); + }; + + interface FooInterface { + }; + """) + + results = parser.finish() + + harness.ok(True, "TestIncompleteTypes interface parsed without error.") + harness.check(len(results), 2, "Should be two productions.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestIncompleteTypes", "Interface has the right QName") + harness.check(iface.identifier.name, "TestIncompleteTypes", "Interface has the right name") + harness.check(len(iface.members), 2, "Expect 2 members") + + attr = iface.members[0] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), + "Should be an IDLAttribute") + method = iface.members[1] + harness.ok(isinstance(method, WebIDL.IDLMethod), + "Should be an IDLMethod") + + harness.check(attr.identifier.QName(), "::TestIncompleteTypes::attr1", + "Attribute has the right QName") + harness.check(attr.type.name, "FooInterface", + "Previously unresolved type has the right name") + + harness.check(method.identifier.QName(), "::TestIncompleteTypes::method1", + "Attribute has the right QName") + (returnType, args) = method.signatures()[0] + harness.check(returnType.name, "FooInterface", + "Previously unresolved type has the right name") + harness.check(args[0].type.name, "FooInterface", + "Previously unresolved type has the right name") diff --git a/dom/bindings/parser/tests/test_interface.py b/dom/bindings/parser/tests/test_interface.py new file mode 100644 index 000000000..e8ed67b54 --- /dev/null +++ b/dom/bindings/parser/tests/test_interface.py @@ -0,0 +1,405 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse("interface Foo { };") + results = parser.finish() + harness.ok(True, "Empty 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(), "::Foo", "Interface has the right QName") + harness.check(iface.identifier.name, "Foo", "Interface has the right name") + harness.check(iface.parent, None, "Interface has no parent") + + parser.parse("interface Bar : Foo { };") + results = parser.finish() + harness.ok(True, "Empty interface parsed without error.") + harness.check(len(results), 2, "Should be two productions") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should be an IDLInterface") + iface = results[1] + harness.check(iface.identifier.QName(), "::Bar", "Interface has the right QName") + harness.check(iface.identifier.name, "Bar", "Interface has the right name") + harness.ok(isinstance(iface.parent, WebIDL.IDLInterface), + "Interface has a parent") + + parser = parser.reset() + parser.parse(""" + interface QNameBase { + attribute long foo; + }; + + interface QNameDerived : QNameBase { + attribute long long foo; + attribute byte bar; + }; + """) + results = parser.finish() + harness.check(len(results), 2, "Should be two productions") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(results[1].parent, results[0], "Inheritance chain is right") + harness.check(len(results[0].members), 1, "Expect 1 productions") + harness.check(len(results[1].members), 2, "Expect 2 productions") + base = results[0] + derived = results[1] + harness.check(base.members[0].identifier.QName(), "::QNameBase::foo", + "Member has the right QName") + harness.check(derived.members[0].identifier.QName(), "::QNameDerived::foo", + "Member has the right QName") + harness.check(derived.members[1].identifier.QName(), "::QNameDerived::bar", + "Member has the right QName") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : B {}; + interface B : A {}; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow cycles in interface inheritance chains") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : C {}; + interface C : B {}; + interface B : A {}; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow indirect cycles in interface inheritance chains") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A {}; + interface B {}; + A implements B; + B implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow cycles via implements") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A {}; + interface C {}; + interface B {}; + A implements C; + C implements B; + B implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow indirect cycles via implements") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : B {}; + interface B {}; + B implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow inheriting from an interface that implements us") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : B {}; + interface B {}; + interface C {}; + B implements C; + C implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow inheriting from an interface that indirectly implements us") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : B {}; + interface B : C {}; + interface C {}; + C implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow indirectly inheriting from an interface that implements us") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A : B {}; + interface B : C {}; + interface C {}; + interface D {}; + C implements D; + D implements A; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow indirectly inheriting from an interface that indirectly implements us") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A; + interface B : A {}; + """) + results = parser.finish() + except: + 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/dom/bindings/parser/tests/test_interface_const_identifier_conflicts.py b/dom/bindings/parser/tests/test_interface_const_identifier_conflicts.py new file mode 100644 index 000000000..db944e7aa --- /dev/null +++ b/dom/bindings/parser/tests/test_interface_const_identifier_conflicts.py @@ -0,0 +1,15 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface IdentifierConflict { + const byte thing1 = 1; + const unsigned long thing1 = 1; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py b/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py new file mode 100644 index 000000000..1a73fb917 --- /dev/null +++ b/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py @@ -0,0 +1,60 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface IdentifierConflictAcrossMembers1 { + const byte thing1 = 1; + readonly attribute long thing1; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface IdentifierConflictAcrossMembers2 { + readonly attribute long thing1; + const byte thing1 = 1; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface IdentifierConflictAcrossMembers3 { + getter boolean thing1(DOMString name); + readonly attribute long thing1; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface IdentifierConflictAcrossMembers1 { + const byte thing1 = 1; + long thing1(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py new file mode 100644 index 000000000..ee5d870c2 --- /dev/null +++ b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py @@ -0,0 +1,691 @@ +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 + unrelatedMembers = [("unrelatedAttribute", WebIDL.IDLAttribute), + ("unrelatedMethod", WebIDL.IDLMethod)] + + # + # Simple Usage Tests + # + + shouldPass("Iterable (key only)", + """ + interface Foo1 { + iterable<long>; + readonly attribute unsigned long length; + getter long(unsigned long index); + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, valueIterableMembers + unrelatedMembers) + + shouldPass("Iterable (key only) inheriting from parent", + """ + interface Foo1 : Foo2 { + iterable<long>; + readonly attribute unsigned long length; + getter long(unsigned long index); + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, valueIterableMembers, numProductions=2) + + shouldPass("Iterable (key and value)", + """ + interface Foo1 { + iterable<long, long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, iterableMembers + unrelatedMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2) + + shouldPass("Iterable (key and value) inheriting from parent", + """ + interface Foo1 : Foo2 { + iterable<long, long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, iterableMembers, + # numProductions == 3 because of the generated iterator iface, + numProductions=3) + + shouldPass("Maplike (readwrite)", + """ + interface Foo1 { + maplike<long, long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers + unrelatedMembers) + + shouldPass("Maplike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + maplike<long, long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers, numProductions=2) + + shouldPass("Maplike (readwrite)", + """ + interface Foo1 { + maplike<long, long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers + unrelatedMembers) + + shouldPass("Maplike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + maplike<long, long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers, numProductions=2) + + shouldPass("Maplike (readonly)", + """ + interface Foo1 { + readonly maplike<long, long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapROMembers + unrelatedMembers) + + shouldPass("Maplike (readonly) inheriting from parent", + """ + interface Foo1 : Foo2 { + readonly maplike<long, long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapROMembers, numProductions=2) + + shouldPass("Setlike (readwrite)", + """ + interface Foo1 { + setlike<long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setRWMembers + unrelatedMembers) + + shouldPass("Setlike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + setlike<long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setRWMembers, numProductions=2) + + shouldPass("Setlike (readonly)", + """ + interface Foo1 { + readonly setlike<long>; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setROMembers + unrelatedMembers) + + shouldPass("Setlike (readonly) inheriting from parent", + """ + interface Foo1 : Foo2 { + readonly setlike<long>; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setROMembers, numProductions=2) + + 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/dom/bindings/parser/tests/test_lenientSetter.py b/dom/bindings/parser/tests/test_lenientSetter.py new file mode 100644 index 000000000..78a9ffe9e --- /dev/null +++ b/dom/bindings/parser/tests/test_lenientSetter.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 [LenientSetter] extended attribute MUST take no arguments. + should_throw(parser, harness, "no arguments", """ + interface I { + [LenientSetter=X] readonly attribute long A; + }; + """) + + # An attribute with the [LenientSetter] extended attribute MUST NOT + # also be declared with the [PutForwards] extended attribute. + should_throw(parser, harness, "PutForwards", """ + interface I { + [PutForwards=B, LenientSetter] readonly attribute J A; + }; + interface J { + attribute long B; + }; + """) + + # An attribute with the [LenientSetter] extended attribute MUST NOT + # also be declared with the [Replaceable] extended attribute. + should_throw(parser, harness, "Replaceable", """ + interface I { + [Replaceable, LenientSetter] readonly attribute J A; + }; + """) + + # The [LenientSetter] extended attribute MUST NOT be used on an + # attribute that is not read only. + should_throw(parser, harness, "writable attribute", """ + interface I { + [LenientSetter] attribute long A; + }; + """) + + # The [LenientSetter] extended attribute MUST NOT be used on a + # static attribute. + should_throw(parser, harness, "static attribute", """ + interface I { + [LenientSetter] static readonly attribute long A; + }; + """) diff --git a/dom/bindings/parser/tests/test_method.py b/dom/bindings/parser/tests/test_method.py new file mode 100644 index 000000000..cf7f1b40d --- /dev/null +++ b/dom/bindings/parser/tests/test_method.py @@ -0,0 +1,178 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestMethods { + void basic(); + static void basicStatic(); + void basicWithSimpleArgs(boolean arg1, byte arg2, unsigned long arg3); + boolean basicBoolean(); + static boolean basicStaticBoolean(); + boolean basicBooleanWithSimpleArgs(boolean arg1, byte arg2, unsigned long arg3); + void optionalArg(optional byte? arg1, optional sequence<byte> arg2); + void variadicArg(byte?... arg1); + object getObject(); + void setObject(object arg1); + void setAny(any arg1); + float doFloats(float arg1); + }; + """) + + results = parser.finish() + + harness.ok(True, "TestMethods interface parsed without error.") + harness.check(len(results), 1, "Should be one production.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestMethods", "Interface has the right QName") + harness.check(iface.identifier.name, "TestMethods", "Interface has the right name") + harness.check(len(iface.members), 12, "Expect 12 members") + + methods = iface.members + + def checkArgument(argument, QName, name, type, optional, variadic): + harness.ok(isinstance(argument, WebIDL.IDLArgument), + "Should be an IDLArgument") + harness.check(argument.identifier.QName(), QName, "Argument has the right QName") + harness.check(argument.identifier.name, name, "Argument has the right name") + harness.check(str(argument.type), type, "Argument has the right return type") + harness.check(argument.optional, optional, "Argument has the right optional value") + harness.check(argument.variadic, variadic, "Argument has the right variadic value") + + def checkMethod(method, QName, name, signatures, + static=False, getter=False, setter=False, creator=False, + deleter=False, legacycaller=False, stringifier=False): + harness.ok(isinstance(method, WebIDL.IDLMethod), + "Should be an IDLMethod") + harness.ok(method.isMethod(), "Method is a method") + harness.ok(not method.isAttr(), "Method is not an attr") + harness.ok(not method.isConst(), "Method is not a const") + harness.check(method.identifier.QName(), QName, "Method has the right QName") + harness.check(method.identifier.name, name, "Method has the right name") + harness.check(method.isStatic(), static, "Method has the correct static value") + harness.check(method.isGetter(), getter, "Method has the correct getter value") + harness.check(method.isSetter(), setter, "Method has the correct setter value") + harness.check(method.isCreator(), creator, "Method has the correct creator value") + harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") + harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") + harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") + harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") + + sigpairs = zip(method.signatures(), signatures) + for (gotSignature, expectedSignature) in sigpairs: + (gotRetType, gotArgs) = gotSignature + (expectedRetType, expectedArgs) = expectedSignature + + harness.check(str(gotRetType), expectedRetType, + "Method has the expected return type.") + + for i in range(0, len(gotArgs)): + (QName, name, type, optional, variadic) = expectedArgs[i] + checkArgument(gotArgs[i], QName, name, type, optional, variadic) + + checkMethod(methods[0], "::TestMethods::basic", "basic", [("Void", [])]) + checkMethod(methods[1], "::TestMethods::basicStatic", "basicStatic", + [("Void", [])], static=True) + checkMethod(methods[2], "::TestMethods::basicWithSimpleArgs", + "basicWithSimpleArgs", + [("Void", + [("::TestMethods::basicWithSimpleArgs::arg1", "arg1", "Boolean", False, False), + ("::TestMethods::basicWithSimpleArgs::arg2", "arg2", "Byte", False, False), + ("::TestMethods::basicWithSimpleArgs::arg3", "arg3", "UnsignedLong", False, False)])]) + checkMethod(methods[3], "::TestMethods::basicBoolean", "basicBoolean", [("Boolean", [])]) + checkMethod(methods[4], "::TestMethods::basicStaticBoolean", "basicStaticBoolean", [("Boolean", [])], static=True) + checkMethod(methods[5], "::TestMethods::basicBooleanWithSimpleArgs", + "basicBooleanWithSimpleArgs", + [("Boolean", + [("::TestMethods::basicBooleanWithSimpleArgs::arg1", "arg1", "Boolean", False, False), + ("::TestMethods::basicBooleanWithSimpleArgs::arg2", "arg2", "Byte", False, False), + ("::TestMethods::basicBooleanWithSimpleArgs::arg3", "arg3", "UnsignedLong", False, False)])]) + checkMethod(methods[6], "::TestMethods::optionalArg", + "optionalArg", + [("Void", + [("::TestMethods::optionalArg::arg1", "arg1", "ByteOrNull", True, False), + ("::TestMethods::optionalArg::arg2", "arg2", "ByteSequence", True, False)])]) + checkMethod(methods[7], "::TestMethods::variadicArg", + "variadicArg", + [("Void", + [("::TestMethods::variadicArg::arg1", "arg1", "ByteOrNull", True, True)])]) + checkMethod(methods[8], "::TestMethods::getObject", + "getObject", [("Object", [])]) + checkMethod(methods[9], "::TestMethods::setObject", + "setObject", + [("Void", + [("::TestMethods::setObject::arg1", "arg1", "Object", False, False)])]) + checkMethod(methods[10], "::TestMethods::setAny", + "setAny", + [("Void", + [("::TestMethods::setAny::arg1", "arg1", "Any", False, False)])]) + checkMethod(methods[11], "::TestMethods::doFloats", + "doFloats", + [("Float", + [("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])]) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + void foo(optional float bar = 1); + }; + """) + results = parser.finish() + except Exception, x: + threw = True + harness.ok(not threw, "Should allow integer to float type corecion") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [GetterThrows] void foo(); + }; + """) + results = parser.finish() + except Exception, x: + threw = True + 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/dom/bindings/parser/tests/test_mozmap.py b/dom/bindings/parser/tests/test_mozmap.py new file mode 100644 index 000000000..1a36fdd62 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_namespace.py b/dom/bindings/parser/tests/test_namespace.py new file mode 100644 index 000000000..74533a177 --- /dev/null +++ b/dom/bindings/parser/tests/test_namespace.py @@ -0,0 +1,223 @@ +def WebIDLTest(parser, harness): + parser.parse( + """ + namespace MyNamespace { + attribute any foo; + any bar(); + }; + """) + + results = parser.finish() + harness.check(len(results), 1, "Should have a thing.") + harness.ok(results[0].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[0].members), 2, + "Should have two things in our namespace") + harness.ok(results[0].members[0].isAttr(), "First member is attribute") + harness.ok(results[0].members[0].isStatic(), "Attribute should be static") + harness.ok(results[0].members[1].isMethod(), "Second member is method") + harness.ok(results[0].members[1].isStatic(), "Operation should be static") + + parser = parser.reset() + parser.parse( + """ + namespace MyNamespace { + attribute any foo; + }; + partial namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + harness.check(len(results), 2, "Should have things.") + harness.ok(results[0].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[0].members), 2, + "Should have two things in our namespace") + harness.ok(results[0].members[0].isAttr(), "First member is attribute") + harness.ok(results[0].members[0].isStatic(), "Attribute should be static"); + harness.ok(results[0].members[1].isMethod(), "Second member is method") + harness.ok(results[0].members[1].isStatic(), "Operation should be static"); + + parser = parser.reset() + parser.parse( + """ + partial namespace MyNamespace { + any bar(); + }; + namespace MyNamespace { + attribute any foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, "Should have things.") + harness.ok(results[1].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[1].members), 2, + "Should have two things in our namespace") + harness.ok(results[1].members[0].isAttr(), "First member is attribute") + harness.ok(results[1].members[0].isStatic(), "Attribute should be static"); + harness.ok(results[1].members[1].isMethod(), "Second member is method") + harness.ok(results[1].members[1].isStatic(), "Operation should be static"); + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + static attribute any foo; + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + static any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any bar(); + }; + + interface MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + partial namespace MyNamespace { + any baz(); + }; + + interface MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any bar(); + }; + + partial interface MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + partial interface MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface MyNamespace { + any bar(); + }; + + partial namespace MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_newobject.py b/dom/bindings/parser/tests/test_newobject.py new file mode 100644 index 000000000..26785c6a2 --- /dev/null +++ b/dom/bindings/parser/tests/test_newobject.py @@ -0,0 +1,70 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + # Basic functionality + parser.parse( + """ + interface Iface { + [NewObject] readonly attribute Iface attr; + [NewObject] Iface method(); + }; + """) + results = parser.finish() + harness.ok(results, "Should not have thrown on basic [NewObject] usage") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Pure, NewObject] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must depend on something") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Pure, NewObject] Iface method(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] methods must depend on something") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Cached, NewObject, Affects=Nothing] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must not be [Cached]") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [StoreInSlot, NewObject, Affects=Nothing] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must not be [StoreInSlot]") diff --git a/dom/bindings/parser/tests/test_nullable_equivalency.py b/dom/bindings/parser/tests/test_nullable_equivalency.py new file mode 100644 index 000000000..2b48b615d --- /dev/null +++ b/dom/bindings/parser/tests/test_nullable_equivalency.py @@ -0,0 +1,115 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestNullableEquivalency1 { + attribute long a; + attribute long? b; + }; + + interface TestNullableEquivalency2 { + attribute ArrayBuffer a; + attribute ArrayBuffer? b; + }; + + /* Can't have dictionary-valued attributes, so can't test that here */ + + enum TestNullableEquivalency4Enum { + "Foo", + "Bar" + }; + + interface TestNullableEquivalency4 { + attribute TestNullableEquivalency4Enum a; + attribute TestNullableEquivalency4Enum? b; + }; + + interface TestNullableEquivalency5 { + attribute TestNullableEquivalency4 a; + attribute TestNullableEquivalency4? b; + }; + + interface TestNullableEquivalency6 { + attribute boolean a; + attribute boolean? b; + }; + + interface TestNullableEquivalency7 { + attribute DOMString a; + attribute DOMString? b; + }; + + interface TestNullableEquivalency8 { + attribute float a; + attribute float? b; + }; + + interface TestNullableEquivalency9 { + attribute double a; + attribute double? b; + }; + + interface TestNullableEquivalency10 { + attribute object a; + attribute object? b; + }; + """) + + for decl in parser.finish(): + if decl.isInterface(): + checkEquivalent(decl, harness) + +def checkEquivalent(iface, harness): + type1 = iface.members[0].type + type2 = iface.members[1].type + + harness.check(type1.nullable(), False, 'attr1 should not be nullable') + harness.check(type2.nullable(), True, 'attr2 should be nullable') + + # We don't know about type1, but type2, the nullable type, definitely + # shouldn't be builtin. + harness.check(type2.builtin, False, 'attr2 should not be builtin') + + # Ensure that all attributes of type2 match those in type1, except for: + # - names on an ignore list, + # - names beginning with '_', + # - functions which throw when called with no args, and + # - class-level non-callables ("static variables"). + # + # Yes, this is an ugly, fragile hack. But it finds bugs... + for attr in dir(type1): + if attr.startswith('_') or \ + attr in ['nullable', 'builtin', 'filename', 'location', + 'inner', 'QName', 'getDeps', 'name'] or \ + (hasattr(type(type1), attr) and not callable(getattr(type1, attr))): + continue + + a1 = getattr(type1, attr) + + if callable(a1): + try: + v1 = a1() + except: + # Can't call a1 with no args, so skip this attriute. + continue + + try: + a2 = getattr(type2, attr) + except: + harness.ok(False, 'Missing %s attribute on type %s in %s' % (attr, type2, iface)) + continue + + if not callable(a2): + harness.ok(False, "%s attribute on type %s in %s wasn't callable" % (attr, type2, iface)) + continue + + v2 = a2() + harness.check(v2, v1, '%s method return value' % attr) + else: + try: + a2 = getattr(type2, attr) + except: + harness.ok(False, 'Missing %s attribute on type %s in %s' % (attr, type2, iface)) + continue + + harness.check(a2, a1, '%s attribute should match' % attr) diff --git a/dom/bindings/parser/tests/test_nullable_void.py b/dom/bindings/parser/tests/test_nullable_void.py new file mode 100644 index 000000000..961ff825e --- /dev/null +++ b/dom/bindings/parser/tests/test_nullable_void.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface NullableVoid { + void? foo(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_optional_constraints.py b/dom/bindings/parser/tests/test_optional_constraints.py new file mode 100644 index 000000000..6217465ce --- /dev/null +++ b/dom/bindings/parser/tests/test_optional_constraints.py @@ -0,0 +1,30 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface OptionalConstraints1 { + void foo(optional byte arg1, byte arg2); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(not threw, + "Should not have thrown on non-optional argument following " + "optional argument.") + + parser = parser.reset() + parser.parse(""" + interface OptionalConstraints2 { + void foo(optional byte arg1 = 1, optional byte arg2 = 2, + optional byte arg3, optional byte arg4 = 4, + optional byte arg5, optional byte arg6 = 9); + }; + """) + results = parser.finish() + args = results[0].members[0].signatures()[0][1] + harness.check(len(args), 6, "Should have 6 arguments") + harness.check(args[5].defaultValue.value, 9, + "Should have correct default value") diff --git a/dom/bindings/parser/tests/test_overload.py b/dom/bindings/parser/tests/test_overload.py new file mode 100644 index 000000000..3c680ad52 --- /dev/null +++ b/dom/bindings/parser/tests/test_overload.py @@ -0,0 +1,60 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestOverloads { + void basic(); + void basic(long arg1); + 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); + }; + """) + + results = parser.finish() + + harness.ok(True, "TestOverloads interface parsed without error.") + harness.check(len(results), 1, "Should be one production.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "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), 4, "Expect %s members" % 4) + + member = iface.members[0] + harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName") + harness.check(member.identifier.name, "basic", "Method has the right name") + harness.check(member.hasOverloads(), True, "Method has overloads") + + signatures = member.signatures() + harness.check(len(signatures), 2, "Method should have 2 signatures") + + (retval, argumentSet) = signatures[0] + + harness.check(str(retval), "Void", "Expect a void retval") + harness.check(len(argumentSet), 0, "Expect an empty argument set") + + (retval, argumentSet) = signatures[1] + harness.check(str(retval), "Void", "Expect a void retval") + harness.check(len(argumentSet), 1, "Expect an argument set with one argument") + + argument = argumentSet[0] + harness.ok(isinstance(argument, WebIDL.IDLArgument), + "Should be an IDLArgument") + 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/dom/bindings/parser/tests/test_promise.py b/dom/bindings/parser/tests/test_promise.py new file mode 100644 index 000000000..55bc07680 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_prototype_ident.py b/dom/bindings/parser/tests/test_prototype_ident.py new file mode 100644 index 000000000..d3932b54f --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_putForwards.py b/dom/bindings/parser/tests/test_putForwards.py new file mode 100644 index 000000000..86a1bf115 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_replaceable.py b/dom/bindings/parser/tests/test_replaceable.py new file mode 100644 index 000000000..93ee42ed9 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_sanity.py b/dom/bindings/parser/tests/test_sanity.py new file mode 100644 index 000000000..d3184c007 --- /dev/null +++ b/dom/bindings/parser/tests/test_sanity.py @@ -0,0 +1,7 @@ +def WebIDLTest(parser, harness): + parser.parse("") + parser.finish() + harness.ok(True, "Parsing nothing doesn't throw.") + parser.parse("interface Foo {};") + parser.finish() + harness.ok(True, "Parsing a silly interface doesn't throw.") diff --git a/dom/bindings/parser/tests/test_securecontext_extended_attribute.py b/dom/bindings/parser/tests/test_securecontext_extended_attribute.py new file mode 100644 index 000000000..084f19fa7 --- /dev/null +++ b/dom/bindings/parser/tests/test_securecontext_extended_attribute.py @@ -0,0 +1,332 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + partial interface TestSecureContextOnInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 6, "TestSecureContextOnInterface should have six members") + harness.ok(results[0].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members from partial interface") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members from partial interface") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members from partial interface") + + # Same thing, but with the partial interface specified first: + parser = parser.reset() + parser.parse(""" + partial interface TestSecureContextOnInterfaceAfterPartialInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + [SecureContext] + interface TestSecureContextOnInterfaceAfterPartialInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[1].members), 6, "TestSecureContextOnInterfaceAfterPartialInterface should have six members") + harness.ok(results[1].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[1].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members") + harness.ok(results[1].members[1].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members") + harness.ok(results[1].members[2].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members") + harness.ok(results[1].members[3].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members from partial interface") + harness.ok(results[1].members[4].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members from partial interface") + harness.ok(results[1].members[5].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members from partial interface") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnPartialInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + [SecureContext] + partial interface TestSecureContextOnPartialInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 6, "TestSecureContextOnPartialInterface should have six members") + harness.ok(results[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's constant members") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's attribute members") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's method members") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"), + "Constant members from [SecureContext] partial interface should be [SecureContext]") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute members from [SecureContext] partial interface should be [SecureContext]") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"), + "Method members from [SecureContext] partial interface should be [SecureContext]") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnInterfaceMembers { + const octet TEST_NON_SECURE_CONSTANT_1 = 0; + [SecureContext] + const octet TEST_SECURE_CONSTANT = 1; + const octet TEST_NON_SECURE_CONSTANT_2 = 2; + readonly attribute byte testNonSecureAttribute1; + [SecureContext] + readonly attribute byte testSecureAttribute; + readonly attribute byte testNonSecureAttribute2; + void testNonSecureMethod1(byte foo); + [SecureContext] + void testSecureMethod(byte foo); + void testNonSecureMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 9, "TestSecureContextOnInterfaceMembers should have nine members") + harness.ok(results[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] on members should not propagate up to the interface") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "Constant should not have [SecureContext] extended attribute") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "Constant should have [SecureContext] extended attribute") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Constant should not have [SecureContext] extended attribute") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Attribute should not have [SecureContext] extended attribute") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute should have [SecureContext] extended attribute") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None, + "Attribute should not have [SecureContext] extended attribute") + harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None, + "Method should not have [SecureContext] extended attribute") + harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"), + "Method should have [SecureContext] extended attribute") + harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None, + "Method should not have [SecureContext] extended attribute") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnPartialInterfaceMembers { + }; + partial interface TestSecureContextOnPartialInterfaceMembers { + const octet TEST_NON_SECURE_CONSTANT_1 = 0; + [SecureContext] + const octet TEST_SECURE_CONSTANT = 1; + const octet TEST_NON_SECURE_CONSTANT_2 = 2; + readonly attribute byte testNonSecureAttribute1; + [SecureContext] + readonly attribute byte testSecureAttribute; + readonly attribute byte testNonSecureAttribute2; + void testNonSecureMethod1(byte foo); + [SecureContext] + void testSecureMethod(byte foo); + void testNonSecureMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 9, "TestSecureContextOnPartialInterfaceMembers should have nine members") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "Constant from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "Constant from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Constant from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Attribute from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None, + "Attribute from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None, + "Method from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"), + "Method from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None, + "Method from partial interface should not have [SecureContext] extended attribute") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext=something] + interface TestSecureContextTakesNoValue1 { + const octet TEST_SECURE_CONSTANT = 0; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must take no arguments (testing on interface)") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextForOverloads1 { + [SecureContext] + void testSecureMethod(byte foo); + }; + partial interface TestSecureContextForOverloads1 { + void testSecureMethod(byte foo, byte bar); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "If [SecureContext] appears on an overloaded operation, then it MUST appear on all overloads") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextForOverloads2 { + [SecureContext] + void testSecureMethod(byte foo); + }; + partial interface TestSecureContextForOverloads2 { + [SecureContext] + void testSecureMethod(byte foo, byte bar); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "[SecureContext] can appear on an overloaded operation if it appears on all overloads") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterfaceAndMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on an interface and interface member") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextOnPartialInterfaceAndMember { + }; + [SecureContext] + partial interface TestSecureContextOnPartialInterfaceAndMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on a partial interface and one of the partial interface's member's") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterfaceAndPartialInterfaceMember { + }; + partial interface TestSecureContextOnInterfaceAndPartialInterfaceMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on an interface and one of its partial interface's member's") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInheritedInterface { + }; + interface TestSecureContextNotOnInheritingInterface : TestSecureContextOnInheritedInterface { + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must appear on interfaces that inherit from another [SecureContext] interface") + + # Test 'implements'. The behavior tested here may have to change depending + # on the resolution of https://github.com/heycam/webidl/issues/118 + parser = parser.reset() + parser.parse(""" + [SecureContext] + interface TestSecureContextInterfaceThatImplementsNonSecureContextInterface { + const octet TEST_CONSTANT = 0; + }; + interface TestNonSecureContextInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + TestSecureContextInterfaceThatImplementsNonSecureContextInterface implements TestNonSecureContextInterface; + """) + results = parser.finish() + harness.check(len(results[0].members), 4, "TestSecureContextInterfaceThatImplementsNonSecureContextInterface should have two members") + harness.ok(results[0].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members even when other members are copied from a non-[SecureContext] interface") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None, + "Constants copied from non-[SecureContext] interface should not be [SecureContext]") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Attributes copied from non-[SecureContext] interface should not be [SecureContext]") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Methods copied from non-[SecureContext] interface should not be [SecureContext]") + + # Test SecureContext and NoInterfaceObject + parser = parser.reset() + parser.parse(""" + [NoInterfaceObject, SecureContext] + interface TestSecureContextNoInterfaceObject { + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 1, "TestSecureContextNoInterfaceObject should have only one member") + harness.ok(results[0].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), + "Interface member should have [SecureContext] extended attribute") diff --git a/dom/bindings/parser/tests/test_special_method_signature_mismatch.py b/dom/bindings/parser/tests/test_special_method_signature_mismatch.py new file mode 100644 index 000000000..5ea1743d3 --- /dev/null +++ b/dom/bindings/parser/tests/test_special_method_signature_mismatch.py @@ -0,0 +1,294 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch1 { + getter long long foo(long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch2 { + getter void foo(unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch3 { + getter boolean foo(unsigned long index, boolean extraArg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch4 { + getter boolean foo(unsigned long... index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch5 { + getter boolean foo(optional unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch6 { + getter boolean foo(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch7 { + deleter long long foo(long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch9 { + deleter boolean foo(unsigned long index, boolean extraArg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch10 { + deleter boolean foo(unsigned long... index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch11 { + deleter boolean foo(optional unsigned long index); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch12 { + deleter boolean foo(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch13 { + setter long long foo(long index, long long value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch15 { + setter boolean foo(unsigned long index, boolean value, long long extraArg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch16 { + setter boolean foo(unsigned long index, boolean... value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch17 { + setter boolean foo(unsigned long index, optional boolean value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch18 { + setter boolean foo(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch20 { + creator long long foo(long index, long long value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch22 { + creator boolean foo(unsigned long index, boolean value, long long extraArg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch23 { + creator boolean foo(unsigned long index, boolean... value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch24 { + creator boolean foo(unsigned long index, optional boolean value); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodSignatureMismatch25 { + creator boolean foo(); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_special_methods.py b/dom/bindings/parser/tests/test_special_methods.py new file mode 100644 index 000000000..5b45c3399 --- /dev/null +++ b/dom/bindings/parser/tests/test_special_methods.py @@ -0,0 +1,85 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface SpecialMethods { + getter long long (unsigned long index); + setter long long (unsigned long index, long long value); + creator long long (unsigned long index, long long value); + getter boolean (DOMString name); + setter boolean (DOMString name, boolean value); + creator boolean (DOMString name, boolean value); + deleter boolean (DOMString name); + }; + + interface SpecialMethodsCombination { + setter creator long long (unsigned long index, long long value); + getter deleter boolean (DOMString name); + setter creator boolean (DOMString name, boolean value); + }; + """) + + results = parser.finish() + + def checkMethod(method, QName, name, + static=False, getter=False, setter=False, creator=False, + deleter=False, legacycaller=False, stringifier=False): + harness.ok(isinstance(method, WebIDL.IDLMethod), + "Should be an IDLMethod") + harness.check(method.identifier.QName(), QName, "Method has the right QName") + harness.check(method.identifier.name, name, "Method has the right name") + harness.check(method.isStatic(), static, "Method has the correct static value") + harness.check(method.isGetter(), getter, "Method has the correct getter value") + harness.check(method.isSetter(), setter, "Method has the correct setter value") + harness.check(method.isCreator(), creator, "Method has the correct creator value") + harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") + harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") + harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") + + harness.check(len(results), 2, "Expect 2 interfaces") + + iface = results[0] + harness.check(len(iface.members), 7, "Expect 7 members") + + checkMethod(iface.members[0], "::SpecialMethods::__indexedgetter", "__indexedgetter", + getter=True) + checkMethod(iface.members[1], "::SpecialMethods::__indexedsetter", "__indexedsetter", + setter=True) + checkMethod(iface.members[2], "::SpecialMethods::__indexedcreator", "__indexedcreator", + creator=True) + checkMethod(iface.members[3], "::SpecialMethods::__namedgetter", "__namedgetter", + getter=True) + checkMethod(iface.members[4], "::SpecialMethods::__namedsetter", "__namedsetter", + setter=True) + checkMethod(iface.members[5], "::SpecialMethods::__namedcreator", "__namedcreator", + creator=True) + checkMethod(iface.members[6], "::SpecialMethods::__nameddeleter", "__nameddeleter", + deleter=True) + + iface = results[1] + harness.check(len(iface.members), 3, "Expect 3 members") + + checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedsettercreator", + "__indexedsettercreator", setter=True, creator=True) + checkMethod(iface.members[1], "::SpecialMethodsCombination::__namedgetterdeleter", + "__namedgetterdeleter", getter=True, deleter=True) + checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedsettercreator", + "__namedsettercreator", setter=True, creator=True) + + parser = parser.reset(); + + threw = False + try: + parser.parse( + """ + interface IndexedDeleter { + deleter void(unsigned long index); + }; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "There are no indexed deleters") + + diff --git a/dom/bindings/parser/tests/test_special_methods_uniqueness.py b/dom/bindings/parser/tests/test_special_methods_uniqueness.py new file mode 100644 index 000000000..42e2c5bb7 --- /dev/null +++ b/dom/bindings/parser/tests/test_special_methods_uniqueness.py @@ -0,0 +1,62 @@ +import WebIDL + +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface SpecialMethodUniqueness1 { + getter deleter boolean (DOMString name); + getter boolean (DOMString name); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodUniqueness1 { + deleter boolean (DOMString name); + getter deleter boolean (DOMString name); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodUniqueness1 { + setter creator boolean (DOMString name); + creator boolean (DOMString name); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + threw = False + try: + parser.parse(""" + interface SpecialMethodUniqueness1 { + setter boolean (DOMString name); + creator setter boolean (DOMString name); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_stringifier.py b/dom/bindings/parser/tests/test_stringifier.py new file mode 100644 index 000000000..14c2c5226 --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_treatNonCallableAsNull.py b/dom/bindings/parser/tests/test_treatNonCallableAsNull.py new file mode 100644 index 000000000..7a0bde8a6 --- /dev/null +++ b/dom/bindings/parser/tests/test_treatNonCallableAsNull.py @@ -0,0 +1,71 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + [TreatNonCallableAsNull] callback Function = any(any... arguments); + + interface TestTreatNonCallableAsNull1 { + attribute Function? onfoo; + attribute Function onbar; + }; + """) + + results = parser.finish() + + iface = results[1] + attr = iface.members[0] + harness.check(attr.type.treatNonCallableAsNull(), True, "Got the expected value") + attr = iface.members[1] + harness.check(attr.type.treatNonCallableAsNull(), False, "Got the expected value") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + callback Function = any(any... arguments); + + interface TestTreatNonCallableAsNull2 { + [TreatNonCallableAsNull] attribute Function onfoo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + callback Function = any(any... arguments); + + [TreatNonCallableAsNull] + interface TestTreatNonCallableAsNull3 { + attribute Function onfoo; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [TreatNonCallableAsNull, TreatNonObjectAsNull] + callback Function = any(any... arguments); + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_typedef.py b/dom/bindings/parser/tests/test_typedef.py new file mode 100644 index 000000000..8921985c5 --- /dev/null +++ b/dom/bindings/parser/tests/test_typedef.py @@ -0,0 +1,76 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + typedef long mylong; + typedef long? mynullablelong; + interface Foo { + const mylong X = 5; + const mynullablelong Y = 7; + const mynullablelong Z = null; + void foo(mylong arg); + }; + """) + + results = parser.finish() + + harness.check(results[2].members[1].type.name, "LongOrNull", + "Should expand typedefs") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef long? mynullablelong; + interface Foo { + void foo(mynullablelong? Y); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on nullable inside nullable arg.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef long? mynullablelong; + interface Foo { + const mynullablelong? X = 5; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on nullable inside nullable const.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + const mynullablelong? X = 5; + }; + typedef long? mynullablelong; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown on nullable inside nullable const typedef " + "after interface.") + + parser = parser.reset() + parser.parse(""" + interface Foo { + const mylong X = 5; + }; + typedef long mylong; + """) + + results = parser.finish() + + harness.check(results[0].members[0].type.name, "Long", + "Should expand typedefs that come before interface") diff --git a/dom/bindings/parser/tests/test_unenumerable_own_properties.py b/dom/bindings/parser/tests/test_unenumerable_own_properties.py new file mode 100644 index 000000000..d017d5ce0 --- /dev/null +++ b/dom/bindings/parser/tests/test_unenumerable_own_properties.py @@ -0,0 +1,64 @@ +def WebIDLTest(parser, harness): + + parser.parse( + """ + interface Foo {}; + [LegacyUnenumerableNamedProperties] + interface Bar : Foo { + getter long(DOMString name); + }; + interface Baz : Bar { + getter long(DOMString name); + }; + """); + results = parser.finish(); + harness.check(len(results), 3, "Should have three interfaces") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties] + interface NoNamedGetter { + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties=Foo] + interface ShouldNotHaveArg { + getter long(DOMString name); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties] + interface Foo { + getter long(DOMString name); + }; + interface Bar : Foo {}; + [LegacyUnenumerableNamedProperties] + interface Baz : Bar { + getter long(DOMString name); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_unforgeable.py b/dom/bindings/parser/tests/test_unforgeable.py new file mode 100644 index 000000000..3787e8c6a --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_union.py b/dom/bindings/parser/tests/test_union.py new file mode 100644 index 000000000..9c4f2a56a --- /dev/null +++ b/dom/bindings/parser/tests/test_union.py @@ -0,0 +1,168 @@ +import WebIDL +import itertools +import string + +# We'd like to use itertools.chain but it's 2.6 or higher. +def chain(*iterables): + # chain('ABC', 'DEF') --> A B C D E F + for it in iterables: + for element in it: + yield element + +# We'd like to use itertools.combinations but it's 2.6 or higher. +def combinations(iterable, r): + # combinations('ABCD', 2) --> AB AC AD BC BD CD + # combinations(range(4), 3) --> 012 013 023 123 + pool = tuple(iterable) + n = len(pool) + if r > n: + return + indices = range(r) + yield tuple(pool[i] for i in indices) + while True: + for i in reversed(range(r)): + if indices[i] != i + n - r: + break + else: + return + indices[i] += 1 + for j in range(i+1, r): + indices[j] = indices[j-1] + 1 + yield tuple(pool[i] for i in indices) + +# We'd like to use itertools.combinations_with_replacement but it's 2.7 or +# higher. +def combinations_with_replacement(iterable, r): + # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC + pool = tuple(iterable) + n = len(pool) + if not n and r: + return + indices = [0] * r + yield tuple(pool[i] for i in indices) + while True: + for i in reversed(range(r)): + if indices[i] != n - 1: + break + else: + return + indices[i:] = [indices[i] + 1] * (r - i) + yield tuple(pool[i] for i in indices) + +def WebIDLTest(parser, harness): + types = ["float", + "double", + "short", + "unsigned short", + "long", + "unsigned long", + "long long", + "unsigned long long", + "boolean", + "byte", + "octet", + "DOMString", + "ByteString", + "USVString", + #"sequence<float>", + "object", + "ArrayBuffer", + #"Date", + "TestInterface1", + "TestInterface2"] + + testPre = """ + interface TestInterface1 { + }; + interface TestInterface2 { + }; + """ + + interface = testPre + """ + interface PrepareForTest { + """ + for (i, type) in enumerate(types): + interface += string.Template(""" + readonly attribute ${type} attr${i}; + """).substitute(i=i, type=type) + interface += """ + }; + """ + + parser.parse(interface) + results = parser.finish() + + iface = results[2] + + parser = parser.reset() + + def typesAreDistinguishable(t): + return all(u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) + def typesAreNotDistinguishable(t): + return any(not u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) + def unionTypeName(t): + if len(t) > 2: + t[0:2] = [unionTypeName(t[0:2])] + return "(" + " or ".join(t) + ")" + + # typeCombinations is an iterable of tuples containing the name of the type + # as a string and the parsed IDL type. + def unionTypes(typeCombinations, predicate): + for c in typeCombinations: + if predicate(t[1] for t in c): + yield unionTypeName([t[0] for t in c]) + + # We limit invalid union types with a union member type to the subset of 3 + # types with one invalid combination. + # typeCombinations is an iterable of tuples containing the name of the type + # as a string and the parsed IDL type. + def invalidUnionWithUnion(typeCombinations): + for c in typeCombinations: + if (typesAreNotDistinguishable((c[0][1], c[1][1])) and + typesAreDistinguishable((c[1][1], c[2][1])) and + typesAreDistinguishable((c[0][1], c[2][1]))): + yield unionTypeName([t[0] for t in c]) + + # Create a list of tuples containing the name of the type as a string and + # the parsed IDL type. + types = zip(types, (a.type for a in iface.members)) + + validUnionTypes = chain(unionTypes(combinations(types, 2), typesAreDistinguishable), + unionTypes(combinations(types, 3), typesAreDistinguishable)) + invalidUnionTypes = chain(unionTypes(combinations_with_replacement(types, 2), typesAreNotDistinguishable), + invalidUnionWithUnion(combinations(types, 3))) + interface = testPre + """ + interface TestUnion { + """ + for (i, type) in enumerate(validUnionTypes): + interface += string.Template(""" + void method${i}(${type} arg); + ${type} returnMethod${i}(); + attribute ${type} attr${i}; + void optionalMethod${i}(${type}? arg); + """).substitute(i=i, type=type) + interface += """ + }; + """ + parser.parse(interface) + results = parser.finish() + + parser = parser.reset() + + for invalid in invalidUnionTypes: + interface = testPre + string.Template(""" + interface TestUnion { + void method(${type} arg); + }; + """).substitute(type=invalid) + + threw = False + try: + parser.parse(interface) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() diff --git a/dom/bindings/parser/tests/test_union_any.py b/dom/bindings/parser/tests/test_union_any.py new file mode 100644 index 000000000..e34cadab4 --- /dev/null +++ b/dom/bindings/parser/tests/test_union_any.py @@ -0,0 +1,14 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface AnyNotInUnion { + void foo((any or DOMString) arg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/parser/tests/test_union_nullable.py b/dom/bindings/parser/tests/test_union_nullable.py new file mode 100644 index 000000000..08430a94a --- /dev/null +++ b/dom/bindings/parser/tests/test_union_nullable.py @@ -0,0 +1,53 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface OneNullableInUnion { + void foo((object? or DOMString?) arg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Two nullable member types of a union should have thrown.") + + parser.reset() + threw = False + + try: + parser.parse(""" + interface NullableInNullableUnion { + void foo((object? or DOMString)? arg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "A nullable union type with a nullable member type should have " + "thrown.") + + parser.reset() + threw = False + + try: + parser.parse(""" + interface NullableInUnionNullableUnionHelper { + }; + interface NullableInUnionNullableUnion { + void foo(((object? or DOMString) or NullableInUnionNullableUnionHelper)? arg); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "A nullable union type with a nullable member type should have " + "thrown.") diff --git a/dom/bindings/parser/tests/test_usvstring.py b/dom/bindings/parser/tests/test_usvstring.py new file mode 100644 index 000000000..3a1369abd --- /dev/null +++ b/dom/bindings/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/dom/bindings/parser/tests/test_variadic_callback.py b/dom/bindings/parser/tests/test_variadic_callback.py new file mode 100644 index 000000000..d9a78db20 --- /dev/null +++ b/dom/bindings/parser/tests/test_variadic_callback.py @@ -0,0 +1,10 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + callback TestVariadicCallback = any(any... arguments); + """) + + results = parser.finish() + + harness.ok(True, "TestVariadicCallback callback parsed without error.") diff --git a/dom/bindings/parser/tests/test_variadic_constraints.py b/dom/bindings/parser/tests/test_variadic_constraints.py new file mode 100644 index 000000000..7448e40d5 --- /dev/null +++ b/dom/bindings/parser/tests/test_variadic_constraints.py @@ -0,0 +1,63 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface VariadicConstraints1 { + void foo(byte... arg1, byte arg2); + }; + """) + results = parser.finish() + + except: + threw = True + + harness.ok(threw, + "Should have thrown on variadic argument followed by required " + "argument.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface VariadicConstraints2 { + void foo(byte... arg1, optional byte arg2); + }; + """) + results = parser.finish(); + except: + threw = True + + harness.ok(threw, + "Should have thrown on variadic argument followed by optional " + "argument.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface VariadicConstraints3 { + void foo(optional byte... arg1); + }; + """) + results = parser.finish() + + except: + threw = True + + harness.ok(threw, + "Should have thrown on variadic argument explicitly flagged as " + "optional.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface VariadicConstraints4 { + void foo(byte... arg1 = 0); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown on variadic argument with default value.") |