summaryrefslogtreecommitdiffstats
path: root/dom/bindings/parser/tests/test_attributes_on_types.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings/parser/tests/test_attributes_on_types.py')
-rw-r--r--dom/bindings/parser/tests/test_attributes_on_types.py567
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",
+ )