diff options
Diffstat (limited to 'dom/bindings/parser/tests/test_attributes_on_types.py')
-rw-r--r-- | dom/bindings/parser/tests/test_attributes_on_types.py | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/dom/bindings/parser/tests/test_attributes_on_types.py b/dom/bindings/parser/tests/test_attributes_on_types.py new file mode 100644 index 0000000000..d0a0c7a72c --- /dev/null +++ b/dom/bindings/parser/tests/test_attributes_on_types.py @@ -0,0 +1,567 @@ +def WebIDLTest(parser, harness): + # Basic functionality + threw = False + try: + parser.parse( + """ + typedef [EnforceRange] long Foo; + typedef [Clamp] long Bar; + typedef [LegacyNullToEmptyString] DOMString Baz; + dictionary A { + required [EnforceRange] long a; + required [Clamp] long b; + [ChromeOnly, EnforceRange] long c; + Foo d; + }; + interface B { + attribute Foo typedefFoo; + attribute [EnforceRange] long foo; + attribute [Clamp] long bar; + attribute [LegacyNullToEmptyString] DOMString baz; + undefined method([EnforceRange] long foo, [Clamp] long bar, + [LegacyNullToEmptyString] DOMString baz); + undefined method2(optional [EnforceRange] long foo, optional [Clamp] long bar, + optional [LegacyNullToEmptyString] DOMString baz); + undefined method3(optional [LegacyNullToEmptyString] UTF8String foo = ""); + }; + interface C { + attribute [EnforceRange] long? foo; + attribute [Clamp] long? bar; + undefined method([EnforceRange] long? foo, [Clamp] long? bar); + undefined method2(optional [EnforceRange] long? foo, optional [Clamp] long? bar); + }; + interface Setlike { + setlike<[Clamp] long>; + }; + interface Maplike { + maplike<[Clamp] long, [EnforceRange] long>; + }; + interface Iterable { + iterable<[Clamp] long, [EnforceRange] long>; + }; + """ + ) + results = parser.finish() + except Exception: + threw = True + + harness.ok(not threw, "Should not have thrown on parsing normal") + if not threw: + harness.check( + results[0].innerType.hasEnforceRange(), True, "Foo is [EnforceRange]" + ) + harness.check(results[1].innerType.hasClamp(), True, "Bar is [Clamp]") + harness.check( + results[2].innerType.legacyNullToEmptyString, + True, + "Baz is [LegacyNullToEmptyString]", + ) + A = results[3] + harness.check( + A.members[0].type.hasEnforceRange(), True, "A.a is [EnforceRange]" + ) + harness.check(A.members[1].type.hasClamp(), True, "A.b is [Clamp]") + harness.check( + A.members[2].type.hasEnforceRange(), True, "A.c is [EnforceRange]" + ) + harness.check( + A.members[3].type.hasEnforceRange(), True, "A.d is [EnforceRange]" + ) + B = results[4] + harness.check( + B.members[0].type.hasEnforceRange(), True, "B.typedefFoo is [EnforceRange]" + ) + harness.check( + B.members[1].type.hasEnforceRange(), True, "B.foo is [EnforceRange]" + ) + harness.check(B.members[2].type.hasClamp(), True, "B.bar is [Clamp]") + harness.check( + B.members[3].type.legacyNullToEmptyString, + True, + "B.baz is [LegacyNullToEmptyString]", + ) + method = B.members[4].signatures()[0][1] + harness.check( + method[0].type.hasEnforceRange(), + True, + "foo argument of method is [EnforceRange]", + ) + harness.check( + method[1].type.hasClamp(), True, "bar argument of method is [Clamp]" + ) + harness.check( + method[2].type.legacyNullToEmptyString, + True, + "baz argument of method is [LegacyNullToEmptyString]", + ) + method2 = B.members[5].signatures()[0][1] + harness.check( + method2[0].type.hasEnforceRange(), + True, + "foo argument of method2 is [EnforceRange]", + ) + harness.check( + method2[1].type.hasClamp(), True, "bar argument of method2 is [Clamp]" + ) + harness.check( + method2[2].type.legacyNullToEmptyString, + True, + "baz argument of method2 is [LegacyNullToEmptyString]", + ) + + method3 = B.members[6].signatures()[0][1] + harness.check( + method3[0].type.legacyNullToEmptyString, + True, + "bar argument of method2 is [LegacyNullToEmptyString]", + ) + harness.check( + method3[0].defaultValue.type.isUTF8String(), + True, + "default value of bar argument of method2 is correctly coerced to UTF8String", + ) + + C = results[5] + harness.ok(C.members[0].type.nullable(), "C.foo is nullable") + harness.ok(C.members[0].type.hasEnforceRange(), "C.foo has [EnforceRange]") + harness.ok(C.members[1].type.nullable(), "C.bar is nullable") + harness.ok(C.members[1].type.hasClamp(), "C.bar has [Clamp]") + method = C.members[2].signatures()[0][1] + harness.ok(method[0].type.nullable(), "foo argument of method is nullable") + harness.ok( + method[0].type.hasEnforceRange(), + "foo argument of method has [EnforceRange]", + ) + harness.ok(method[1].type.nullable(), "bar argument of method is nullable") + harness.ok(method[1].type.hasClamp(), "bar argument of method has [Clamp]") + method2 = C.members[3].signatures()[0][1] + harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable") + harness.ok( + method2[0].type.hasEnforceRange(), + "foo argument of method2 has [EnforceRange]", + ) + harness.ok(method2[1].type.nullable(), "bar argument of method2 is nullable") + harness.ok(method2[1].type.hasClamp(), "bar argument of method2 has [Clamp]") + + # Test [AllowShared] + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [AllowShared] ArrayBufferView Foo; + dictionary A { + required [AllowShared] ArrayBufferView a; + [ChromeOnly, AllowShared] ArrayBufferView b; + Foo c; + }; + interface B { + attribute Foo typedefFoo; + attribute [AllowShared] ArrayBufferView foo; + undefined method([AllowShared] ArrayBufferView foo); + undefined method2(optional [AllowShared] ArrayBufferView foo); + }; + interface C { + attribute [AllowShared] ArrayBufferView? foo; + undefined method([AllowShared] ArrayBufferView? foo); + undefined method2(optional [AllowShared] ArrayBufferView? foo); + }; + interface Setlike { + setlike<[AllowShared] ArrayBufferView>; + }; + interface Maplike { + maplike<[Clamp] long, [AllowShared] ArrayBufferView>; + }; + interface Iterable { + iterable<[Clamp] long, [AllowShared] ArrayBufferView>; + }; + """ + ) + results = parser.finish() + except Exception: + threw = True + + harness.ok(not threw, "Should not have thrown on parsing normal") + if not threw: + harness.ok(results[0].innerType.hasAllowShared(), "Foo is [AllowShared]") + A = results[1] + harness.ok(A.members[0].type.hasAllowShared(), "A.a is [AllowShared]") + harness.ok(A.members[1].type.hasAllowShared(), "A.b is [AllowShared]") + harness.ok(A.members[2].type.hasAllowShared(), "A.c is [AllowShared]") + B = results[2] + harness.ok(B.members[0].type.hasAllowShared(), "B.typedefFoo is [AllowShared]") + harness.ok(B.members[1].type.hasAllowShared(), "B.foo is [AllowShared]") + method = B.members[2].signatures()[0][1] + harness.ok( + method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]" + ) + method2 = B.members[3].signatures()[0][1] + harness.ok( + method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]" + ) + C = results[3] + harness.ok(C.members[0].type.nullable(), "C.foo is nullable") + harness.ok(C.members[0].type.hasAllowShared(), "C.foo is [AllowShared]") + method = C.members[1].signatures()[0][1] + harness.ok(method[0].type.nullable(), "foo argument of method is nullable") + harness.ok( + method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]" + ) + method2 = C.members[2].signatures()[0][1] + harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable") + harness.ok( + method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]" + ) + + ATTRIBUTES = [ + ("[Clamp]", "long"), + ("[EnforceRange]", "long"), + ("[LegacyNullToEmptyString]", "DOMString"), + ("[AllowShared]", "ArrayBufferView"), + ] + TEMPLATES = [ + ( + "required dictionary members", + """ + dictionary Foo { + %s required %s foo; + }; + """, + ), + ( + "optional arguments", + """ + interface Foo { + undefined foo(%s optional %s foo); + }; + """, + ), + ( + "typedefs", + """ + %s typedef %s foo; + """, + ), + ( + "attributes", + """ + interface Foo { + %s attribute %s foo; + }; + """, + ), + ( + "readonly attributes", + """ + interface Foo { + readonly attribute %s %s foo; + }; + """, + ), + ( + "readonly unresolved attributes", + """ + interface Foo { + readonly attribute Bar baz; + }; + typedef %s %s Bar; + """, + ), + ( + "method", + """ + interface Foo { + %s %s foo(); + }; + """, + ), + ( + "interface", + """ + %s + interface Foo { + attribute %s foo; + }; + """, + ), + ( + "partial interface", + """ + interface Foo { + undefined foo(); + }; + %s + partial interface Foo { + attribute %s bar; + }; + """, + ), + ( + "interface mixin", + """ + %s + interface mixin Foo { + attribute %s foo; + }; + """, + ), + ( + "namespace", + """ + %s + namespace Foo { + attribute %s foo; + }; + """, + ), + ( + "partial namespace", + """ + namespace Foo { + undefined foo(); + }; + %s + partial namespace Foo { + attribute %s bar; + }; + """, + ), + ( + "dictionary", + """ + %s + dictionary Foo { + %s foo; + }; + """, + ), + ] + + for (name, template) in TEMPLATES: + parser = parser.reset() + threw = False + try: + parser.parse(template % ("", "long")) + parser.finish() + except Exception: + threw = True + harness.ok(not threw, "Template for %s parses without attributes" % name) + for (attribute, type) in ATTRIBUTES: + parser = parser.reset() + threw = False + try: + parser.parse(template % (attribute, type)) + parser.finish() + except Exception: + threw = True + harness.ok(threw, "Should not allow %s on %s" % (attribute, name)) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [Clamp, EnforceRange] long Foo; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange]") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [EnforceRange, Clamp] long Foo; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange]") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [Clamp] long Foo; + typedef [EnforceRange] Foo bar; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [EnforceRange] long Foo; + typedef [Clamp] Foo bar; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs") + + TYPES = [ + "DOMString", + "unrestricted float", + "float", + "unrestricted double", + "double", + ] + + for type in TYPES: + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [Clamp] %s Foo; + """ + % type + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow [Clamp] on %s" % type) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [EnforceRange] %s Foo; + """ + % type + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow [EnforceRange] on %s" % type) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [LegacyNullToEmptyString] long Foo; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow [LegacyNullToEmptyString] on long") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [LegacyNullToEmptyString] JSString Foo; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should not allow [LegacyNullToEmptyString] on JSString") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [LegacyNullToEmptyString] DOMString? Foo; + """ + ) + parser.finish() + except Exception: + threw = True + + harness.ok( + threw, "Should not allow [LegacyNullToEmptyString] on nullable DOMString" + ) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [AllowShared] DOMString Foo; + """ + ) + results = parser.finish() + except Exception: + threw = True + harness.ok(threw, "[AllowShared] only allowed on buffer source types") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + typedef [AllowShared=something] ArrayBufferView Foo; + """ + ) + results = parser.finish() + except Exception: + threw = True + harness.ok(threw, "[AllowShared] must take no arguments") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Foo { + undefined foo([Clamp] Bar arg); + }; + typedef long Bar; + """ + ) + results = parser.finish() + except Exception: + threw = True + harness.ok(not threw, "Should allow type attributes on unresolved types") + harness.check( + results[0].members[0].signatures()[0][1][0].type.hasClamp(), + True, + "Unresolved types with type attributes should correctly resolve with attributes", + ) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Foo { + undefined foo(Bar arg); + }; + typedef [Clamp] long Bar; + """ + ) + results = parser.finish() + except Exception: + threw = True + harness.ok(not threw, "Should allow type attributes on typedefs") + harness.check( + results[0].members[0].signatures()[0][1][0].type.hasClamp(), + True, + "Unresolved types that resolve to typedefs with attributes should correctly resolve with " + "attributes", + ) |