Update the WebIDL parser

Upstream doesn't allow downloading .tar.gz archives so update.sh was changed
to use unzip.
This commit is contained in:
Anthony Ramine 2020-03-14 10:54:04 +01:00
parent 6ab923c8e8
commit 4930479ac8
11 changed files with 533 additions and 204 deletions

View file

@ -25,6 +25,12 @@ def WebIDLTest(parser, harness):
void method2(optional [EnforceRange] long foo, optional [Clamp] long bar,
optional [TreatNullAs=EmptyString] DOMString baz);
};
interface C {
attribute [EnforceRange] long? foo;
attribute [Clamp] long? bar;
void method([EnforceRange] long? foo, [Clamp] long? bar);
void method2(optional [EnforceRange] long? foo, optional [Clamp] long? bar);
};
interface Setlike {
setlike<[Clamp] long>;
};
@ -41,29 +47,105 @@ def WebIDLTest(parser, harness):
harness.ok(not threw, "Should not have thrown on parsing normal")
if not threw:
harness.check(results[0].innerType.enforceRange, True, "Foo is [EnforceRange]")
harness.check(results[1].innerType.clamp, True, "Bar is [Clamp]")
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.treatNullAsEmpty, True, "Baz is [TreatNullAs=EmptyString]")
A = results[3]
harness.check(A.members[0].type.enforceRange, True, "A.a is [EnforceRange]")
harness.check(A.members[1].type.clamp, True, "A.b is [Clamp]")
harness.check(A.members[2].type.enforceRange, True, "A.c is [EnforceRange]")
harness.check(A.members[3].type.enforceRange, True, "A.d is [EnforceRange]")
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.enforceRange, True, "B.typedefFoo is [EnforceRange]")
harness.check(B.members[1].type.enforceRange, True, "B.foo is [EnforceRange]")
harness.check(B.members[2].type.clamp, True, "B.bar is [Clamp]")
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.treatNullAsEmpty, True, "B.baz is [TreatNullAs=EmptyString]")
method = B.members[4].signatures()[0][1]
harness.check(method[0].type.enforceRange, True, "foo argument of method is [EnforceRange]")
harness.check(method[1].type.clamp, True, "bar argument of method is [Clamp]")
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.treatNullAsEmpty, True, "baz argument of method is [TreatNullAs=EmptyString]")
method2 = B.members[5].signatures()[0][1]
harness.check(method[0].type.enforceRange, True, "foo argument of method2 is [EnforceRange]")
harness.check(method[1].type.clamp, True, "bar argument of method2 is [Clamp]")
harness.check(method[0].type.hasEnforceRange(), True, "foo argument of method2 is [EnforceRange]")
harness.check(method[1].type.hasClamp(), True, "bar argument of method2 is [Clamp]")
harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method2 is [TreatNullAs=EmptyString]")
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]")
ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"), ("[TreatNullAs=EmptyString]", "DOMString")]
# 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;
void method([AllowShared] ArrayBufferView foo);
void method2(optional [AllowShared] ArrayBufferView foo);
};
interface C {
attribute [AllowShared] ArrayBufferView? foo;
void method([AllowShared] ArrayBufferView? foo);
void 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:
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"),
("[TreatNullAs=EmptyString]", "DOMString"), ("[AllowShared]", "ArrayBufferView")]
TEMPLATES = [
("required dictionary members", """
dictionary Foo {
@ -93,7 +175,54 @@ def WebIDLTest(parser, harness):
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 {
void 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 {
void foo();
};
%s
partial namespace Foo {
attribute %s bar;
};
"""),
("dictionary","""
%s
dictionary Foo {
%s foo;
};
""")
];
for (name, template) in TEMPLATES:
@ -167,30 +296,32 @@ def WebIDLTest(parser, harness):
harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs")
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [Clamp] DOMString Foo;
""")
parser.finish()
except:
threw = True
TYPES = ["DOMString", "unrestricted float", "float", "unrestricted double", "double"]
harness.ok(threw, "Should not allow [Clamp] on DOMString")
for type in TYPES:
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [Clamp] %s Foo;
""" % type)
parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow [Clamp] on %s" % type)
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [EnforceRange] DOMString Foo;
""")
parser.finish()
except:
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [EnforceRange] %s Foo;
""" % type)
parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow [EnforceRange] on DOMString")
harness.ok(threw, "Should not allow [EnforceRange] on %s" % type)
parser = parser.reset()
@ -217,6 +348,40 @@ def WebIDLTest(parser, harness):
harness.ok(threw, "Should not allow [TreatNullAs] on JSString")
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [TreatNullAs=EmptyString] DOMString? Foo;
""")
parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow [TreatNullAs] on nullable DOMString")
parser = parser.reset()
threw = False
try:
parser.parse("""
typedef [AllowShared] DOMString Foo;
""")
results = parser.finish()
except:
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:
threw = True
harness.ok(threw, "[AllowShared] must take no arguments")
parser = parser.reset()
threw = False
try:
@ -230,7 +395,7 @@ def WebIDLTest(parser, harness):
except:
threw = True
harness.ok(not threw, "Should allow type attributes on unresolved types")
harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True,
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()
@ -246,5 +411,5 @@ def WebIDLTest(parser, harness):
except:
threw = True
harness.ok(not threw, "Should allow type attributes on typedefs")
harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True,
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")

View file

@ -11,9 +11,9 @@ def WebIDLTest(parser, harness):
harness.check(argument.variadic, variadic, "Argument has the right variadic value")
def checkMethod(method, QName, name, signatures,
static=True, getter=False, setter=False,
deleter=False, legacycaller=False, stringifier=False,
chromeOnly=False, htmlConstructor=False):
static=True, getter=False, setter=False, deleter=False,
legacycaller=False, stringifier=False, chromeOnly=False,
htmlConstructor=False, secureContext=False, pref=None, func=None):
harness.ok(isinstance(method, WebIDL.IDLMethod),
"Should be an IDLMethod")
harness.ok(method.isMethod(), "Method is a method")
@ -30,6 +30,9 @@ def WebIDLTest(parser, harness):
harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly")
harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value")
harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
harness.check(method.getExtendedAttribute("Pref"), pref, "Method has the correct pref value")
harness.check(method.getExtendedAttribute("Func"), func, "Method has the correct func value")
harness.check(method.getExtendedAttribute("SecureContext") is not None, secureContext, "Method has the correct SecureContext value")
sigpairs = zip(method.signatures(), signatures)
for (gotSignature, expectedSignature) in sigpairs:
@ -88,6 +91,21 @@ def WebIDLTest(parser, harness):
results = parser.finish()
checkResults(results)
parser = parser.reset()
parser.parse("""
interface TestPrefConstructor {
[Pref="dom.webidl.test1"] constructor();
};
""")
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(), "::TestPrefConstructor::constructor",
"constructor", [("TestPrefConstructor (Wrapper)", [])],
pref=["dom.webidl.test1"])
parser = parser.reset()
parser.parse("""
interface TestChromeOnlyConstructor {
@ -103,6 +121,53 @@ def WebIDLTest(parser, harness):
"constructor", [("TestChromeOnlyConstructor (Wrapper)", [])],
chromeOnly=True)
parser = parser.reset()
parser.parse("""
interface TestSCConstructor {
[SecureContext] constructor();
};
""")
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(), "::TestSCConstructor::constructor",
"constructor", [("TestSCConstructor (Wrapper)", [])],
secureContext=True)
parser = parser.reset()
parser.parse("""
interface TestFuncConstructor {
[Func="Document::IsWebAnimationsEnabled"] constructor();
};
""")
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(), "::TestFuncConstructor::constructor",
"constructor", [("TestFuncConstructor (Wrapper)", [])],
func=["Document::IsWebAnimationsEnabled"])
parser = parser.reset()
parser.parse("""
interface TestPrefChromeOnlySCFuncConstructor {
[ChromeOnly, Pref="dom.webidl.test1", SecureContext, Func="Document::IsWebAnimationsEnabled"]
constructor();
};
""")
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(), "::TestPrefChromeOnlySCFuncConstructor::constructor",
"constructor", [("TestPrefChromeOnlySCFuncConstructor (Wrapper)", [])],
func=["Document::IsWebAnimationsEnabled"], pref=["dom.webidl.test1"],
chromeOnly=True, secureContext=True)
parser = parser.reset()
parser.parse("""
interface TestHTMLConstructor {

View file

@ -1,15 +0,0 @@
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")

View file

@ -149,7 +149,7 @@ def WebIDLTest(parser, harness):
# Now let's test our whole distinguishability table
argTypes = [ "long", "short", "long?", "short?", "boolean",
"boolean?", "DOMString", "ByteString", "Enum", "Enum2",
"boolean?", "DOMString", "ByteString", "UTF8String", "Enum", "Enum2",
"Interface", "Interface?",
"AncestorInterface", "UnrelatedInterface", "CallbackInterface",
"CallbackInterface?", "CallbackInterface2",
@ -158,14 +158,12 @@ def WebIDLTest(parser, harness):
"record<DOMString, object>",
"record<USVString, Dict>",
"record<ByteString, long>",
"Date", "Date?", "any",
"Promise<any>", "Promise<any>?",
"USVString", "JSString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
"record<UTF8String, long>",
"any", "Promise<any>", "Promise<any>?",
"USVString", "JSString", "ArrayBuffer", "ArrayBufferView",
"Uint8Array", "Uint16Array",
"(long or Callback)", "(long or Dict)",
]
# When we can parse Date, we need to add it here.
# XXXbz we can, and should really do that...
# Try to categorize things a bit to keep list lengths down
def allBut(list1, list2):
@ -177,26 +175,24 @@ def WebIDLTest(parser, harness):
primitives = numerics + booleans
nonNumerics = allBut(argTypes, numerics + unions)
nonBooleans = allBut(argTypes, booleans)
strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString" ]
strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString", "UTF8String" ]
nonStrings = allBut(argTypes, strings)
nonObjects = primitives + strings
objects = allBut(argTypes, nonObjects )
bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"]
sharedBufferSourceTypes = ["SharedArrayBuffer"]
interfaces = [ "Interface", "Interface?", "AncestorInterface",
"UnrelatedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
"UnrelatedInterface" ] + bufferSourceTypes
nullables = (["long?", "short?", "boolean?", "Interface?",
"CallbackInterface?", "Dict", "Dict2",
"Date?", "any", "Promise<any>?"] +
allBut(unions, [ "(long or Callback)" ]))
dates = [ "Date", "Date?" ]
sequences = [ "sequence<long>", "sequence<short>" ]
nonUserObjects = nonObjects + interfaces + dates + sequences
nonUserObjects = nonObjects + interfaces + sequences
otherObjects = allBut(argTypes, nonUserObjects + ["object"])
notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
otherObjects + sequences + bufferSourceTypes)
records = [ "record<DOMString, object>", "record<USVString, Dict>",
"record<ByteString, long>" ] # JSString not supported in records
"record<ByteString, long>", "record<UTF8String, long>" ] # JSString not supported in records
# Build a representation of the distinguishability table as a dict
# of dicts, holding True values where needed, holes elsewhere.
@ -215,6 +211,7 @@ def WebIDLTest(parser, harness):
setDistinguishable("boolean?", allBut(nonBooleans, nullables))
setDistinguishable("DOMString", nonStrings)
setDistinguishable("ByteString", nonStrings)
setDistinguishable("UTF8String", nonStrings)
setDistinguishable("USVString", nonStrings)
setDistinguishable("JSString", nonStrings)
setDistinguishable("Enum", nonStrings)
@ -240,8 +237,7 @@ def WebIDLTest(parser, harness):
setDistinguishable("record<USVString, Dict>", nonUserObjects)
# JSString not supported in records
setDistinguishable("record<ByteString, long>", nonUserObjects)
setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
setDistinguishable("record<UTF8String, long>", nonUserObjects)
setDistinguishable("any", [])
setDistinguishable("Promise<any>", [])
setDistinguishable("Promise<any>?", [])
@ -249,7 +245,6 @@ def WebIDLTest(parser, harness):
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"]))
setDistinguishable("(long or Callback)",
allBut(nonUserObjects, numerics))
setDistinguishable("(long or Dict)",

View file

@ -56,9 +56,9 @@ def WebIDLTest(parser, harness):
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].type.clamp,
harness.ok(results[0].members[0].signatures()[0][1][0].type.hasClamp(),
"Should be clamped")
harness.ok(not results[0].members[1].signatures()[0][1][0].type.clamp,
harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasClamp(),
"Should not be clamped")
parser = parser.reset()
@ -86,9 +86,9 @@ def WebIDLTest(parser, harness):
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].type.enforceRange,
harness.ok(results[0].members[0].signatures()[0][1][0].type.hasEnforceRange(),
"Should be enforceRange")
harness.ok(not results[0].members[1].signatures()[0][1][0].type.enforceRange,
harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasEnforceRange(),
"Should not be enforceRange")
parser = parser.reset()

View file

@ -80,7 +80,7 @@ def checkEquivalent(iface, harness):
for attr in dir(type1):
if attr.startswith('_') or \
attr in ['nullable', 'builtin', 'filename', 'location',
'inner', 'QName', 'getDeps', 'name'] or \
'inner', 'QName', 'getDeps', 'name', 'prettyName'] or \
(hasattr(type(type1), attr) and not callable(getattr(type1, attr))):
continue

View file

@ -85,7 +85,7 @@ def WebIDLTest(parser, harness):
JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long",
"unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean",
"DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
"DOMString", "ByteString", "UTF8String", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array",
"Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ]
@ -129,9 +129,12 @@ def WebIDLTest(parser, harness):
doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False,
"record<DOMString, %s> should be a JSON type" % type)
doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False,
doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False,
"record<ByteString, %s> should be a JSON type" % type)
doTest("interface Test { record<UTF8String, %s> toJSON(); };" % type, False,
"record<UTF8String, %s> should be a JSON type" % type)
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False,
"record<USVString, %s> should be a JSON type" % type)
@ -174,12 +177,12 @@ def WebIDLTest(parser, harness):
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True,
"record<USVString, %s> should not be a JSON type" % type)
if type != "any":
doTest("interface Foo { object toJSON(); }; "
"interface Test { (Foo or %s) toJSON(); };" % type, True,
"union containing a non-JSON type (%s) should not be a JSON type" % type)
doTest("interface test { %s? toJSON(); };" % type, True,
"Nullable type (%s) should not be a JSON type" % type)