|
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) |