test_union.py (5340B)
1 import string 2 3 import WebIDL 4 5 # We'd like to use itertools.chain but it's 2.6 or higher. 6 7 8 def chain(*iterables): 9 # chain('ABC', 'DEF') --> A B C D E F 10 for it in iterables: 11 yield from it 12 13 14 # We'd like to use itertools.combinations but it's 2.6 or higher. 15 def combinations(iterable, r): 16 # combinations('ABCD', 2) --> AB AC AD BC BD CD 17 # combinations(range(4), 3) --> 012 013 023 123 18 pool = tuple(iterable) 19 n = len(pool) 20 if r > n: 21 return 22 indices = list(range(r)) 23 yield tuple(pool[i] for i in indices) 24 while True: 25 for i in reversed(range(r)): 26 if indices[i] != i + n - r: 27 break 28 else: 29 return 30 indices[i] += 1 31 for j in range(i + 1, r): 32 indices[j] = indices[j - 1] + 1 33 yield tuple(pool[i] for i in indices) 34 35 36 # We'd like to use itertools.combinations_with_replacement but it's 2.7 or 37 # higher. 38 def combinations_with_replacement(iterable, r): 39 # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC 40 pool = tuple(iterable) 41 n = len(pool) 42 if not n and r: 43 return 44 indices = [0] * r 45 yield tuple(pool[i] for i in indices) 46 while True: 47 for i in reversed(range(r)): 48 if indices[i] != n - 1: 49 break 50 else: 51 return 52 indices[i:] = [indices[i] + 1] * (r - i) 53 yield tuple(pool[i] for i in indices) 54 55 56 def WebIDLTest(parser, harness): 57 types = [ 58 "float", 59 "double", 60 "short", 61 "unsigned short", 62 "long", 63 "unsigned long", 64 "long long", 65 "unsigned long long", 66 "boolean", 67 "byte", 68 "octet", 69 "DOMString", 70 "ByteString", 71 "USVString", 72 # "sequence<float>", 73 "object", 74 "ArrayBuffer", 75 # "Date", 76 "TestInterface1", 77 "TestInterface2", 78 ] 79 80 testPre = """ 81 interface TestInterface1 { 82 }; 83 interface TestInterface2 { 84 }; 85 """ 86 87 interface = ( 88 testPre 89 + """ 90 interface PrepareForTest { 91 """ 92 ) 93 for i, type in enumerate(types): 94 interface += string.Template( 95 """ 96 readonly attribute ${type} attr${i}; 97 """ 98 ).substitute(i=i, type=type) 99 interface += """ 100 }; 101 """ 102 103 parser.parse(interface) 104 results = parser.finish() 105 106 iface = results[2] 107 108 parser = parser.reset() 109 110 def typesAreDistinguishable(t): 111 return all(u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) 112 113 def typesAreNotDistinguishable(t): 114 return any(not u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2)) 115 116 def unionTypeName(t): 117 if len(t) > 2: 118 t[0:2] = [unionTypeName(t[0:2])] 119 return "(" + " or ".join(t) + ")" 120 121 # typeCombinations is an iterable of tuples containing the name of the type 122 # as a string and the parsed IDL type. 123 def unionTypes(typeCombinations, predicate): 124 for c in typeCombinations: 125 if predicate(t[1] for t in c): 126 yield unionTypeName([t[0] for t in c]) 127 128 # We limit invalid union types with a union member type to the subset of 3 129 # types with one invalid combination. 130 # typeCombinations is an iterable of tuples containing the name of the type 131 # as a string and the parsed IDL type. 132 def invalidUnionWithUnion(typeCombinations): 133 for c in typeCombinations: 134 if ( 135 typesAreNotDistinguishable((c[0][1], c[1][1])) 136 and typesAreDistinguishable((c[1][1], c[2][1])) 137 and typesAreDistinguishable((c[0][1], c[2][1])) 138 ): 139 yield unionTypeName([t[0] for t in c]) 140 141 # Create a list of tuples containing the name of the type as a string and 142 # the parsed IDL type. 143 types = zip(types, (a.type for a in iface.members)) 144 145 validUnionTypes = chain( 146 unionTypes(combinations(types, 2), typesAreDistinguishable), 147 unionTypes(combinations(types, 3), typesAreDistinguishable), 148 ) 149 invalidUnionTypes = chain( 150 unionTypes(combinations_with_replacement(types, 2), typesAreNotDistinguishable), 151 invalidUnionWithUnion(combinations(types, 3)), 152 ) 153 interface = ( 154 testPre 155 + """ 156 interface TestUnion { 157 """ 158 ) 159 for i, type in enumerate(validUnionTypes): 160 interface += string.Template( 161 """ 162 undefined method${i}(${type} arg); 163 ${type} returnMethod${i}(); 164 attribute ${type} attr${i}; 165 undefined optionalMethod${i}(${type}? arg); 166 """ 167 ).substitute(i=i, type=type) 168 interface += """ 169 }; 170 """ 171 parser.parse(interface) 172 results = parser.finish() 173 174 parser = parser.reset() 175 176 for invalid in invalidUnionTypes: 177 interface = testPre + string.Template( 178 """ 179 interface TestUnion { 180 undefined method(${type} arg); 181 }; 182 """ 183 ).substitute(type=invalid) 184 185 threw = False 186 try: 187 parser.parse(interface) 188 results = parser.finish() 189 except WebIDL.WebIDLError: 190 threw = True 191 192 harness.ok(threw, "Should have thrown.") 193 194 parser = parser.reset()