|
1 import WebIDL |
|
2 |
|
3 def WebIDLTest(parser, harness): |
|
4 parser.parse("interface Foo { };") |
|
5 results = parser.finish() |
|
6 harness.ok(True, "Empty interface parsed without error.") |
|
7 harness.check(len(results), 1, "Should be one production") |
|
8 harness.ok(isinstance(results[0], WebIDL.IDLInterface), |
|
9 "Should be an IDLInterface") |
|
10 iface = results[0] |
|
11 harness.check(iface.identifier.QName(), "::Foo", "Interface has the right QName") |
|
12 harness.check(iface.identifier.name, "Foo", "Interface has the right name") |
|
13 harness.check(iface.parent, None, "Interface has no parent") |
|
14 |
|
15 parser.parse("interface Bar : Foo { };") |
|
16 results = parser.finish() |
|
17 harness.ok(True, "Empty interface parsed without error.") |
|
18 harness.check(len(results), 2, "Should be two productions") |
|
19 harness.ok(isinstance(results[1], WebIDL.IDLInterface), |
|
20 "Should be an IDLInterface") |
|
21 iface = results[1] |
|
22 harness.check(iface.identifier.QName(), "::Bar", "Interface has the right QName") |
|
23 harness.check(iface.identifier.name, "Bar", "Interface has the right name") |
|
24 harness.ok(isinstance(iface.parent, WebIDL.IDLInterface), |
|
25 "Interface has a parent") |
|
26 |
|
27 parser = parser.reset() |
|
28 parser.parse(""" |
|
29 interface QNameBase { |
|
30 attribute long foo; |
|
31 }; |
|
32 |
|
33 interface QNameDerived : QNameBase { |
|
34 attribute long long foo; |
|
35 attribute byte bar; |
|
36 }; |
|
37 """) |
|
38 results = parser.finish() |
|
39 harness.check(len(results), 2, "Should be two productions") |
|
40 harness.ok(isinstance(results[0], WebIDL.IDLInterface), |
|
41 "Should be an IDLInterface") |
|
42 harness.ok(isinstance(results[1], WebIDL.IDLInterface), |
|
43 "Should be an IDLInterface") |
|
44 harness.check(results[1].parent, results[0], "Inheritance chain is right") |
|
45 harness.check(len(results[0].members), 1, "Expect 1 productions") |
|
46 harness.check(len(results[1].members), 2, "Expect 2 productions") |
|
47 base = results[0] |
|
48 derived = results[1] |
|
49 harness.check(base.members[0].identifier.QName(), "::QNameBase::foo", |
|
50 "Member has the right QName") |
|
51 harness.check(derived.members[0].identifier.QName(), "::QNameDerived::foo", |
|
52 "Member has the right QName") |
|
53 harness.check(derived.members[1].identifier.QName(), "::QNameDerived::bar", |
|
54 "Member has the right QName") |
|
55 |
|
56 parser = parser.reset() |
|
57 threw = False |
|
58 try: |
|
59 parser.parse(""" |
|
60 interface A : B {}; |
|
61 interface B : A {}; |
|
62 """) |
|
63 results = parser.finish() |
|
64 except: |
|
65 threw = True |
|
66 |
|
67 harness.ok(threw, "Should not allow cycles in interface inheritance chains") |
|
68 |
|
69 parser = parser.reset() |
|
70 threw = False |
|
71 try: |
|
72 parser.parse(""" |
|
73 interface A : C {}; |
|
74 interface C : B {}; |
|
75 interface B : A {}; |
|
76 """) |
|
77 results = parser.finish() |
|
78 except: |
|
79 threw = True |
|
80 |
|
81 harness.ok(threw, "Should not allow indirect cycles in interface inheritance chains") |
|
82 |
|
83 parser = parser.reset() |
|
84 threw = False |
|
85 try: |
|
86 parser.parse(""" |
|
87 interface A {}; |
|
88 interface B {}; |
|
89 A implements B; |
|
90 B implements A; |
|
91 """) |
|
92 results = parser.finish() |
|
93 except: |
|
94 threw = True |
|
95 |
|
96 harness.ok(threw, "Should not allow cycles via implements") |
|
97 |
|
98 parser = parser.reset() |
|
99 threw = False |
|
100 try: |
|
101 parser.parse(""" |
|
102 interface A {}; |
|
103 interface C {}; |
|
104 interface B {}; |
|
105 A implements C; |
|
106 C implements B; |
|
107 B implements A; |
|
108 """) |
|
109 results = parser.finish() |
|
110 except: |
|
111 threw = True |
|
112 |
|
113 harness.ok(threw, "Should not allow indirect cycles via implements") |
|
114 |
|
115 parser = parser.reset() |
|
116 threw = False |
|
117 try: |
|
118 parser.parse(""" |
|
119 interface A : B {}; |
|
120 interface B {}; |
|
121 B implements A; |
|
122 """) |
|
123 results = parser.finish() |
|
124 except: |
|
125 threw = True |
|
126 |
|
127 harness.ok(threw, "Should not allow inheriting from an interface that implements us") |
|
128 |
|
129 parser = parser.reset() |
|
130 threw = False |
|
131 try: |
|
132 parser.parse(""" |
|
133 interface A : B {}; |
|
134 interface B {}; |
|
135 interface C {}; |
|
136 B implements C; |
|
137 C implements A; |
|
138 """) |
|
139 results = parser.finish() |
|
140 except: |
|
141 threw = True |
|
142 |
|
143 harness.ok(threw, "Should not allow inheriting from an interface that indirectly implements us") |
|
144 |
|
145 parser = parser.reset() |
|
146 threw = False |
|
147 try: |
|
148 parser.parse(""" |
|
149 interface A : B {}; |
|
150 interface B : C {}; |
|
151 interface C {}; |
|
152 C implements A; |
|
153 """) |
|
154 results = parser.finish() |
|
155 except: |
|
156 threw = True |
|
157 |
|
158 harness.ok(threw, "Should not allow indirectly inheriting from an interface that implements us") |
|
159 |
|
160 parser = parser.reset() |
|
161 threw = False |
|
162 try: |
|
163 parser.parse(""" |
|
164 interface A : B {}; |
|
165 interface B : C {}; |
|
166 interface C {}; |
|
167 interface D {}; |
|
168 C implements D; |
|
169 D implements A; |
|
170 """) |
|
171 results = parser.finish() |
|
172 except: |
|
173 threw = True |
|
174 |
|
175 harness.ok(threw, "Should not allow indirectly inheriting from an interface that indirectly implements us") |
|
176 |
|
177 parser = parser.reset() |
|
178 threw = False |
|
179 try: |
|
180 parser.parse(""" |
|
181 interface A; |
|
182 interface B : A {}; |
|
183 """) |
|
184 results = parser.finish() |
|
185 except: |
|
186 threw = True |
|
187 |
|
188 harness.ok(threw, "Should not allow inheriting from an interface that is only forward declared") |
|
189 |
|
190 parser = parser.reset() |
|
191 parser.parse(""" |
|
192 [Constructor(long arg)] |
|
193 interface A { |
|
194 readonly attribute boolean x; |
|
195 void foo(); |
|
196 }; |
|
197 [Constructor] |
|
198 partial interface A { |
|
199 readonly attribute boolean y; |
|
200 void foo(long arg); |
|
201 }; |
|
202 """); |
|
203 results = parser.finish(); |
|
204 harness.check(len(results), 1, |
|
205 "Should have one result with partial interface") |
|
206 iface = results[0] |
|
207 harness.check(len(iface.members), 3, |
|
208 "Should have three members with partial interface") |
|
209 harness.check(iface.members[0].identifier.name, "x", |
|
210 "First member should be x with partial interface") |
|
211 harness.check(iface.members[1].identifier.name, "foo", |
|
212 "Second member should be foo with partial interface") |
|
213 harness.check(len(iface.members[1].signatures()), 2, |
|
214 "Should have two foo signatures with partial interface") |
|
215 harness.check(iface.members[2].identifier.name, "y", |
|
216 "Third member should be y with partial interface") |
|
217 harness.check(len(iface.ctor().signatures()), 2, |
|
218 "Should have two constructors with partial interface") |
|
219 |
|
220 parser = parser.reset() |
|
221 parser.parse(""" |
|
222 [Constructor] |
|
223 partial interface A { |
|
224 readonly attribute boolean y; |
|
225 void foo(long arg); |
|
226 }; |
|
227 [Constructor(long arg)] |
|
228 interface A { |
|
229 readonly attribute boolean x; |
|
230 void foo(); |
|
231 }; |
|
232 """); |
|
233 results = parser.finish(); |
|
234 harness.check(len(results), 1, |
|
235 "Should have one result with reversed partial interface") |
|
236 iface = results[0] |
|
237 harness.check(len(iface.members), 3, |
|
238 "Should have three members with reversed partial interface") |
|
239 harness.check(iface.members[0].identifier.name, "x", |
|
240 "First member should be x with reversed partial interface") |
|
241 harness.check(iface.members[1].identifier.name, "foo", |
|
242 "Second member should be foo with reversed partial interface") |
|
243 harness.check(len(iface.members[1].signatures()), 2, |
|
244 "Should have two foo signatures with reversed partial interface") |
|
245 harness.check(iface.members[2].identifier.name, "y", |
|
246 "Third member should be y with reversed partial interface") |
|
247 harness.check(len(iface.ctor().signatures()), 2, |
|
248 "Should have two constructors with reversed partial interface") |
|
249 |
|
250 parser = parser.reset() |
|
251 threw = False |
|
252 try: |
|
253 parser.parse(""" |
|
254 interface A { |
|
255 readonly attribute boolean x; |
|
256 }; |
|
257 interface A { |
|
258 readonly attribute boolean y; |
|
259 }; |
|
260 """) |
|
261 results = parser.finish() |
|
262 except: |
|
263 threw = True |
|
264 harness.ok(threw, |
|
265 "Should not allow two non-partial interfaces with the same name") |
|
266 |
|
267 parser = parser.reset() |
|
268 threw = False |
|
269 try: |
|
270 parser.parse(""" |
|
271 partial interface A { |
|
272 readonly attribute boolean x; |
|
273 }; |
|
274 partial interface A { |
|
275 readonly attribute boolean y; |
|
276 }; |
|
277 """) |
|
278 results = parser.finish() |
|
279 except: |
|
280 threw = True |
|
281 harness.ok(threw, |
|
282 "Must have a non-partial interface for a given name") |
|
283 |
|
284 parser = parser.reset() |
|
285 threw = False |
|
286 try: |
|
287 parser.parse(""" |
|
288 dictionary A { |
|
289 boolean x; |
|
290 }; |
|
291 partial interface A { |
|
292 readonly attribute boolean y; |
|
293 }; |
|
294 """) |
|
295 results = parser.finish() |
|
296 except: |
|
297 threw = True |
|
298 harness.ok(threw, |
|
299 "Should not allow a name collision between partial interface " |
|
300 "and other object") |
|
301 |
|
302 parser = parser.reset() |
|
303 threw = False |
|
304 try: |
|
305 parser.parse(""" |
|
306 dictionary A { |
|
307 boolean x; |
|
308 }; |
|
309 interface A { |
|
310 readonly attribute boolean y; |
|
311 }; |
|
312 """) |
|
313 results = parser.finish() |
|
314 except: |
|
315 threw = True |
|
316 harness.ok(threw, |
|
317 "Should not allow a name collision between interface " |
|
318 "and other object") |
|
319 |
|
320 parser = parser.reset() |
|
321 threw = False |
|
322 try: |
|
323 parser.parse(""" |
|
324 dictionary A { |
|
325 boolean x; |
|
326 }; |
|
327 interface A; |
|
328 """) |
|
329 results = parser.finish() |
|
330 except: |
|
331 threw = True |
|
332 harness.ok(threw, |
|
333 "Should not allow a name collision between external interface " |
|
334 "and other object") |
|
335 |
|
336 parser = parser.reset() |
|
337 threw = False |
|
338 try: |
|
339 parser.parse(""" |
|
340 interface A { |
|
341 readonly attribute boolean x; |
|
342 }; |
|
343 interface A; |
|
344 """) |
|
345 results = parser.finish() |
|
346 except: |
|
347 threw = True |
|
348 harness.ok(threw, |
|
349 "Should not allow a name collision between external interface " |
|
350 "and interface") |
|
351 |
|
352 parser = parser.reset() |
|
353 parser.parse(""" |
|
354 interface A; |
|
355 interface A; |
|
356 """) |
|
357 results = parser.finish() |
|
358 harness.ok(len(results) == 1 and |
|
359 isinstance(results[0], WebIDL.IDLExternalInterface), |
|
360 "Should allow name collisions between external interface " |
|
361 "declarations") |
|
362 |
|
363 parser = parser.reset() |
|
364 threw = False |
|
365 try: |
|
366 parser.parse(""" |
|
367 [SomeRandomAnnotation] |
|
368 interface A { |
|
369 readonly attribute boolean y; |
|
370 }; |
|
371 """) |
|
372 results = parser.finish() |
|
373 except: |
|
374 threw = True |
|
375 harness.ok(threw, |
|
376 "Should not allow unknown extended attributes on interfaces") |
|
377 |
|
378 parser = parser.reset() |
|
379 threw = False |
|
380 try: |
|
381 parser.parse(""" |
|
382 interface B {}; |
|
383 [ArrayClass] |
|
384 interface A : B { |
|
385 }; |
|
386 """) |
|
387 results = parser.finish() |
|
388 except: |
|
389 threw = True |
|
390 harness.ok(threw, |
|
391 "Should not allow [ArrayClass] on interfaces with parents") |
|
392 |
|
393 parser = parser.reset() |
|
394 threw = False |
|
395 try: |
|
396 parser.parse(""" |
|
397 [ArrayClass] |
|
398 interface A { |
|
399 }; |
|
400 """) |
|
401 results = parser.finish() |
|
402 except: |
|
403 threw = True |
|
404 harness.ok(not threw, |
|
405 "Should allow [ArrayClass] on interfaces without parents") |