1import WebIDL
2
3
4def WebIDLTest(parser, harness):
5    def checkArgument(argument, QName, name, type, optional, variadic):
6        harness.ok(isinstance(argument, WebIDL.IDLArgument), "Should be an IDLArgument")
7        harness.check(
8            argument.identifier.QName(), QName, "Argument has the right QName"
9        )
10        harness.check(argument.identifier.name, name, "Argument has the right name")
11        harness.check(str(argument.type), type, "Argument has the right return type")
12        harness.check(
13            argument.optional, optional, "Argument has the right optional value"
14        )
15        harness.check(
16            argument.variadic, variadic, "Argument has the right variadic value"
17        )
18
19    def checkMethod(
20        method,
21        QName,
22        name,
23        signatures,
24        static=True,
25        getter=False,
26        setter=False,
27        deleter=False,
28        legacycaller=False,
29        stringifier=False,
30        chromeOnly=False,
31        htmlConstructor=False,
32        secureContext=False,
33        pref=None,
34        func=None,
35    ):
36        harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod")
37        harness.ok(method.isMethod(), "Method is a method")
38        harness.ok(not method.isAttr(), "Method is not an attr")
39        harness.ok(not method.isConst(), "Method is not a const")
40        harness.check(method.identifier.QName(), QName, "Method has the right QName")
41        harness.check(method.identifier.name, name, "Method has the right name")
42        harness.check(method.isStatic(), static, "Method has the correct static value")
43        harness.check(method.isGetter(), getter, "Method has the correct getter value")
44        harness.check(method.isSetter(), setter, "Method has the correct setter value")
45        harness.check(
46            method.isDeleter(), deleter, "Method has the correct deleter value"
47        )
48        harness.check(
49            method.isLegacycaller(),
50            legacycaller,
51            "Method has the correct legacycaller value",
52        )
53        harness.check(
54            method.isStringifier(),
55            stringifier,
56            "Method has the correct stringifier value",
57        )
58        harness.check(
59            method.getExtendedAttribute("ChromeOnly") is not None,
60            chromeOnly,
61            "Method has the correct value for ChromeOnly",
62        )
63        harness.check(
64            method.isHTMLConstructor(),
65            htmlConstructor,
66            "Method has the correct htmlConstructor value",
67        )
68        harness.check(
69            len(method.signatures()),
70            len(signatures),
71            "Method has the correct number of signatures",
72        )
73        harness.check(
74            method.getExtendedAttribute("Pref"),
75            pref,
76            "Method has the correct pref value",
77        )
78        harness.check(
79            method.getExtendedAttribute("Func"),
80            func,
81            "Method has the correct func value",
82        )
83        harness.check(
84            method.getExtendedAttribute("SecureContext") is not None,
85            secureContext,
86            "Method has the correct SecureContext value",
87        )
88
89        sigpairs = zip(method.signatures(), signatures)
90        for (gotSignature, expectedSignature) in sigpairs:
91            (gotRetType, gotArgs) = gotSignature
92            (expectedRetType, expectedArgs) = expectedSignature
93
94            harness.check(
95                str(gotRetType), expectedRetType, "Method has the expected return type."
96            )
97
98            for i in range(0, len(gotArgs)):
99                (QName, name, type, optional, variadic) = expectedArgs[i]
100                checkArgument(gotArgs[i], QName, name, type, optional, variadic)
101
102    def checkResults(results):
103        harness.check(len(results), 3, "Should be three productions")
104        harness.ok(
105            isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface"
106        )
107        harness.ok(
108            isinstance(results[1], WebIDL.IDLInterface), "Should be an IDLInterface"
109        )
110        harness.ok(
111            isinstance(results[2], WebIDL.IDLInterface), "Should be an IDLInterface"
112        )
113
114        checkMethod(
115            results[0].ctor(),
116            "::TestConstructorNoArgs::constructor",
117            "constructor",
118            [("TestConstructorNoArgs (Wrapper)", [])],
119        )
120        harness.check(
121            len(results[0].members), 0, "TestConstructorNoArgs should not have members"
122        )
123        checkMethod(
124            results[1].ctor(),
125            "::TestConstructorWithArgs::constructor",
126            "constructor",
127            [
128                (
129                    "TestConstructorWithArgs (Wrapper)",
130                    [
131                        (
132                            "::TestConstructorWithArgs::constructor::name",
133                            "name",
134                            "String",
135                            False,
136                            False,
137                        )
138                    ],
139                )
140            ],
141        )
142        harness.check(
143            len(results[1].members),
144            0,
145            "TestConstructorWithArgs should not have members",
146        )
147        checkMethod(
148            results[2].ctor(),
149            "::TestConstructorOverloads::constructor",
150            "constructor",
151            [
152                (
153                    "TestConstructorOverloads (Wrapper)",
154                    [
155                        (
156                            "::TestConstructorOverloads::constructor::foo",
157                            "foo",
158                            "Object",
159                            False,
160                            False,
161                        )
162                    ],
163                ),
164                (
165                    "TestConstructorOverloads (Wrapper)",
166                    [
167                        (
168                            "::TestConstructorOverloads::constructor::bar",
169                            "bar",
170                            "Boolean",
171                            False,
172                            False,
173                        )
174                    ],
175                ),
176            ],
177        )
178        harness.check(
179            len(results[2].members),
180            0,
181            "TestConstructorOverloads should not have members",
182        )
183
184    parser.parse(
185        """
186        interface TestConstructorNoArgs {
187          constructor();
188        };
189
190        interface TestConstructorWithArgs {
191          constructor(DOMString name);
192        };
193
194        interface TestConstructorOverloads {
195          constructor(object foo);
196          constructor(boolean bar);
197        };
198    """
199    )
200    results = parser.finish()
201    checkResults(results)
202
203    parser = parser.reset()
204    parser.parse(
205        """
206        interface TestPrefConstructor {
207            [Pref="dom.webidl.test1"] constructor();
208        };
209    """
210    )
211    results = parser.finish()
212    harness.check(len(results), 1, "Should be one production")
213    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
214
215    checkMethod(
216        results[0].ctor(),
217        "::TestPrefConstructor::constructor",
218        "constructor",
219        [("TestPrefConstructor (Wrapper)", [])],
220        pref=["dom.webidl.test1"],
221    )
222
223    parser = parser.reset()
224    parser.parse(
225        """
226        interface TestChromeOnlyConstructor {
227          [ChromeOnly] constructor();
228        };
229    """
230    )
231    results = parser.finish()
232    harness.check(len(results), 1, "Should be one production")
233    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
234
235    checkMethod(
236        results[0].ctor(),
237        "::TestChromeOnlyConstructor::constructor",
238        "constructor",
239        [("TestChromeOnlyConstructor (Wrapper)", [])],
240        chromeOnly=True,
241    )
242
243    parser = parser.reset()
244    parser.parse(
245        """
246        interface TestSCConstructor {
247            [SecureContext] constructor();
248        };
249    """
250    )
251    results = parser.finish()
252    harness.check(len(results), 1, "Should be one production")
253    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
254
255    checkMethod(
256        results[0].ctor(),
257        "::TestSCConstructor::constructor",
258        "constructor",
259        [("TestSCConstructor (Wrapper)", [])],
260        secureContext=True,
261    )
262
263    parser = parser.reset()
264    parser.parse(
265        """
266        interface TestFuncConstructor {
267            [Func="Document::IsWebAnimationsEnabled"] constructor();
268        };
269    """
270    )
271    results = parser.finish()
272    harness.check(len(results), 1, "Should be one production")
273    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
274
275    checkMethod(
276        results[0].ctor(),
277        "::TestFuncConstructor::constructor",
278        "constructor",
279        [("TestFuncConstructor (Wrapper)", [])],
280        func=["Document::IsWebAnimationsEnabled"],
281    )
282
283    parser = parser.reset()
284    parser.parse(
285        """
286        interface TestPrefChromeOnlySCFuncConstructor {
287            [ChromeOnly, Pref="dom.webidl.test1", SecureContext, Func="Document::IsWebAnimationsEnabled"]
288            constructor();
289        };
290    """
291    )
292    results = parser.finish()
293    harness.check(len(results), 1, "Should be one production")
294    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
295
296    checkMethod(
297        results[0].ctor(),
298        "::TestPrefChromeOnlySCFuncConstructor::constructor",
299        "constructor",
300        [("TestPrefChromeOnlySCFuncConstructor (Wrapper)", [])],
301        func=["Document::IsWebAnimationsEnabled"],
302        pref=["dom.webidl.test1"],
303        chromeOnly=True,
304        secureContext=True,
305    )
306
307    parser = parser.reset()
308    parser.parse(
309        """
310        interface TestHTMLConstructor {
311          [HTMLConstructor] constructor();
312        };
313    """
314    )
315    results = parser.finish()
316    harness.check(len(results), 1, "Should be one production")
317    harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface")
318
319    checkMethod(
320        results[0].ctor(),
321        "::TestHTMLConstructor::constructor",
322        "constructor",
323        [("TestHTMLConstructor (Wrapper)", [])],
324        htmlConstructor=True,
325    )
326
327    parser = parser.reset()
328    threw = False
329    try:
330        parser.parse(
331            """
332        interface TestChromeOnlyConstructor {
333          constructor()
334          [ChromeOnly] constructor(DOMString a);
335        };
336        """
337        )
338        results = parser.finish()
339    except:
340        threw = True
341
342    harness.ok(threw, "Can't have both a constructor and a ChromeOnly constructor")
343
344    # Test HTMLConstructor with argument
345    parser = parser.reset()
346    threw = False
347    try:
348        parser.parse(
349            """
350            interface TestHTMLConstructorWithArgs {
351              [HTMLConstructor] constructor(DOMString a);
352            };
353        """
354        )
355        results = parser.finish()
356    except:
357        threw = True
358
359    harness.ok(threw, "HTMLConstructor should take no argument")
360
361    # Test HTMLConstructor on a callback interface
362    parser = parser.reset()
363    threw = False
364    try:
365        parser.parse(
366            """
367            callback interface TestHTMLConstructorOnCallbackInterface {
368              [HTMLConstructor] constructor();
369            };
370        """
371        )
372        results = parser.finish()
373    except:
374        threw = True
375
376    harness.ok(threw, "HTMLConstructor can't be used on a callback interface")
377
378    # Test HTMLConstructor and constructor operation
379    parser = parser.reset()
380    threw = False
381    try:
382        parser.parse(
383            """
384            interface TestHTMLConstructorAndConstructor {
385              constructor();
386              [HTMLConstructor] constructor();
387            };
388        """
389        )
390        results = parser.finish()
391    except:
392        threw = True
393
394    harness.ok(threw, "Can't have both a constructor and a HTMLConstructor")
395
396    parser = parser.reset()
397    threw = False
398    try:
399        parser.parse(
400            """
401            interface TestHTMLConstructorAndConstructor {
402              [Throws]
403              constructor();
404              [HTMLConstructor] constructor();
405            };
406        """
407        )
408        results = parser.finish()
409    except:
410        threw = True
411
412    harness.ok(threw, "Can't have both a throwing constructor and a HTMLConstructor")
413
414    parser = parser.reset()
415    threw = False
416    try:
417        parser.parse(
418            """
419            interface TestHTMLConstructorAndConstructor {
420              constructor(DOMString a);
421              [HTMLConstructor] constructor();
422            };
423        """
424        )
425        results = parser.finish()
426    except:
427        threw = True
428
429    harness.ok(threw, "Can't have both a HTMLConstructor and a constructor operation")
430
431    parser = parser.reset()
432    threw = False
433    try:
434        parser.parse(
435            """
436            interface TestHTMLConstructorAndConstructor {
437              [Throws]
438              constructor(DOMString a);
439              [HTMLConstructor] constructor();
440            };
441        """
442        )
443        results = parser.finish()
444    except:
445        threw = True
446
447    harness.ok(
448        threw,
449        "Can't have both a HTMLConstructor and a throwing constructor " "operation",
450    )
451
452    # Test HTMLConstructor and [ChromeOnly] constructor operation
453    parser = parser.reset()
454    threw = False
455    try:
456        parser.parse(
457            """
458            interface TestHTMLConstructorAndConstructor {
459              [ChromeOnly]
460              constructor();
461              [HTMLConstructor] constructor();
462            };
463        """
464        )
465        results = parser.finish()
466    except:
467        threw = True
468
469    harness.ok(threw, "Can't have both a ChromeOnly constructor and a HTMLConstructor")
470
471    parser = parser.reset()
472    threw = False
473    try:
474        parser.parse(
475            """
476            interface TestHTMLConstructorAndConstructor {
477              [Throws, ChromeOnly]
478              constructor();
479              [HTMLConstructor] constructor();
480            };
481        """
482        )
483        results = parser.finish()
484    except:
485        threw = True
486
487    harness.ok(
488        threw,
489        "Can't have both a throwing chromeonly constructor and a " "HTMLConstructor",
490    )
491
492    parser = parser.reset()
493    threw = False
494    try:
495        parser.parse(
496            """
497            interface TestHTMLConstructorAndConstructor {
498              [ChromeOnly]
499              constructor(DOMString a);
500              [HTMLConstructor] constructor();
501            };
502        """
503        )
504        results = parser.finish()
505    except:
506        threw = True
507
508    harness.ok(
509        threw,
510        "Can't have both a HTMLConstructor and a chromeonly constructor " "operation",
511    )
512
513    parser = parser.reset()
514    threw = False
515    try:
516        parser.parse(
517            """
518            interface TestHTMLConstructorAndConstructor {
519              [Throws, ChromeOnly]
520              constructor(DOMString a);
521              [HTMLConstructor] constructor();
522            };
523        """
524        )
525        results = parser.finish()
526    except:
527        threw = True
528
529    harness.ok(
530        threw,
531        "Can't have both a HTMLConstructor and a throwing chromeonly "
532        "constructor operation",
533    )
534
535    parser = parser.reset()
536    threw = False
537    try:
538        parser.parse(
539            """
540            [LegacyNoInterfaceObject]
541            interface InterfaceWithoutInterfaceObject {
542              constructor();
543            };
544        """
545        )
546        results = parser.finish()
547    except:
548        threw = True
549
550    harness.ok(
551        threw,
552        "Can't have a constructor operation on a [LegacyNoInterfaceObject] "
553        "interface",
554    )
555
556    parser = parser.reset()
557    threw = False
558    try:
559        parser.parse(
560            """
561            interface InterfaceWithPartial {
562            };
563
564            partial interface InterfaceWithPartial {
565              constructor();
566            };
567        """
568        )
569        results = parser.finish()
570    except:
571        threw = True
572
573    harness.ok(threw, "Can't have a constructor operation on a partial interface")
574
575    parser = parser.reset()
576    threw = False
577    try:
578        parser.parse(
579            """
580            interface InterfaceWithMixin {
581            };
582
583            interface mixin Mixin {
584              constructor();
585            };
586
587            InterfaceWithMixin includes Mixin
588        """
589        )
590        results = parser.finish()
591    except:
592        threw = True
593
594    harness.ok(threw, "Can't have a constructor operation on a mixin")
595