michael@0: import WebIDL michael@0: import itertools michael@0: import string michael@0: michael@0: # We'd like to use itertools.chain but it's 2.6 or higher. michael@0: def chain(*iterables): michael@0: # chain('ABC', 'DEF') --> A B C D E F michael@0: for it in iterables: michael@0: for element in it: michael@0: yield element michael@0: michael@0: # We'd like to use itertools.combinations but it's 2.6 or higher. michael@0: def combinations(iterable, r): michael@0: # combinations('ABCD', 2) --> AB AC AD BC BD CD michael@0: # combinations(range(4), 3) --> 012 013 023 123 michael@0: pool = tuple(iterable) michael@0: n = len(pool) michael@0: if r > n: michael@0: return michael@0: indices = range(r) michael@0: yield tuple(pool[i] for i in indices) michael@0: while True: michael@0: for i in reversed(range(r)): michael@0: if indices[i] != i + n - r: michael@0: break michael@0: else: michael@0: return michael@0: indices[i] += 1 michael@0: for j in range(i+1, r): michael@0: indices[j] = indices[j-1] + 1 michael@0: yield tuple(pool[i] for i in indices) michael@0: michael@0: # We'd like to use itertools.combinations_with_replacement but it's 2.7 or michael@0: # higher. michael@0: def combinations_with_replacement(iterable, r): michael@0: # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC michael@0: pool = tuple(iterable) michael@0: n = len(pool) michael@0: if not n and r: michael@0: return michael@0: indices = [0] * r michael@0: yield tuple(pool[i] for i in indices) michael@0: while True: michael@0: for i in reversed(range(r)): michael@0: if indices[i] != n - 1: michael@0: break michael@0: else: michael@0: return michael@0: indices[i:] = [indices[i] + 1] * (r - i) michael@0: yield tuple(pool[i] for i in indices) michael@0: michael@0: def WebIDLTest(parser, harness): michael@0: types = ["float", michael@0: "double", michael@0: "short", michael@0: "unsigned short", michael@0: "long", michael@0: "unsigned long", michael@0: "long long", michael@0: "unsigned long long", michael@0: "boolean", michael@0: "byte", michael@0: "octet", michael@0: "DOMString", michael@0: "ByteString", michael@0: #"sequence", michael@0: "object", michael@0: "ArrayBuffer", michael@0: #"Date", michael@0: "TestInterface1", michael@0: "TestInterface2"] michael@0: michael@0: testPre = """ michael@0: interface TestInterface1 { michael@0: }; michael@0: interface TestInterface2 { michael@0: }; michael@0: """ michael@0: michael@0: interface = testPre + """ michael@0: interface PrepareForTest { michael@0: """ michael@0: for (i, type) in enumerate(types): michael@0: interface += string.Template(""" michael@0: readonly attribute ${type} attr${i}; michael@0: """).substitute(i=i, type=type) michael@0: interface += """ michael@0: }; michael@0: """ michael@0: michael@0: parser.parse(interface) michael@0: results = parser.finish() michael@0: michael@0: iface = results[2] michael@0: michael@0: parser = parser.reset() michael@0: michael@0: def typesAreDistinguishable(t): michael@0: return all(u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) michael@0: def typesAreNotDistinguishable(t): michael@0: return any(not u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) michael@0: def unionTypeName(t): michael@0: if len(t) > 2: michael@0: t[0:2] = [unionTypeName(t[0:2])] michael@0: return "(" + " or ".join(t) + ")" michael@0: michael@0: # typeCombinations is an iterable of tuples containing the name of the type michael@0: # as a string and the parsed IDL type. michael@0: def unionTypes(typeCombinations, predicate): michael@0: for c in typeCombinations: michael@0: if predicate(t[1] for t in c): michael@0: yield unionTypeName([t[0] for t in c]) michael@0: michael@0: # We limit invalid union types with a union member type to the subset of 3 michael@0: # types with one invalid combination. michael@0: # typeCombinations is an iterable of tuples containing the name of the type michael@0: # as a string and the parsed IDL type. michael@0: def invalidUnionWithUnion(typeCombinations): michael@0: for c in typeCombinations: michael@0: if (typesAreNotDistinguishable((c[0][1], c[1][1])) and michael@0: typesAreDistinguishable((c[1][1], c[2][1])) and michael@0: typesAreDistinguishable((c[0][1], c[2][1]))): michael@0: yield unionTypeName([t[0] for t in c]) michael@0: michael@0: # Create a list of tuples containing the name of the type as a string and michael@0: # the parsed IDL type. michael@0: types = zip(types, (a.type for a in iface.members)) michael@0: michael@0: validUnionTypes = chain(unionTypes(combinations(types, 2), typesAreDistinguishable), michael@0: unionTypes(combinations(types, 3), typesAreDistinguishable)) michael@0: invalidUnionTypes = chain(unionTypes(combinations_with_replacement(types, 2), typesAreNotDistinguishable), michael@0: invalidUnionWithUnion(combinations(types, 3))) michael@0: interface = testPre + """ michael@0: interface TestUnion { michael@0: """ michael@0: for (i, type) in enumerate(validUnionTypes): michael@0: interface += string.Template(""" michael@0: void method${i}(${type} arg); michael@0: ${type} returnMethod${i}(); michael@0: attribute ${type} attr${i}; michael@0: void arrayMethod${i}(${type}[] arg); michael@0: ${type}[] arrayReturnMethod${i}(); michael@0: attribute ${type}[] arrayAttr${i}; michael@0: void optionalMethod${i}(${type}? arg); michael@0: """).substitute(i=i, type=type) michael@0: interface += """ michael@0: }; michael@0: """ michael@0: parser.parse(interface) michael@0: results = parser.finish() michael@0: michael@0: parser = parser.reset() michael@0: michael@0: for invalid in invalidUnionTypes: michael@0: interface = testPre + string.Template(""" michael@0: interface TestUnion { michael@0: void method(${type} arg); michael@0: }; michael@0: """).substitute(type=invalid) michael@0: michael@0: threw = False michael@0: try: michael@0: parser.parse(interface) michael@0: results = parser.finish() michael@0: except: michael@0: threw = True michael@0: michael@0: harness.ok(threw, "Should have thrown.") michael@0: michael@0: parser = parser.reset()