| 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", |
| "prettyName", |
| ] |
| or (hasattr(type(type1), attr) and not callable(getattr(type1, attr))) |
| ): |
| continue |
| |
| a1 = getattr(type1, attr) |
| |
| if callable(a1): |
| try: |
| v1 = a1() |
| except AssertionError: |
| # Various methods assert that they're called on objects of |
| # the right type, skip them if the assert fails. |
| continue |
| except TypeError: |
| # a1 requires positional arguments, so skip this attribute. |
| continue |
| |
| try: |
| a2 = getattr(type2, attr) |
| except WebIDL.WebIDLError: |
| 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 WebIDL.WebIDLError: |
| harness.ok( |
| False, |
| "Missing %s attribute on type %s in %s" % (attr, type2, iface), |
| ) |
| continue |
| |
| harness.check(a2, a1, "%s attribute should match" % attr) |