| |
1 def firstArgType(method): |
| |
2 return method.signatures()[0][1][0].type |
| |
3 |
| |
4 def WebIDLTest(parser, harness): |
| |
5 parser.parse(""" |
| |
6 dictionary Dict { |
| |
7 }; |
| |
8 callback interface Foo { |
| |
9 }; |
| |
10 interface Bar { |
| |
11 // Bit of a pain to get things that have dictionary types |
| |
12 void passDict(optional Dict arg); |
| |
13 void passFoo(Foo arg); |
| |
14 void passNullableUnion((object? or DOMString) arg); |
| |
15 void passNullable(Foo? arg); |
| |
16 }; |
| |
17 """) |
| |
18 results = parser.finish() |
| |
19 |
| |
20 iface = results[2] |
| |
21 harness.ok(iface.isInterface(), "Should have interface") |
| |
22 dictMethod = iface.members[0] |
| |
23 ifaceMethod = iface.members[1] |
| |
24 nullableUnionMethod = iface.members[2] |
| |
25 nullableIfaceMethod = iface.members[3] |
| |
26 |
| |
27 dictType = firstArgType(dictMethod) |
| |
28 ifaceType = firstArgType(ifaceMethod) |
| |
29 |
| |
30 harness.ok(dictType.isDictionary(), "Should have dictionary type"); |
| |
31 harness.ok(ifaceType.isInterface(), "Should have interface type"); |
| |
32 harness.ok(ifaceType.isCallbackInterface(), "Should have callback interface type"); |
| |
33 |
| |
34 harness.ok(not dictType.isDistinguishableFrom(ifaceType), |
| |
35 "Dictionary not distinguishable from callback interface") |
| |
36 harness.ok(not ifaceType.isDistinguishableFrom(dictType), |
| |
37 "Callback interface not distinguishable from dictionary") |
| |
38 |
| |
39 nullableUnionType = firstArgType(nullableUnionMethod) |
| |
40 nullableIfaceType = firstArgType(nullableIfaceMethod) |
| |
41 |
| |
42 harness.ok(nullableUnionType.isUnion(), "Should have union type"); |
| |
43 harness.ok(nullableIfaceType.isInterface(), "Should have interface type"); |
| |
44 harness.ok(nullableIfaceType.nullable(), "Should have nullable type"); |
| |
45 |
| |
46 harness.ok(not nullableUnionType.isDistinguishableFrom(nullableIfaceType), |
| |
47 "Nullable type not distinguishable from union with nullable " |
| |
48 "member type") |
| |
49 harness.ok(not nullableIfaceType.isDistinguishableFrom(nullableUnionType), |
| |
50 "Union with nullable member type not distinguishable from " |
| |
51 "nullable type") |
| |
52 |
| |
53 parser = parser.reset() |
| |
54 parser.parse(""" |
| |
55 interface TestIface { |
| |
56 void passKid(Kid arg); |
| |
57 void passParent(Parent arg); |
| |
58 void passGrandparent(Grandparent arg); |
| |
59 void passImplemented(Implemented arg); |
| |
60 void passImplementedParent(ImplementedParent arg); |
| |
61 void passUnrelated1(Unrelated1 arg); |
| |
62 void passUnrelated2(Unrelated2 arg); |
| |
63 void passArrayBuffer(ArrayBuffer arg); |
| |
64 void passArrayBuffer(ArrayBufferView arg); |
| |
65 }; |
| |
66 |
| |
67 interface Kid : Parent {}; |
| |
68 interface Parent : Grandparent {}; |
| |
69 interface Grandparent {}; |
| |
70 interface Implemented : ImplementedParent {}; |
| |
71 Parent implements Implemented; |
| |
72 interface ImplementedParent {}; |
| |
73 interface Unrelated1 {}; |
| |
74 interface Unrelated2 {}; |
| |
75 """) |
| |
76 results = parser.finish() |
| |
77 |
| |
78 iface = results[0] |
| |
79 harness.ok(iface.isInterface(), "Should have interface") |
| |
80 argTypes = [firstArgType(method) for method in iface.members] |
| |
81 unrelatedTypes = [firstArgType(method) for method in iface.members[-3:]] |
| |
82 |
| |
83 for type1 in argTypes: |
| |
84 for type2 in argTypes: |
| |
85 distinguishable = (type1 is not type2 and |
| |
86 (type1 in unrelatedTypes or |
| |
87 type2 in unrelatedTypes)) |
| |
88 |
| |
89 harness.check(type1.isDistinguishableFrom(type2), |
| |
90 distinguishable, |
| |
91 "Type %s should %sbe distinguishable from type %s" % |
| |
92 (type1, "" if distinguishable else "not ", type2)) |
| |
93 harness.check(type2.isDistinguishableFrom(type1), |
| |
94 distinguishable, |
| |
95 "Type %s should %sbe distinguishable from type %s" % |
| |
96 (type2, "" if distinguishable else "not ", type1)) |
| |
97 |
| |
98 parser = parser.reset() |
| |
99 parser.parse(""" |
| |
100 interface Dummy {}; |
| |
101 interface TestIface { |
| |
102 void method(long arg1, TestIface arg2); |
| |
103 void method(long arg1, long arg2); |
| |
104 void method(long arg1, Dummy arg2); |
| |
105 void method(DOMString arg1, DOMString arg2, DOMString arg3); |
| |
106 }; |
| |
107 """) |
| |
108 results = parser.finish() |
| |
109 harness.check(len(results[1].members), 1, |
| |
110 "Should look like we have one method") |
| |
111 harness.check(len(results[1].members[0].signatures()), 4, |
| |
112 "Should have four signatures") |
| |
113 |
| |
114 parser = parser.reset() |
| |
115 threw = False |
| |
116 try: |
| |
117 parser.parse(""" |
| |
118 interface Dummy {}; |
| |
119 interface TestIface { |
| |
120 void method(long arg1, TestIface arg2); |
| |
121 void method(long arg1, long arg2); |
| |
122 void method(any arg1, Dummy arg2); |
| |
123 void method(DOMString arg1, DOMString arg2, DOMString arg3); |
| |
124 }; |
| |
125 """) |
| |
126 results = parser.finish() |
| |
127 except: |
| |
128 threw = True |
| |
129 |
| |
130 harness.ok(threw, |
| |
131 "Should throw when args before the distinguishing arg are not " |
| |
132 "all the same type") |
| |
133 |
| |
134 parser = parser.reset() |
| |
135 threw = False |
| |
136 try: |
| |
137 parser.parse(""" |
| |
138 interface Dummy {}; |
| |
139 interface TestIface { |
| |
140 void method(long arg1, TestIface arg2); |
| |
141 void method(long arg1, long arg2); |
| |
142 void method(any arg1, DOMString arg2); |
| |
143 void method(DOMString arg1, DOMString arg2, DOMString arg3); |
| |
144 }; |
| |
145 """) |
| |
146 results = parser.finish() |
| |
147 except: |
| |
148 threw = True |
| |
149 |
| |
150 harness.ok(threw, "Should throw when there is no distinguishing index") |
| |
151 |
| |
152 # Now let's test our whole distinguishability table |
| |
153 argTypes = [ "long", "short", "long?", "short?", "boolean", |
| |
154 "boolean?", "DOMString", "ByteString", "Enum", "Enum2", |
| |
155 "Interface", "Interface?", |
| |
156 "AncestorInterface", "UnrelatedInterface", |
| |
157 "ImplementedInterface", "CallbackInterface", |
| |
158 "CallbackInterface?", "CallbackInterface2", |
| |
159 "object", "Callback", "Callback2", "optional Dict", |
| |
160 "optional Dict2", "sequence<long>", "sequence<short>", |
| |
161 "MozMap<object>", "MozMap<Dict>", "MozMap<long>", |
| |
162 "long[]", "short[]", "Date", "Date?", "any" ] |
| |
163 # When we can parse Date and RegExp, we need to add them here. |
| |
164 |
| |
165 # Try to categorize things a bit to keep list lengths down |
| |
166 def allBut(list1, list2): |
| |
167 return [a for a in list1 if a not in list2 and a != "any"] |
| |
168 numerics = [ "long", "short", "long?", "short?" ] |
| |
169 booleans = [ "boolean", "boolean?" ] |
| |
170 primitives = numerics + booleans |
| |
171 nonNumerics = allBut(argTypes, numerics) |
| |
172 nonBooleans = allBut(argTypes, booleans) |
| |
173 strings = [ "DOMString", "ByteString", "Enum", "Enum2" ] |
| |
174 nonStrings = allBut(argTypes, strings) |
| |
175 nonObjects = primitives + strings |
| |
176 objects = allBut(argTypes, nonObjects ) |
| |
177 interfaces = [ "Interface", "Interface?", "AncestorInterface", |
| |
178 "UnrelatedInterface", "ImplementedInterface" ] |
| |
179 nullables = ["long?", "short?", "boolean?", "Interface?", |
| |
180 "CallbackInterface?", "optional Dict", "optional Dict2", |
| |
181 "Date?", "any"] |
| |
182 dates = [ "Date", "Date?" ] |
| |
183 nonUserObjects = nonObjects + interfaces + dates |
| |
184 otherObjects = allBut(argTypes, nonUserObjects + ["object"]) |
| |
185 notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + |
| |
186 otherObjects + dates) |
| |
187 |
| |
188 # Build a representation of the distinguishability table as a dict |
| |
189 # of dicts, holding True values where needed, holes elsewhere. |
| |
190 data = dict(); |
| |
191 for type in argTypes: |
| |
192 data[type] = dict() |
| |
193 def setDistinguishable(type, types): |
| |
194 for other in types: |
| |
195 data[type][other] = True |
| |
196 |
| |
197 setDistinguishable("long", nonNumerics) |
| |
198 setDistinguishable("short", nonNumerics) |
| |
199 setDistinguishable("long?", allBut(nonNumerics, nullables)) |
| |
200 setDistinguishable("short?", allBut(nonNumerics, nullables)) |
| |
201 setDistinguishable("boolean", nonBooleans) |
| |
202 setDistinguishable("boolean?", allBut(nonBooleans, nullables)) |
| |
203 setDistinguishable("DOMString", nonStrings) |
| |
204 setDistinguishable("ByteString", nonStrings) |
| |
205 setDistinguishable("Enum", nonStrings) |
| |
206 setDistinguishable("Enum2", nonStrings) |
| |
207 setDistinguishable("Interface", notRelatedInterfaces) |
| |
208 setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables)) |
| |
209 setDistinguishable("AncestorInterface", notRelatedInterfaces) |
| |
210 setDistinguishable("UnrelatedInterface", |
| |
211 allBut(argTypes, ["object", "UnrelatedInterface"])) |
| |
212 setDistinguishable("ImplementedInterface", notRelatedInterfaces) |
| |
213 setDistinguishable("CallbackInterface", nonUserObjects) |
| |
214 setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables)) |
| |
215 setDistinguishable("CallbackInterface2", nonUserObjects) |
| |
216 setDistinguishable("object", nonObjects) |
| |
217 setDistinguishable("Callback", nonUserObjects) |
| |
218 setDistinguishable("Callback2", nonUserObjects) |
| |
219 setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) |
| |
220 setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) |
| |
221 setDistinguishable("sequence<long>", nonUserObjects) |
| |
222 setDistinguishable("sequence<short>", nonUserObjects) |
| |
223 setDistinguishable("MozMap<object>", nonUserObjects) |
| |
224 setDistinguishable("MozMap<Dict>", nonUserObjects) |
| |
225 setDistinguishable("MozMap<long>", nonUserObjects) |
| |
226 setDistinguishable("long[]", nonUserObjects) |
| |
227 setDistinguishable("short[]", nonUserObjects) |
| |
228 setDistinguishable("Date", allBut(argTypes, dates + ["object"])) |
| |
229 setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) |
| |
230 setDistinguishable("any", []) |
| |
231 |
| |
232 def areDistinguishable(type1, type2): |
| |
233 return data[type1].get(type2, False) |
| |
234 |
| |
235 def checkDistinguishability(parser, type1, type2): |
| |
236 idlTemplate = """ |
| |
237 enum Enum { "a", "b" }; |
| |
238 enum Enum2 { "c", "d" }; |
| |
239 interface Interface : AncestorInterface {}; |
| |
240 interface AncestorInterface {}; |
| |
241 interface UnrelatedInterface {}; |
| |
242 interface ImplementedInterface {}; |
| |
243 Interface implements ImplementedInterface; |
| |
244 callback interface CallbackInterface {}; |
| |
245 callback interface CallbackInterface2 {}; |
| |
246 callback Callback = any(); |
| |
247 callback Callback2 = long(short arg); |
| |
248 dictionary Dict {}; |
| |
249 dictionary Dict2 {}; |
| |
250 interface TestInterface {%s |
| |
251 }; |
| |
252 """ |
| |
253 methodTemplate = """ |
| |
254 void myMethod(%s arg);""" |
| |
255 methods = (methodTemplate % type1) + (methodTemplate % type2) |
| |
256 idl = idlTemplate % methods |
| |
257 parser = parser.reset() |
| |
258 threw = False |
| |
259 try: |
| |
260 parser.parse(idl) |
| |
261 results = parser.finish() |
| |
262 except: |
| |
263 threw = True |
| |
264 |
| |
265 if areDistinguishable(type1, type2): |
| |
266 harness.ok(not threw, |
| |
267 "Should not throw for '%s' and '%s' because they are distinguishable" % (type1, type2)) |
| |
268 else: |
| |
269 harness.ok(threw, |
| |
270 "Should throw for '%s' and '%s' because they are not distinguishable" % (type1, type2)) |
| |
271 |
| |
272 # Enumerate over everything in both orders, since order matters in |
| |
273 # terms of our implementation of distinguishability checks |
| |
274 for type1 in argTypes: |
| |
275 for type2 in argTypes: |
| |
276 checkDistinguishability(parser, type1, type2) |