Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import imp
6 import os.path
7 import sys
8 import unittest
9
10 def _GetDirAbove(dirname):
11 """Returns the directory "above" this file containing |dirname| (which must
12 also be "above" this file)."""
13 path = os.path.abspath(__file__)
14 while True:
15 path, tail = os.path.split(path)
16 assert tail
17 if tail == dirname:
18 return path
19
20 try:
21 imp.find_module("mojom")
22 except ImportError:
23 sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
24 import mojom.parse.ast as ast
25 import mojom.parse.lexer as lexer
26 import mojom.parse.parser as parser
27
28
29 class ParserTest(unittest.TestCase):
30 """Tests |parser.Parse()|."""
31
32 def testTrivialValidSource(self):
33 """Tests a trivial, but valid, .mojom source."""
34
35 source = """\
36 // This is a comment.
37
38 module my_module;
39 """
40 expected = ast.Mojom(
41 ast.Module(('IDENTIFIER', 'my_module'), None),
42 ast.ImportList(),
43 [])
44 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
45
46 def testSourceWithCrLfs(self):
47 """Tests a .mojom source with CR-LFs instead of LFs."""
48
49 source = "// This is a comment.\r\n\r\nmodule my_module;\r\n"
50 expected = ast.Mojom(
51 ast.Module(('IDENTIFIER', 'my_module'), None),
52 ast.ImportList(),
53 [])
54 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
55
56 def testUnexpectedEOF(self):
57 """Tests a "truncated" .mojom source."""
58
59 source = """\
60 // This is a comment.
61
62 module my_module
63 """
64 with self.assertRaisesRegexp(
65 parser.ParseError,
66 r"^my_file\.mojom: Error: Unexpected end of file$"):
67 parser.Parse(source, "my_file.mojom")
68
69 def testCommentLineNumbers(self):
70 """Tests that line numbers are correctly tracked when comments are
71 present."""
72
73 source1 = """\
74 // Isolated C++-style comments.
75
76 // Foo.
77 asdf1
78 """
79 with self.assertRaisesRegexp(
80 parser.ParseError,
81 r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\n *asdf1$"):
82 parser.Parse(source1, "my_file.mojom")
83
84 source2 = """\
85 // Consecutive C++-style comments.
86 // Foo.
87 // Bar.
88
89 struct Yada { // Baz.
90 // Quux.
91 int32 x;
92 };
93
94 asdf2
95 """
96 with self.assertRaisesRegexp(
97 parser.ParseError,
98 r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\n *asdf2$"):
99 parser.Parse(source2, "my_file.mojom")
100
101 source3 = """\
102 /* Single-line C-style comments. */
103 /* Foobar. */
104
105 /* Baz. */
106 asdf3
107 """
108 with self.assertRaisesRegexp(
109 parser.ParseError,
110 r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\n *asdf3$"):
111 parser.Parse(source3, "my_file.mojom")
112
113 source4 = """\
114 /* Multi-line C-style comments.
115 */
116 /*
117 Foo.
118 Bar.
119 */
120
121 /* Baz
122 Quux. */
123 asdf4
124 """
125 with self.assertRaisesRegexp(
126 parser.ParseError,
127 r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\n *asdf4$"):
128 parser.Parse(source4, "my_file.mojom")
129
130
131 def testSimpleStruct(self):
132 """Tests a simple .mojom source that just defines a struct."""
133
134 source = """\
135 module my_module;
136
137 struct MyStruct {
138 int32 a;
139 double b;
140 };
141 """
142 expected = ast.Mojom(
143 ast.Module(('IDENTIFIER', 'my_module'), None),
144 ast.ImportList(),
145 [ast.Struct(
146 'MyStruct',
147 None,
148 ast.StructBody(
149 [ast.StructField('a', None, 'int32', None),
150 ast.StructField('b', None, 'double', None)]))])
151 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
152
153 def testSimpleStructWithoutModule(self):
154 """Tests a simple struct without an explict module statement."""
155
156 source = """\
157 struct MyStruct {
158 int32 a;
159 double b;
160 };
161 """
162 expected = ast.Mojom(
163 None,
164 ast.ImportList(),
165 [ast.Struct(
166 'MyStruct',
167 None,
168 ast.StructBody(
169 [ast.StructField('a', None, 'int32', None),
170 ast.StructField('b', None, 'double', None)]))])
171 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
172
173 def testValidStructDefinitions(self):
174 """Tests all types of definitions that can occur in a struct."""
175
176 source = """\
177 struct MyStruct {
178 enum MyEnum { VALUE };
179 const double kMyConst = 1.23;
180 int32 a;
181 SomeOtherStruct b; // Invalidity detected at another stage.
182 };
183 """
184 expected = ast.Mojom(
185 None,
186 ast.ImportList(),
187 [ast.Struct(
188 'MyStruct',
189 None,
190 ast.StructBody(
191 [ast.Enum('MyEnum',
192 ast.EnumValueList(ast.EnumValue('VALUE', None))),
193 ast.Const('kMyConst', 'double', '1.23'),
194 ast.StructField('a', None, 'int32', None),
195 ast.StructField('b', None, 'SomeOtherStruct', None)]))])
196 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
197
198 def testInvalidStructDefinitions(self):
199 """Tests that definitions that aren't allowed in a struct are correctly
200 detected."""
201
202 source1 = """\
203 struct MyStruct {
204 MyMethod(int32 a);
205 };
206 """
207 with self.assertRaisesRegexp(
208 parser.ParseError,
209 r"^my_file\.mojom:2: Error: Unexpected '\(':\n"
210 r" *MyMethod\(int32 a\);$"):
211 parser.Parse(source1, "my_file.mojom")
212
213 source2 = """\
214 struct MyStruct {
215 struct MyInnerStruct {
216 int32 a;
217 };
218 };
219 """
220 with self.assertRaisesRegexp(
221 parser.ParseError,
222 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
223 r" *struct MyInnerStruct {$"):
224 parser.Parse(source2, "my_file.mojom")
225
226 source3 = """\
227 struct MyStruct {
228 interface MyInterface {
229 MyMethod(int32 a);
230 };
231 };
232 """
233 with self.assertRaisesRegexp(
234 parser.ParseError,
235 r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
236 r" *interface MyInterface {$"):
237 parser.Parse(source3, "my_file.mojom")
238
239 def testMissingModuleName(self):
240 """Tests an (invalid) .mojom with a missing module name."""
241
242 source1 = """\
243 // Missing module name.
244 module ;
245 struct MyStruct {
246 int32 a;
247 };
248 """
249 with self.assertRaisesRegexp(
250 parser.ParseError,
251 r"^my_file\.mojom:2: Error: Unexpected ';':\n *module ;$"):
252 parser.Parse(source1, "my_file.mojom")
253
254 # Another similar case, but make sure that line-number tracking/reporting
255 # is correct.
256 source2 = """\
257 module
258 // This line intentionally left unblank.
259
260 struct MyStruct {
261 int32 a;
262 };
263 """
264 with self.assertRaisesRegexp(
265 parser.ParseError,
266 r"^my_file\.mojom:4: Error: Unexpected 'struct':\n"
267 r" *struct MyStruct {$"):
268 parser.Parse(source2, "my_file.mojom")
269
270 def testMultipleModuleStatements(self):
271 """Tests an (invalid) .mojom with multiple module statements."""
272
273 source = """\
274 module foo;
275 module bar;
276 """
277 with self.assertRaisesRegexp(
278 parser.ParseError,
279 r"^my_file\.mojom:2: Error: Multiple \"module\" statements not "
280 r"allowed:\n *module bar;$"):
281 parser.Parse(source, "my_file.mojom")
282
283 def testModuleStatementAfterImport(self):
284 """Tests an (invalid) .mojom with a module statement after an import."""
285
286 source = """\
287 import "foo.mojom";
288 module foo;
289 """
290 with self.assertRaisesRegexp(
291 parser.ParseError,
292 r"^my_file\.mojom:2: Error: \"module\" statements must precede imports "
293 r"and definitions:\n *module foo;$"):
294 parser.Parse(source, "my_file.mojom")
295
296 def testModuleStatementAfterDefinition(self):
297 """Tests an (invalid) .mojom with a module statement after a definition."""
298
299 source = """\
300 struct MyStruct {
301 int32 a;
302 };
303 module foo;
304 """
305 with self.assertRaisesRegexp(
306 parser.ParseError,
307 r"^my_file\.mojom:4: Error: \"module\" statements must precede imports "
308 r"and definitions:\n *module foo;$"):
309 parser.Parse(source, "my_file.mojom")
310
311 def testImportStatementAfterDefinition(self):
312 """Tests an (invalid) .mojom with an import statement after a definition."""
313
314 source = """\
315 struct MyStruct {
316 int32 a;
317 };
318 import "foo.mojom";
319 """
320 with self.assertRaisesRegexp(
321 parser.ParseError,
322 r"^my_file\.mojom:4: Error: \"import\" statements must precede "
323 r"definitions:\n *import \"foo.mojom\";$"):
324 parser.Parse(source, "my_file.mojom")
325
326 def testEnums(self):
327 """Tests that enum statements are correctly parsed."""
328
329 source = """\
330 module my_module;
331 enum MyEnum1 { VALUE1, VALUE2 }; // No trailing comma.
332 enum MyEnum2 {
333 VALUE1 = -1,
334 VALUE2 = 0,
335 VALUE3 = + 987, // Check that space is allowed.
336 VALUE4 = 0xAF12,
337 VALUE5 = -0x09bcd,
338 VALUE6 = VALUE5,
339 VALUE7, // Leave trailing comma.
340 };
341 """
342 expected = ast.Mojom(
343 ast.Module(('IDENTIFIER', 'my_module'), None),
344 ast.ImportList(),
345 [ast.Enum(
346 'MyEnum1',
347 ast.EnumValueList([ast.EnumValue('VALUE1', None),
348 ast.EnumValue('VALUE2', None)])),
349 ast.Enum(
350 'MyEnum2',
351 ast.EnumValueList([ast.EnumValue('VALUE1', '-1'),
352 ast.EnumValue('VALUE2', '0'),
353 ast.EnumValue('VALUE3', '+987'),
354 ast.EnumValue('VALUE4', '0xAF12'),
355 ast.EnumValue('VALUE5', '-0x09bcd'),
356 ast.EnumValue('VALUE6', ('IDENTIFIER',
357 'VALUE5')),
358 ast.EnumValue('VALUE7', None)]))])
359 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
360
361 def testInvalidEnumInitializers(self):
362 """Tests that invalid enum initializers are correctly detected."""
363
364 # No values.
365 source1 = """\
366 enum MyEnum {
367 };
368 """
369 with self.assertRaisesRegexp(
370 parser.ParseError,
371 r"^my_file\.mojom:2: Error: Unexpected '}':\n"
372 r" *};$"):
373 parser.Parse(source1, "my_file.mojom")
374
375 # Floating point value.
376 source2 = "enum MyEnum { VALUE = 0.123 };"
377 with self.assertRaisesRegexp(
378 parser.ParseError,
379 r"^my_file\.mojom:1: Error: Unexpected '0\.123':\n"
380 r"enum MyEnum { VALUE = 0\.123 };$"):
381 parser.Parse(source2, "my_file.mojom")
382
383 # Boolean value.
384 source2 = "enum MyEnum { VALUE = true };"
385 with self.assertRaisesRegexp(
386 parser.ParseError,
387 r"^my_file\.mojom:1: Error: Unexpected 'true':\n"
388 r"enum MyEnum { VALUE = true };$"):
389 parser.Parse(source2, "my_file.mojom")
390
391 def testConsts(self):
392 """Tests some constants and struct members initialized with them."""
393
394 source = """\
395 module my_module;
396
397 struct MyStruct {
398 const int8 kNumber = -1;
399 int8 number@0 = kNumber;
400 };
401 """
402 expected = ast.Mojom(
403 ast.Module(('IDENTIFIER', 'my_module'), None),
404 ast.ImportList(),
405 [ast.Struct(
406 'MyStruct', None,
407 ast.StructBody(
408 [ast.Const('kNumber', 'int8', '-1'),
409 ast.StructField('number', ast.Ordinal(0), 'int8',
410 ('IDENTIFIER', 'kNumber'))]))])
411 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
412
413 def testNoConditionals(self):
414 """Tests that ?: is not allowed."""
415
416 source = """\
417 module my_module;
418
419 enum MyEnum {
420 MY_ENUM_1 = 1 ? 2 : 3
421 };
422 """
423 with self.assertRaisesRegexp(
424 parser.ParseError,
425 r"^my_file\.mojom:4: Error: Unexpected '\?':\n"
426 r" *MY_ENUM_1 = 1 \? 2 : 3$"):
427 parser.Parse(source, "my_file.mojom")
428
429 def testSimpleOrdinals(self):
430 """Tests that (valid) ordinal values are scanned correctly."""
431
432 source = """\
433 module my_module;
434
435 // This isn't actually valid .mojom, but the problem (missing ordinals)
436 // should be handled at a different level.
437 struct MyStruct {
438 int32 a0@0;
439 int32 a1@1;
440 int32 a2@2;
441 int32 a9@9;
442 int32 a10 @10;
443 int32 a11 @11;
444 int32 a29 @29;
445 int32 a1234567890 @1234567890;
446 };
447 """
448 expected = ast.Mojom(
449 ast.Module(('IDENTIFIER', 'my_module'), None),
450 ast.ImportList(),
451 [ast.Struct(
452 'MyStruct',
453 None,
454 ast.StructBody(
455 [ast.StructField('a0', ast.Ordinal(0), 'int32', None),
456 ast.StructField('a1', ast.Ordinal(1), 'int32', None),
457 ast.StructField('a2', ast.Ordinal(2), 'int32', None),
458 ast.StructField('a9', ast.Ordinal(9), 'int32', None),
459 ast.StructField('a10', ast.Ordinal(10), 'int32', None),
460 ast.StructField('a11', ast.Ordinal(11), 'int32', None),
461 ast.StructField('a29', ast.Ordinal(29), 'int32', None),
462 ast.StructField('a1234567890', ast.Ordinal(1234567890),
463 'int32', None)]))])
464 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
465
466 def testInvalidOrdinals(self):
467 """Tests that (lexically) invalid ordinals are correctly detected."""
468
469 source1 = """\
470 module my_module;
471
472 struct MyStruct {
473 int32 a_missing@;
474 };
475 """
476 with self.assertRaisesRegexp(
477 lexer.LexError,
478 r"^my_file\.mojom:4: Error: Missing ordinal value$"):
479 parser.Parse(source1, "my_file.mojom")
480
481 source2 = """\
482 module my_module;
483
484 struct MyStruct {
485 int32 a_octal@01;
486 };
487 """
488 with self.assertRaisesRegexp(
489 lexer.LexError,
490 r"^my_file\.mojom:4: Error: "
491 r"Octal and hexadecimal ordinal values not allowed$"):
492 parser.Parse(source2, "my_file.mojom")
493
494 source3 = """\
495 module my_module; struct MyStruct { int32 a_invalid_octal@08; };
496 """
497 with self.assertRaisesRegexp(
498 lexer.LexError,
499 r"^my_file\.mojom:1: Error: "
500 r"Octal and hexadecimal ordinal values not allowed$"):
501 parser.Parse(source3, "my_file.mojom")
502
503 source4 = "module my_module; struct MyStruct { int32 a_hex@0x1aB9; };"
504 with self.assertRaisesRegexp(
505 lexer.LexError,
506 r"^my_file\.mojom:1: Error: "
507 r"Octal and hexadecimal ordinal values not allowed$"):
508 parser.Parse(source4, "my_file.mojom")
509
510 source5 = "module my_module; struct MyStruct { int32 a_hex@0X0; };"
511 with self.assertRaisesRegexp(
512 lexer.LexError,
513 r"^my_file\.mojom:1: Error: "
514 r"Octal and hexadecimal ordinal values not allowed$"):
515 parser.Parse(source5, "my_file.mojom")
516
517 source6 = """\
518 struct MyStruct {
519 int32 a_too_big@999999999999;
520 };
521 """
522 with self.assertRaisesRegexp(
523 parser.ParseError,
524 r"^my_file\.mojom:2: Error: "
525 r"Ordinal value 999999999999 too large:\n"
526 r" *int32 a_too_big@999999999999;$"):
527 parser.Parse(source6, "my_file.mojom")
528
529 def testNestedNamespace(self):
530 """Tests that "nested" namespaces work."""
531
532 source = """\
533 module my.mod;
534
535 struct MyStruct {
536 int32 a;
537 };
538 """
539 expected = ast.Mojom(
540 ast.Module(('IDENTIFIER', 'my.mod'), None),
541 ast.ImportList(),
542 [ast.Struct(
543 'MyStruct',
544 None,
545 ast.StructBody(ast.StructField('a', None, 'int32', None)))])
546 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
547
548 def testValidHandleTypes(self):
549 """Tests (valid) handle types."""
550
551 source = """\
552 struct MyStruct {
553 handle a;
554 handle<data_pipe_consumer> b;
555 handle <data_pipe_producer> c;
556 handle < message_pipe > d;
557 handle
558 < shared_buffer
559 > e;
560 };
561 """
562 expected = ast.Mojom(
563 None,
564 ast.ImportList(),
565 [ast.Struct(
566 'MyStruct',
567 None,
568 ast.StructBody(
569 [ast.StructField('a', None, 'handle', None),
570 ast.StructField('b', None, 'handle<data_pipe_consumer>', None),
571 ast.StructField('c', None, 'handle<data_pipe_producer>', None),
572 ast.StructField('d', None, 'handle<message_pipe>', None),
573 ast.StructField('e', None, 'handle<shared_buffer>', None)]))])
574 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
575
576 def testInvalidHandleType(self):
577 """Tests an invalid (unknown) handle type."""
578
579 source = """\
580 struct MyStruct {
581 handle<wtf_is_this> foo;
582 };
583 """
584 with self.assertRaisesRegexp(
585 parser.ParseError,
586 r"^my_file\.mojom:2: Error: "
587 r"Invalid handle type 'wtf_is_this':\n"
588 r" *handle<wtf_is_this> foo;$"):
589 parser.Parse(source, "my_file.mojom")
590
591 def testValidDefaultValues(self):
592 """Tests default values that are valid (to the parser)."""
593
594 source = """\
595 struct MyStruct {
596 int16 a0 = 0;
597 uint16 a1 = 0x0;
598 uint16 a2 = 0x00;
599 uint16 a3 = 0x01;
600 uint16 a4 = 0xcd;
601 int32 a5 = 12345;
602 int64 a6 = -12345;
603 int64 a7 = +12345;
604 uint32 a8 = 0x12cd3;
605 uint32 a9 = -0x12cD3;
606 uint32 a10 = +0x12CD3;
607 bool a11 = true;
608 bool a12 = false;
609 float a13 = 1.2345;
610 float a14 = -1.2345;
611 float a15 = +1.2345;
612 float a16 = 123.;
613 float a17 = .123;
614 double a18 = 1.23E10;
615 double a19 = 1.E-10;
616 double a20 = .5E+10;
617 double a21 = -1.23E10;
618 double a22 = +.123E10;
619 };
620 """
621 expected = ast.Mojom(
622 None,
623 ast.ImportList(),
624 [ast.Struct(
625 'MyStruct',
626 None,
627 ast.StructBody(
628 [ast.StructField('a0', None, 'int16', '0'),
629 ast.StructField('a1', None, 'uint16', '0x0'),
630 ast.StructField('a2', None, 'uint16', '0x00'),
631 ast.StructField('a3', None, 'uint16', '0x01'),
632 ast.StructField('a4', None, 'uint16', '0xcd'),
633 ast.StructField('a5' , None, 'int32', '12345'),
634 ast.StructField('a6', None, 'int64', '-12345'),
635 ast.StructField('a7', None, 'int64', '+12345'),
636 ast.StructField('a8', None, 'uint32', '0x12cd3'),
637 ast.StructField('a9', None, 'uint32', '-0x12cD3'),
638 ast.StructField('a10', None, 'uint32', '+0x12CD3'),
639 ast.StructField('a11', None, 'bool', 'true'),
640 ast.StructField('a12', None, 'bool', 'false'),
641 ast.StructField('a13', None, 'float', '1.2345'),
642 ast.StructField('a14', None, 'float', '-1.2345'),
643 ast.StructField('a15', None, 'float', '+1.2345'),
644 ast.StructField('a16', None, 'float', '123.'),
645 ast.StructField('a17', None, 'float', '.123'),
646 ast.StructField('a18', None, 'double', '1.23E10'),
647 ast.StructField('a19', None, 'double', '1.E-10'),
648 ast.StructField('a20', None, 'double', '.5E+10'),
649 ast.StructField('a21', None, 'double', '-1.23E10'),
650 ast.StructField('a22', None, 'double', '+.123E10')]))])
651 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
652
653 def testValidFixedSizeArray(self):
654 """Tests parsing a fixed size array."""
655
656 source = """\
657 struct MyStruct {
658 array<int32> normal_array;
659 array<int32, 1> fixed_size_array_one_entry;
660 array<int32, 10> fixed_size_array_ten_entries;
661 array<array<array<int32, 1>>, 2> nested_arrays;
662 };
663 """
664 expected = ast.Mojom(
665 None,
666 ast.ImportList(),
667 [ast.Struct(
668 'MyStruct',
669 None,
670 ast.StructBody(
671 [ast.StructField('normal_array', None, 'int32[]', None),
672 ast.StructField('fixed_size_array_one_entry', None, 'int32[1]',
673 None),
674 ast.StructField('fixed_size_array_ten_entries', None,
675 'int32[10]', None),
676 ast.StructField('nested_arrays', None,
677 'int32[1][][2]', None)]))])
678 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
679
680 def testValidNestedArray(self):
681 """Tests parsing a nested array."""
682
683 source = "struct MyStruct { array<array<int32>> nested_array; };"
684 expected = ast.Mojom(
685 None,
686 ast.ImportList(),
687 [ast.Struct(
688 'MyStruct',
689 None,
690 ast.StructBody(
691 ast.StructField('nested_array', None, 'int32[][]', None)))])
692 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
693
694 def testInvalidFixedArraySize(self):
695 """Tests that invalid fixed array bounds are correctly detected."""
696
697 source1 = """\
698 struct MyStruct {
699 array<int32, 0> zero_size_array;
700 };
701 """
702 with self.assertRaisesRegexp(
703 parser.ParseError,
704 r"^my_file\.mojom:2: Error: Fixed array size 0 invalid:\n"
705 r" *array<int32, 0> zero_size_array;$"):
706 parser.Parse(source1, "my_file.mojom")
707
708 source2 = """\
709 struct MyStruct {
710 array<int32, 999999999999> too_big_array;
711 };
712 """
713 with self.assertRaisesRegexp(
714 parser.ParseError,
715 r"^my_file\.mojom:2: Error: Fixed array size 999999999999 invalid:\n"
716 r" *array<int32, 999999999999> too_big_array;$"):
717 parser.Parse(source2, "my_file.mojom")
718
719 source3 = """\
720 struct MyStruct {
721 array<int32, abcdefg> not_a_number;
722 };
723 """
724 with self.assertRaisesRegexp(
725 parser.ParseError,
726 r"^my_file\.mojom:2: Error: Unexpected 'abcdefg':\n"
727 r" *array<int32, abcdefg> not_a_number;"):
728 parser.Parse(source3, "my_file.mojom")
729
730 def testValidAssociativeArrays(self):
731 """Tests that we can parse valid associative array structures."""
732
733 source1 = "struct MyStruct { map<string, uint8> data; };"
734 expected1 = ast.Mojom(
735 None,
736 ast.ImportList(),
737 [ast.Struct(
738 'MyStruct',
739 None,
740 ast.StructBody(
741 [ast.StructField('data', None, 'uint8{string}', None)]))])
742 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
743
744 source2 = "interface MyInterface { MyMethod(map<string, uint8> a); };"
745 expected2 = ast.Mojom(
746 None,
747 ast.ImportList(),
748 [ast.Interface(
749 'MyInterface',
750 None,
751 ast.InterfaceBody(
752 ast.Method(
753 'MyMethod',
754 None,
755 ast.ParameterList(
756 ast.Parameter('a', None, 'uint8{string}')),
757 None)))])
758 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
759
760 source3 = "struct MyStruct { map<string, array<uint8>> data; };"
761 expected3 = ast.Mojom(
762 None,
763 ast.ImportList(),
764 [ast.Struct(
765 'MyStruct',
766 None,
767 ast.StructBody(
768 [ast.StructField('data', None, 'uint8[]{string}', None)]))])
769 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
770
771 def testValidMethod(self):
772 """Tests parsing method declarations."""
773
774 source1 = "interface MyInterface { MyMethod(int32 a); };"
775 expected1 = ast.Mojom(
776 None,
777 ast.ImportList(),
778 [ast.Interface(
779 'MyInterface',
780 None,
781 ast.InterfaceBody(
782 ast.Method(
783 'MyMethod',
784 None,
785 ast.ParameterList(ast.Parameter('a', None, 'int32')),
786 None)))])
787 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
788
789 source2 = """\
790 interface MyInterface {
791 MyMethod1@0(int32 a@0, int64 b@1);
792 MyMethod2@1() => ();
793 };
794 """
795 expected2 = ast.Mojom(
796 None,
797 ast.ImportList(),
798 [ast.Interface(
799 'MyInterface',
800 None,
801 ast.InterfaceBody(
802 [ast.Method(
803 'MyMethod1',
804 ast.Ordinal(0),
805 ast.ParameterList([ast.Parameter('a', ast.Ordinal(0),
806 'int32'),
807 ast.Parameter('b', ast.Ordinal(1),
808 'int64')]),
809 None),
810 ast.Method(
811 'MyMethod2',
812 ast.Ordinal(1),
813 ast.ParameterList(),
814 ast.ParameterList())]))])
815 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
816
817 source3 = """\
818 interface MyInterface {
819 MyMethod(string a) => (int32 a, bool b);
820 };
821 """
822 expected3 = ast.Mojom(
823 None,
824 ast.ImportList(),
825 [ast.Interface(
826 'MyInterface',
827 None,
828 ast.InterfaceBody(
829 ast.Method(
830 'MyMethod',
831 None,
832 ast.ParameterList(ast.Parameter('a', None, 'string')),
833 ast.ParameterList([ast.Parameter('a', None, 'int32'),
834 ast.Parameter('b', None, 'bool')]))))])
835 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
836
837 def testInvalidMethods(self):
838 """Tests that invalid method declarations are correctly detected."""
839
840 # No trailing commas.
841 source1 = """\
842 interface MyInterface {
843 MyMethod(string a,);
844 };
845 """
846 with self.assertRaisesRegexp(
847 parser.ParseError,
848 r"^my_file\.mojom:2: Error: Unexpected '\)':\n"
849 r" *MyMethod\(string a,\);$"):
850 parser.Parse(source1, "my_file.mojom")
851
852 # No leading commas.
853 source2 = """\
854 interface MyInterface {
855 MyMethod(, string a);
856 };
857 """
858 with self.assertRaisesRegexp(
859 parser.ParseError,
860 r"^my_file\.mojom:2: Error: Unexpected ',':\n"
861 r" *MyMethod\(, string a\);$"):
862 parser.Parse(source2, "my_file.mojom")
863
864 def testValidInterfaceDefinitions(self):
865 """Tests all types of definitions that can occur in an interface."""
866
867 source = """\
868 interface MyInterface {
869 enum MyEnum { VALUE };
870 const int32 kMyConst = 123;
871 MyMethod(int32 x) => (MyEnum y);
872 };
873 """
874 expected = ast.Mojom(
875 None,
876 ast.ImportList(),
877 [ast.Interface(
878 'MyInterface',
879 None,
880 ast.InterfaceBody(
881 [ast.Enum('MyEnum',
882 ast.EnumValueList(ast.EnumValue('VALUE', None))),
883 ast.Const('kMyConst', 'int32', '123'),
884 ast.Method(
885 'MyMethod',
886 None,
887 ast.ParameterList(ast.Parameter('x', None, 'int32')),
888 ast.ParameterList(ast.Parameter('y', None, 'MyEnum')))]))])
889 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
890
891 def testInvalidInterfaceDefinitions(self):
892 """Tests that definitions that aren't allowed in an interface are correctly
893 detected."""
894
895 source1 = """\
896 interface MyInterface {
897 struct MyStruct {
898 int32 a;
899 };
900 };
901 """
902 with self.assertRaisesRegexp(
903 parser.ParseError,
904 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
905 r" *struct MyStruct {$"):
906 parser.Parse(source1, "my_file.mojom")
907
908 source2 = """\
909 interface MyInterface {
910 interface MyInnerInterface {
911 MyMethod(int32 x);
912 };
913 };
914 """
915 with self.assertRaisesRegexp(
916 parser.ParseError,
917 r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
918 r" *interface MyInnerInterface {$"):
919 parser.Parse(source2, "my_file.mojom")
920
921 source3 = """\
922 interface MyInterface {
923 int32 my_field;
924 };
925 """
926 # The parser thinks that "int32" is a plausible name for a method, so it's
927 # "my_field" that gives it away.
928 with self.assertRaisesRegexp(
929 parser.ParseError,
930 r"^my_file\.mojom:2: Error: Unexpected 'my_field':\n"
931 r" *int32 my_field;$"):
932 parser.Parse(source3, "my_file.mojom")
933
934 def testValidAttributes(self):
935 """Tests parsing attributes (and attribute lists)."""
936
937 # Note: We use structs because they have (optional) attribute lists.
938
939 # Empty attribute list.
940 source1 = "[] struct MyStruct {};"
941 expected1 = ast.Mojom(
942 None,
943 ast.ImportList(),
944 [ast.Struct('MyStruct', ast.AttributeList(), ast.StructBody())])
945 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
946
947 # One-element attribute list, with name value.
948 source2 = "[MyAttribute=MyName] struct MyStruct {};"
949 expected2 = ast.Mojom(
950 None,
951 ast.ImportList(),
952 [ast.Struct(
953 'MyStruct',
954 ast.AttributeList(ast.Attribute("MyAttribute", "MyName")),
955 ast.StructBody())])
956 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
957
958 # Two-element attribute list, with one string value and one integer value.
959 source3 = "[MyAttribute1 = \"hello\", MyAttribute2 = 5] struct MyStruct {};"
960 expected3 = ast.Mojom(
961 None,
962 ast.ImportList(),
963 [ast.Struct(
964 'MyStruct',
965 ast.AttributeList([ast.Attribute("MyAttribute1", "hello"),
966 ast.Attribute("MyAttribute2", 5)]),
967 ast.StructBody())])
968 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
969
970 # TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()|
971 # literal (non-name) values, which is extremely dubious.)
972
973 def testInvalidAttributes(self):
974 """Tests that invalid attributes and attribute lists are correctly
975 detected."""
976
977 # Trailing commas not allowed.
978 source1 = "[MyAttribute=MyName,] struct MyStruct {};"
979 with self.assertRaisesRegexp(
980 parser.ParseError,
981 r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
982 r"\[MyAttribute=MyName,\] struct MyStruct {};$"):
983 parser.Parse(source1, "my_file.mojom")
984
985 # Missing value.
986 source2 = "[MyAttribute=] struct MyStruct {};"
987 with self.assertRaisesRegexp(
988 parser.ParseError,
989 r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
990 r"\[MyAttribute=\] struct MyStruct {};$"):
991 parser.Parse(source2, "my_file.mojom")
992
993 # Missing key.
994 source3 = "[=MyName] struct MyStruct {};"
995 with self.assertRaisesRegexp(
996 parser.ParseError,
997 r"^my_file\.mojom:1: Error: Unexpected '=':\n"
998 r"\[=MyName\] struct MyStruct {};$"):
999 parser.Parse(source3, "my_file.mojom")
1000
1001 def testValidImports(self):
1002 """Tests parsing import statements."""
1003
1004 # One import (no module statement).
1005 source1 = "import \"somedir/my.mojom\";"
1006 expected1 = ast.Mojom(
1007 None,
1008 ast.ImportList(ast.Import("somedir/my.mojom")),
1009 [])
1010 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
1011
1012 # Two imports (no module statement).
1013 source2 = """\
1014 import "somedir/my1.mojom";
1015 import "somedir/my2.mojom";
1016 """
1017 expected2 = ast.Mojom(
1018 None,
1019 ast.ImportList([ast.Import("somedir/my1.mojom"),
1020 ast.Import("somedir/my2.mojom")]),
1021 [])
1022 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
1023
1024 # Imports with module statement.
1025 source3 = """\
1026 module my_module;
1027 import "somedir/my1.mojom";
1028 import "somedir/my2.mojom";
1029 """
1030 expected3 = ast.Mojom(
1031 ast.Module(('IDENTIFIER', 'my_module'), None),
1032 ast.ImportList([ast.Import("somedir/my1.mojom"),
1033 ast.Import("somedir/my2.mojom")]),
1034 [])
1035 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
1036
1037 def testInvalidImports(self):
1038 """Tests that invalid import statements are correctly detected."""
1039
1040 source1 = """\
1041 // Make the error occur on line 2.
1042 import invalid
1043 """
1044 with self.assertRaisesRegexp(
1045 parser.ParseError,
1046 r"^my_file\.mojom:2: Error: Unexpected 'invalid':\n"
1047 r" *import invalid$"):
1048 parser.Parse(source1, "my_file.mojom")
1049
1050 source2 = """\
1051 import // Missing string.
1052 struct MyStruct {
1053 int32 a;
1054 };
1055 """
1056 with self.assertRaisesRegexp(
1057 parser.ParseError,
1058 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
1059 r" *struct MyStruct {$"):
1060 parser.Parse(source2, "my_file.mojom")
1061
1062 source3 = """\
1063 import "foo.mojom" // Missing semicolon.
1064 struct MyStruct {
1065 int32 a;
1066 };
1067 """
1068 with self.assertRaisesRegexp(
1069 parser.ParseError,
1070 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
1071 r" *struct MyStruct {$"):
1072 parser.Parse(source3, "my_file.mojom")
1073
1074 def testValidNullableTypes(self):
1075 """Tests parsing nullable types."""
1076
1077 source = """\
1078 struct MyStruct {
1079 int32? a; // This is actually invalid, but handled at a different
1080 // level.
1081 string? b;
1082 array<int32> ? c;
1083 array<string ? > ? d;
1084 array<array<int32>?>? e;
1085 array<int32, 1>? f;
1086 array<string?, 1>? g;
1087 some_struct? h;
1088 handle? i;
1089 handle<data_pipe_consumer>? j;
1090 handle<data_pipe_producer>? k;
1091 handle<message_pipe>? l;
1092 handle<shared_buffer>? m;
1093 some_interface&? n;
1094 };
1095 """
1096 expected = ast.Mojom(
1097 None,
1098 ast.ImportList(),
1099 [ast.Struct(
1100 'MyStruct',
1101 None,
1102 ast.StructBody(
1103 [ast.StructField('a', None, 'int32?', None),
1104 ast.StructField('b', None, 'string?', None),
1105 ast.StructField('c', None, 'int32[]?', None),
1106 ast.StructField('d', None, 'string?[]?', None),
1107 ast.StructField('e', None, 'int32[]?[]?', None),
1108 ast.StructField('f', None, 'int32[1]?', None),
1109 ast.StructField('g', None, 'string?[1]?', None),
1110 ast.StructField('h', None, 'some_struct?', None),
1111 ast.StructField('i', None, 'handle?', None),
1112 ast.StructField('j', None, 'handle<data_pipe_consumer>?',
1113 None),
1114 ast.StructField('k', None, 'handle<data_pipe_producer>?',
1115 None),
1116 ast.StructField('l', None, 'handle<message_pipe>?', None),
1117 ast.StructField('m', None, 'handle<shared_buffer>?', None),
1118 ast.StructField('n', None, 'some_interface&?', None)]))])
1119 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
1120
1121 def testInvalidNullableTypes(self):
1122 """Tests that invalid nullable types are correctly detected."""
1123 source1 = """\
1124 struct MyStruct {
1125 string?? a;
1126 };
1127 """
1128 with self.assertRaisesRegexp(
1129 parser.ParseError,
1130 r"^my_file\.mojom:2: Error: Unexpected '\?':\n"
1131 r" *string\?\? a;$"):
1132 parser.Parse(source1, "my_file.mojom")
1133
1134 source2 = """\
1135 struct MyStruct {
1136 handle?<data_pipe_consumer> a;
1137 };
1138 """
1139 with self.assertRaisesRegexp(
1140 parser.ParseError,
1141 r"^my_file\.mojom:2: Error: Unexpected '<':\n"
1142 r" *handle\?<data_pipe_consumer> a;$"):
1143 parser.Parse(source2, "my_file.mojom")
1144
1145 source3 = """\
1146 struct MyStruct {
1147 some_interface?& a;
1148 };
1149 """
1150 with self.assertRaisesRegexp(
1151 parser.ParseError,
1152 r"^my_file\.mojom:2: Error: Unexpected '&':\n"
1153 r" *some_interface\?& a;$"):
1154 parser.Parse(source3, "my_file.mojom")
1155
1156 def testSimpleUnion(self):
1157 """Tests a simple .mojom source that just defines a union."""
1158 source = """\
1159 module my_module;
1160
1161 union MyUnion {
1162 int32 a;
1163 double b;
1164 };
1165 """
1166 expected = ast.Mojom(
1167 ast.Module(('IDENTIFIER', 'my_module'), None),
1168 ast.ImportList(),
1169 [ast.Union(
1170 'MyUnion',
1171 ast.UnionBody([
1172 ast.UnionField('a', None, 'int32'),
1173 ast.UnionField('b', None, 'double')
1174 ]))])
1175 actual = parser.Parse(source, "my_file.mojom")
1176 self.assertEquals(actual, expected)
1177
1178 def testUnionWithOrdinals(self):
1179 """Test that ordinals are assigned to fields."""
1180 source = """\
1181 module my_module;
1182
1183 union MyUnion {
1184 int32 a @10;
1185 double b @30;
1186 };
1187 """
1188 expected = ast.Mojom(
1189 ast.Module(('IDENTIFIER', 'my_module'), None),
1190 ast.ImportList(),
1191 [ast.Union(
1192 'MyUnion',
1193 ast.UnionBody([
1194 ast.UnionField('a', ast.Ordinal(10), 'int32'),
1195 ast.UnionField('b', ast.Ordinal(30), 'double')
1196 ]))])
1197 actual = parser.Parse(source, "my_file.mojom")
1198 self.assertEquals(actual, expected)
1199
1200 def testUnionWithStructMembers(self):
1201 """Test that struct members are accepted."""
1202 source = """\
1203 module my_module;
1204
1205 union MyUnion {
1206 SomeStruct s;
1207 };
1208 """
1209 expected = ast.Mojom(
1210 ast.Module(('IDENTIFIER', 'my_module'), None),
1211 ast.ImportList(),
1212 [ast.Union(
1213 'MyUnion',
1214 ast.UnionBody([
1215 ast.UnionField('s', None, 'SomeStruct')
1216 ]))])
1217 actual = parser.Parse(source, "my_file.mojom")
1218 self.assertEquals(actual, expected)
1219
1220 def testUnionWithArrayMember(self):
1221 """Test that array members are accepted."""
1222 source = """\
1223 module my_module;
1224
1225 union MyUnion {
1226 array<int32> a;
1227 };
1228 """
1229 expected = ast.Mojom(
1230 ast.Module(('IDENTIFIER', 'my_module'), None),
1231 ast.ImportList(),
1232 [ast.Union(
1233 'MyUnion',
1234 ast.UnionBody([
1235 ast.UnionField('a', None, 'int32[]')
1236 ]))])
1237 actual = parser.Parse(source, "my_file.mojom")
1238 self.assertEquals(actual, expected)
1239
1240 def testUnionWithMapMember(self):
1241 """Test that map members are accepted."""
1242 source = """\
1243 module my_module;
1244
1245 union MyUnion {
1246 map<int32, string> m;
1247 };
1248 """
1249 expected = ast.Mojom(
1250 ast.Module(('IDENTIFIER', 'my_module'), None),
1251 ast.ImportList(),
1252 [ast.Union(
1253 'MyUnion',
1254 ast.UnionBody([
1255 ast.UnionField('m', None, 'string{int32}')
1256 ]))])
1257 actual = parser.Parse(source, "my_file.mojom")
1258 self.assertEquals(actual, expected)
1259
1260 def testUnionDisallowNestedStruct(self):
1261 """Tests that structs cannot be nested in unions."""
1262 source = """\
1263 module my_module;
1264
1265 union MyUnion {
1266 struct MyStruct {
1267 int32 a;
1268 };
1269 };
1270 """
1271 with self.assertRaisesRegexp(
1272 parser.ParseError,
1273 r"^my_file\.mojom:4: Error: Unexpected 'struct':\n"
1274 r" *struct MyStruct {$"):
1275 parser.Parse(source, "my_file.mojom")
1276
1277 def testUnionDisallowNestedInterfaces(self):
1278 """Tests that interfaces cannot be nested in unions."""
1279 source = """\
1280 module my_module;
1281
1282 union MyUnion {
1283 interface MyInterface {
1284 MyMethod(int32 a);
1285 };
1286 };
1287 """
1288 with self.assertRaisesRegexp(
1289 parser.ParseError,
1290 r"^my_file\.mojom:4: Error: Unexpected 'interface':\n"
1291 r" *interface MyInterface {$"):
1292 parser.Parse(source, "my_file.mojom")
1293
1294 def testUnionDisallowNestedUnion(self):
1295 """Tests that unions cannot be nested in unions."""
1296 source = """\
1297 module my_module;
1298
1299 union MyUnion {
1300 union MyOtherUnion {
1301 int32 a;
1302 };
1303 };
1304 """
1305 with self.assertRaisesRegexp(
1306 parser.ParseError,
1307 r"^my_file\.mojom:4: Error: Unexpected 'union':\n"
1308 r" *union MyOtherUnion {$"):
1309 parser.Parse(source, "my_file.mojom")
1310
1311 def testUnionDisallowNestedEnum(self):
1312 """Tests that enums cannot be nested in unions."""
1313 source = """\
1314 module my_module;
1315
1316 union MyUnion {
1317 enum MyEnum {
1318 A,
1319 };
1320 };
1321 """
1322 with self.assertRaisesRegexp(
1323 parser.ParseError,
1324 r"^my_file\.mojom:4: Error: Unexpected 'enum':\n"
1325 r" *enum MyEnum {$"):
1326 parser.Parse(source, "my_file.mojom")
1327
1328
1329 if __name__ == "__main__":
1330 unittest.main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698