#### Other Tools

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