1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/parser/tests/test_union.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,170 @@ 1.4 +import WebIDL 1.5 +import itertools 1.6 +import string 1.7 + 1.8 +# We'd like to use itertools.chain but it's 2.6 or higher. 1.9 +def chain(*iterables): 1.10 + # chain('ABC', 'DEF') --> A B C D E F 1.11 + for it in iterables: 1.12 + for element in it: 1.13 + yield element 1.14 + 1.15 +# We'd like to use itertools.combinations but it's 2.6 or higher. 1.16 +def combinations(iterable, r): 1.17 + # combinations('ABCD', 2) --> AB AC AD BC BD CD 1.18 + # combinations(range(4), 3) --> 012 013 023 123 1.19 + pool = tuple(iterable) 1.20 + n = len(pool) 1.21 + if r > n: 1.22 + return 1.23 + indices = range(r) 1.24 + yield tuple(pool[i] for i in indices) 1.25 + while True: 1.26 + for i in reversed(range(r)): 1.27 + if indices[i] != i + n - r: 1.28 + break 1.29 + else: 1.30 + return 1.31 + indices[i] += 1 1.32 + for j in range(i+1, r): 1.33 + indices[j] = indices[j-1] + 1 1.34 + yield tuple(pool[i] for i in indices) 1.35 + 1.36 +# We'd like to use itertools.combinations_with_replacement but it's 2.7 or 1.37 +# higher. 1.38 +def combinations_with_replacement(iterable, r): 1.39 + # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC 1.40 + pool = tuple(iterable) 1.41 + n = len(pool) 1.42 + if not n and r: 1.43 + return 1.44 + indices = [0] * r 1.45 + yield tuple(pool[i] for i in indices) 1.46 + while True: 1.47 + for i in reversed(range(r)): 1.48 + if indices[i] != n - 1: 1.49 + break 1.50 + else: 1.51 + return 1.52 + indices[i:] = [indices[i] + 1] * (r - i) 1.53 + yield tuple(pool[i] for i in indices) 1.54 + 1.55 +def WebIDLTest(parser, harness): 1.56 + types = ["float", 1.57 + "double", 1.58 + "short", 1.59 + "unsigned short", 1.60 + "long", 1.61 + "unsigned long", 1.62 + "long long", 1.63 + "unsigned long long", 1.64 + "boolean", 1.65 + "byte", 1.66 + "octet", 1.67 + "DOMString", 1.68 + "ByteString", 1.69 + #"sequence<float>", 1.70 + "object", 1.71 + "ArrayBuffer", 1.72 + #"Date", 1.73 + "TestInterface1", 1.74 + "TestInterface2"] 1.75 + 1.76 + testPre = """ 1.77 + interface TestInterface1 { 1.78 + }; 1.79 + interface TestInterface2 { 1.80 + }; 1.81 + """ 1.82 + 1.83 + interface = testPre + """ 1.84 + interface PrepareForTest { 1.85 + """ 1.86 + for (i, type) in enumerate(types): 1.87 + interface += string.Template(""" 1.88 + readonly attribute ${type} attr${i}; 1.89 + """).substitute(i=i, type=type) 1.90 + interface += """ 1.91 + }; 1.92 + """ 1.93 + 1.94 + parser.parse(interface) 1.95 + results = parser.finish() 1.96 + 1.97 + iface = results[2] 1.98 + 1.99 + parser = parser.reset() 1.100 + 1.101 + def typesAreDistinguishable(t): 1.102 + return all(u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) 1.103 + def typesAreNotDistinguishable(t): 1.104 + return any(not u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) 1.105 + def unionTypeName(t): 1.106 + if len(t) > 2: 1.107 + t[0:2] = [unionTypeName(t[0:2])] 1.108 + return "(" + " or ".join(t) + ")" 1.109 + 1.110 + # typeCombinations is an iterable of tuples containing the name of the type 1.111 + # as a string and the parsed IDL type. 1.112 + def unionTypes(typeCombinations, predicate): 1.113 + for c in typeCombinations: 1.114 + if predicate(t[1] for t in c): 1.115 + yield unionTypeName([t[0] for t in c]) 1.116 + 1.117 + # We limit invalid union types with a union member type to the subset of 3 1.118 + # types with one invalid combination. 1.119 + # typeCombinations is an iterable of tuples containing the name of the type 1.120 + # as a string and the parsed IDL type. 1.121 + def invalidUnionWithUnion(typeCombinations): 1.122 + for c in typeCombinations: 1.123 + if (typesAreNotDistinguishable((c[0][1], c[1][1])) and 1.124 + typesAreDistinguishable((c[1][1], c[2][1])) and 1.125 + typesAreDistinguishable((c[0][1], c[2][1]))): 1.126 + yield unionTypeName([t[0] for t in c]) 1.127 + 1.128 + # Create a list of tuples containing the name of the type as a string and 1.129 + # the parsed IDL type. 1.130 + types = zip(types, (a.type for a in iface.members)) 1.131 + 1.132 + validUnionTypes = chain(unionTypes(combinations(types, 2), typesAreDistinguishable), 1.133 + unionTypes(combinations(types, 3), typesAreDistinguishable)) 1.134 + invalidUnionTypes = chain(unionTypes(combinations_with_replacement(types, 2), typesAreNotDistinguishable), 1.135 + invalidUnionWithUnion(combinations(types, 3))) 1.136 + interface = testPre + """ 1.137 + interface TestUnion { 1.138 + """ 1.139 + for (i, type) in enumerate(validUnionTypes): 1.140 + interface += string.Template(""" 1.141 + void method${i}(${type} arg); 1.142 + ${type} returnMethod${i}(); 1.143 + attribute ${type} attr${i}; 1.144 + void arrayMethod${i}(${type}[] arg); 1.145 + ${type}[] arrayReturnMethod${i}(); 1.146 + attribute ${type}[] arrayAttr${i}; 1.147 + void optionalMethod${i}(${type}? arg); 1.148 + """).substitute(i=i, type=type) 1.149 + interface += """ 1.150 + }; 1.151 + """ 1.152 + parser.parse(interface) 1.153 + results = parser.finish() 1.154 + 1.155 + parser = parser.reset() 1.156 + 1.157 + for invalid in invalidUnionTypes: 1.158 + interface = testPre + string.Template(""" 1.159 + interface TestUnion { 1.160 + void method(${type} arg); 1.161 + }; 1.162 + """).substitute(type=invalid) 1.163 + 1.164 + threw = False 1.165 + try: 1.166 + parser.parse(interface) 1.167 + results = parser.finish() 1.168 + except: 1.169 + threw = True 1.170 + 1.171 + harness.ok(threw, "Should have thrown.") 1.172 + 1.173 + parser = parser.reset()