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.
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__)
15 path, tail = os.path.split(path)
21 imp.find_module("mojom")
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
29 class ParserTest(unittest.TestCase):
30 """Tests |parser.Parse()|."""
32 def testTrivialValidSource(self):
33 """Tests a trivial, but valid, .mojom source."""
41 ast.Module(('IDENTIFIER', 'my_module'), None),
44 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
46 def testSourceWithCrLfs(self):
47 """Tests a .mojom source with CR-LFs instead of LFs."""
49 source = "// This is a comment.\r\n\r\nmodule my_module;\r\n"
51 ast.Module(('IDENTIFIER', 'my_module'), None),
54 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
56 def testUnexpectedEOF(self):
57 """Tests a "truncated" .mojom source."""
64 with self.assertRaisesRegexp(
66 r"^my_file\.mojom: Error: Unexpected end of file$"):
67 parser.Parse(source, "my_file.mojom")
69 def testCommentLineNumbers(self):
70 """Tests that line numbers are correctly tracked when comments are
74 // Isolated C++-style comments.
79 with self.assertRaisesRegexp(
81 r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\n *asdf1$"):
82 parser.Parse(source1, "my_file.mojom")
85 // Consecutive C++-style comments.
96 with self.assertRaisesRegexp(
98 r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\n *asdf2$"):
99 parser.Parse(source2, "my_file.mojom")
102 /* Single-line C-style comments. */
108 with self.assertRaisesRegexp(
110 r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\n *asdf3$"):
111 parser.Parse(source3, "my_file.mojom")
114 /* Multi-line C-style comments.
125 with self.assertRaisesRegexp(
127 r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\n *asdf4$"):
128 parser.Parse(source4, "my_file.mojom")
131 def testSimpleStruct(self):
132 """Tests a simple .mojom source that just defines a struct."""
142 expected = ast.Mojom(
143 ast.Module(('IDENTIFIER', 'my_module'), None),
149 [ast.StructField('a', None, 'int32', None),
150 ast.StructField('b', None, 'double', None)]))])
151 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
153 def testSimpleStructWithoutModule(self):
154 """Tests a simple struct without an explict module statement."""
162 expected = ast.Mojom(
169 [ast.StructField('a', None, 'int32', None),
170 ast.StructField('b', None, 'double', None)]))])
171 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
173 def testValidStructDefinitions(self):
174 """Tests all types of definitions that can occur in a struct."""
178 enum MyEnum { VALUE };
179 const double kMyConst = 1.23;
181 SomeOtherStruct b; // Invalidity detected at another stage.
184 expected = ast.Mojom(
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)
198 def testInvalidStructDefinitions(self):
199 """Tests that definitions that aren't allowed in a struct are correctly
207 with self.assertRaisesRegexp(
209 r"^my_file\.mojom:2: Error: Unexpected '\(':\n"
210 r" *MyMethod\(int32 a\);$"):
211 parser.Parse(source1, "my_file.mojom")
215 struct MyInnerStruct {
220 with self.assertRaisesRegexp(
222 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
223 r" *struct MyInnerStruct {$"):
224 parser.Parse(source2, "my_file.mojom")
228 interface MyInterface {
233 with self.assertRaisesRegexp(
235 r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
236 r" *interface MyInterface {$"):
237 parser.Parse(source3, "my_file.mojom")
239 def testMissingModuleName(self):
240 """Tests an (invalid) .mojom with a missing module name."""
243 // Missing module name.
249 with self.assertRaisesRegexp(
251 r"^my_file\.mojom:2: Error: Unexpected ';':\n *module ;$"):
252 parser.Parse(source1, "my_file.mojom")
254 # Another similar case, but make sure that line-number tracking/reporting
258 // This line intentionally left unblank.
264 with self.assertRaisesRegexp(
266 r"^my_file\.mojom:4: Error: Unexpected 'struct':\n"
267 r" *struct MyStruct {$"):
268 parser.Parse(source2, "my_file.mojom")
270 def testMultipleModuleStatements(self):
271 """Tests an (invalid) .mojom with multiple module statements."""
277 with self.assertRaisesRegexp(
279 r"^my_file\.mojom:2: Error: Multiple \"module\" statements not "
280 r"allowed:\n *module bar;$"):
281 parser.Parse(source, "my_file.mojom")
283 def testModuleStatementAfterImport(self):
284 """Tests an (invalid) .mojom with a module statement after an import."""
290 with self.assertRaisesRegexp(
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")
296 def testModuleStatementAfterDefinition(self):
297 """Tests an (invalid) .mojom with a module statement after a definition."""
305 with self.assertRaisesRegexp(
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")
311 def testImportStatementAfterDefinition(self):
312 """Tests an (invalid) .mojom with an import statement after a definition."""
320 with self.assertRaisesRegexp(
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")
327 """Tests that enum statements are correctly parsed."""
331 enum MyEnum1 { VALUE1, VALUE2 }; // No trailing comma.
335 VALUE3 = + 987, // Check that space is allowed.
339 VALUE7, // Leave trailing comma.
342 expected = ast.Mojom(
343 ast.Module(('IDENTIFIER', 'my_module'), None),
347 ast.EnumValueList([ast.EnumValue('VALUE1', None),
348 ast.EnumValue('VALUE2', None)])),
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',
358 ast.EnumValue('VALUE7', None)]))])
359 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
361 def testInvalidEnumInitializers(self):
362 """Tests that invalid enum initializers are correctly detected."""
369 with self.assertRaisesRegexp(
371 r"^my_file\.mojom:2: Error: Unexpected '}':\n"
373 parser.Parse(source1, "my_file.mojom")
375 # Floating point value.
376 source2 = "enum MyEnum { VALUE = 0.123 };"
377 with self.assertRaisesRegexp(
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")
384 source2 = "enum MyEnum { VALUE = true };"
385 with self.assertRaisesRegexp(
387 r"^my_file\.mojom:1: Error: Unexpected 'true':\n"
388 r"enum MyEnum { VALUE = true };$"):
389 parser.Parse(source2, "my_file.mojom")
391 def testConsts(self):
392 """Tests some constants and struct members initialized with them."""
398 const int8 kNumber = -1;
399 int8 number@0 = kNumber;
402 expected = ast.Mojom(
403 ast.Module(('IDENTIFIER', 'my_module'), None),
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)
413 def testNoConditionals(self):
414 """Tests that ?: is not allowed."""
420 MY_ENUM_1 = 1 ? 2 : 3
423 with self.assertRaisesRegexp(
425 r"^my_file\.mojom:4: Error: Unexpected '\?':\n"
426 r" *MY_ENUM_1 = 1 \? 2 : 3$"):
427 parser.Parse(source, "my_file.mojom")
429 def testSimpleOrdinals(self):
430 """Tests that (valid) ordinal values are scanned correctly."""
435 // This isn't actually valid .mojom, but the problem (missing ordinals)
436 // should be handled at a different level.
445 int32 a1234567890 @1234567890;
448 expected = ast.Mojom(
449 ast.Module(('IDENTIFIER', 'my_module'), None),
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),
464 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
466 def testInvalidOrdinals(self):
467 """Tests that (lexically) invalid ordinals are correctly detected."""
476 with self.assertRaisesRegexp(
478 r"^my_file\.mojom:4: Error: Missing ordinal value$"):
479 parser.Parse(source1, "my_file.mojom")
488 with self.assertRaisesRegexp(
490 r"^my_file\.mojom:4: Error: "
491 r"Octal and hexadecimal ordinal values not allowed$"):
492 parser.Parse(source2, "my_file.mojom")
495 module my_module; struct MyStruct { int32 a_invalid_octal@08; };
497 with self.assertRaisesRegexp(
499 r"^my_file\.mojom:1: Error: "
500 r"Octal and hexadecimal ordinal values not allowed$"):
501 parser.Parse(source3, "my_file.mojom")
503 source4 = "module my_module; struct MyStruct { int32 a_hex@0x1aB9; };"
504 with self.assertRaisesRegexp(
506 r"^my_file\.mojom:1: Error: "
507 r"Octal and hexadecimal ordinal values not allowed$"):
508 parser.Parse(source4, "my_file.mojom")
510 source5 = "module my_module; struct MyStruct { int32 a_hex@0X0; };"
511 with self.assertRaisesRegexp(
513 r"^my_file\.mojom:1: Error: "
514 r"Octal and hexadecimal ordinal values not allowed$"):
515 parser.Parse(source5, "my_file.mojom")
519 int32 a_too_big@999999999999;
522 with self.assertRaisesRegexp(
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")
529 def testNestedNamespace(self):
530 """Tests that "nested" namespaces work."""
539 expected = ast.Mojom(
540 ast.Module(('IDENTIFIER', 'my.mod'), None),
545 ast.StructBody(ast.StructField('a', None, 'int32', None)))])
546 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
548 def testValidHandleTypes(self):
549 """Tests (valid) handle types."""
554 handle<data_pipe_consumer> b;
555 handle <data_pipe_producer> c;
556 handle < message_pipe > d;
562 expected = ast.Mojom(
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)
576 def testInvalidHandleType(self):
577 """Tests an invalid (unknown) handle type."""
581 handle<wtf_is_this> foo;
584 with self.assertRaisesRegexp(
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")
591 def testValidDefaultValues(self):
592 """Tests default values that are valid (to the parser)."""
605 uint32 a9 = -0x12cD3;
606 uint32 a10 = +0x12CD3;
614 double a18 = 1.23E10;
617 double a21 = -1.23E10;
618 double a22 = +.123E10;
621 expected = ast.Mojom(
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)
653 def testValidFixedSizeArray(self):
654 """Tests parsing a fixed size array."""
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;
664 expected = ast.Mojom(
671 [ast.StructField('normal_array', None, 'int32[]', None),
672 ast.StructField('fixed_size_array_one_entry', None, 'int32[1]',
674 ast.StructField('fixed_size_array_ten_entries', None,
676 ast.StructField('nested_arrays', None,
677 'int32[1][][2]', None)]))])
678 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
680 def testValidNestedArray(self):
681 """Tests parsing a nested array."""
683 source = "struct MyStruct { array<array<int32>> nested_array; };"
684 expected = ast.Mojom(
691 ast.StructField('nested_array', None, 'int32[][]', None)))])
692 self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
694 def testInvalidFixedArraySize(self):
695 """Tests that invalid fixed array bounds are correctly detected."""
699 array<int32, 0> zero_size_array;
702 with self.assertRaisesRegexp(
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")
710 array<int32, 999999999999> too_big_array;
713 with self.assertRaisesRegexp(
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")
721 array<int32, abcdefg> not_a_number;
724 with self.assertRaisesRegexp(
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")
730 def testValidAssociativeArrays(self):
731 """Tests that we can parse valid associative array structures."""
733 source1 = "struct MyStruct { map<string, uint8> data; };"
734 expected1 = ast.Mojom(
741 [ast.StructField('data', None, 'uint8{string}', None)]))])
742 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
744 source2 = "interface MyInterface { MyMethod(map<string, uint8> a); };"
745 expected2 = ast.Mojom(
756 ast.Parameter('a', None, 'uint8{string}')),
758 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
760 source3 = "struct MyStruct { map<string, array<uint8>> data; };"
761 expected3 = ast.Mojom(
768 [ast.StructField('data', None, 'uint8[]{string}', None)]))])
769 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
771 def testValidMethod(self):
772 """Tests parsing method declarations."""
774 source1 = "interface MyInterface { MyMethod(int32 a); };"
775 expected1 = ast.Mojom(
785 ast.ParameterList(ast.Parameter('a', None, 'int32')),
787 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
790 interface MyInterface {
791 MyMethod1@0(int32 a@0, int64 b@1);
795 expected2 = ast.Mojom(
805 ast.ParameterList([ast.Parameter('a', ast.Ordinal(0),
807 ast.Parameter('b', ast.Ordinal(1),
814 ast.ParameterList())]))])
815 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
818 interface MyInterface {
819 MyMethod(string a) => (int32 a, bool b);
822 expected3 = ast.Mojom(
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)
837 def testInvalidMethods(self):
838 """Tests that invalid method declarations are correctly detected."""
840 # No trailing commas.
842 interface MyInterface {
846 with self.assertRaisesRegexp(
848 r"^my_file\.mojom:2: Error: Unexpected '\)':\n"
849 r" *MyMethod\(string a,\);$"):
850 parser.Parse(source1, "my_file.mojom")
854 interface MyInterface {
855 MyMethod(, string a);
858 with self.assertRaisesRegexp(
860 r"^my_file\.mojom:2: Error: Unexpected ',':\n"
861 r" *MyMethod\(, string a\);$"):
862 parser.Parse(source2, "my_file.mojom")
864 def testValidInterfaceDefinitions(self):
865 """Tests all types of definitions that can occur in an interface."""
868 interface MyInterface {
869 enum MyEnum { VALUE };
870 const int32 kMyConst = 123;
871 MyMethod(int32 x) => (MyEnum y);
874 expected = ast.Mojom(
882 ast.EnumValueList(ast.EnumValue('VALUE', None))),
883 ast.Const('kMyConst', 'int32', '123'),
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)
891 def testInvalidInterfaceDefinitions(self):
892 """Tests that definitions that aren't allowed in an interface are correctly
896 interface MyInterface {
902 with self.assertRaisesRegexp(
904 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
905 r" *struct MyStruct {$"):
906 parser.Parse(source1, "my_file.mojom")
909 interface MyInterface {
910 interface MyInnerInterface {
915 with self.assertRaisesRegexp(
917 r"^my_file\.mojom:2: Error: Unexpected 'interface':\n"
918 r" *interface MyInnerInterface {$"):
919 parser.Parse(source2, "my_file.mojom")
922 interface MyInterface {
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(
930 r"^my_file\.mojom:2: Error: Unexpected 'my_field':\n"
931 r" *int32 my_field;$"):
932 parser.Parse(source3, "my_file.mojom")
934 def testValidAttributes(self):
935 """Tests parsing attributes (and attribute lists)."""
937 # Note: We use structs because they have (optional) attribute lists.
939 # Empty attribute list.
940 source1 = "[] struct MyStruct {};"
941 expected1 = ast.Mojom(
944 [ast.Struct('MyStruct', ast.AttributeList(), ast.StructBody())])
945 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
947 # One-element attribute list, with name value.
948 source2 = "[MyAttribute=MyName] struct MyStruct {};"
949 expected2 = ast.Mojom(
954 ast.AttributeList(ast.Attribute("MyAttribute", "MyName")),
956 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
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(
965 ast.AttributeList([ast.Attribute("MyAttribute1", "hello"),
966 ast.Attribute("MyAttribute2", 5)]),
968 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
970 # TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()|
971 # literal (non-name) values, which is extremely dubious.)
973 def testInvalidAttributes(self):
974 """Tests that invalid attributes and attribute lists are correctly
977 # Trailing commas not allowed.
978 source1 = "[MyAttribute=MyName,] struct MyStruct {};"
979 with self.assertRaisesRegexp(
981 r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
982 r"\[MyAttribute=MyName,\] struct MyStruct {};$"):
983 parser.Parse(source1, "my_file.mojom")
986 source2 = "[MyAttribute=] struct MyStruct {};"
987 with self.assertRaisesRegexp(
989 r"^my_file\.mojom:1: Error: Unexpected '\]':\n"
990 r"\[MyAttribute=\] struct MyStruct {};$"):
991 parser.Parse(source2, "my_file.mojom")
994 source3 = "[=MyName] struct MyStruct {};"
995 with self.assertRaisesRegexp(
997 r"^my_file\.mojom:1: Error: Unexpected '=':\n"
998 r"\[=MyName\] struct MyStruct {};$"):
999 parser.Parse(source3, "my_file.mojom")
1001 def testValidImports(self):
1002 """Tests parsing import statements."""
1004 # One import (no module statement).
1005 source1 = "import \"somedir/my.mojom\";"
1006 expected1 = ast.Mojom(
1008 ast.ImportList(ast.Import("somedir/my.mojom")),
1010 self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1)
1012 # Two imports (no module statement).
1014 import "somedir/my1.mojom";
1015 import "somedir/my2.mojom";
1017 expected2 = ast.Mojom(
1019 ast.ImportList([ast.Import("somedir/my1.mojom"),
1020 ast.Import("somedir/my2.mojom")]),
1022 self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2)
1024 # Imports with module statement.
1027 import "somedir/my1.mojom";
1028 import "somedir/my2.mojom";
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")]),
1035 self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3)
1037 def testInvalidImports(self):
1038 """Tests that invalid import statements are correctly detected."""
1041 // Make the error occur on line 2.
1044 with self.assertRaisesRegexp(
1046 r"^my_file\.mojom:2: Error: Unexpected 'invalid':\n"
1047 r" *import invalid$"):
1048 parser.Parse(source1, "my_file.mojom")
1051 import // Missing string.
1056 with self.assertRaisesRegexp(
1058 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
1059 r" *struct MyStruct {$"):
1060 parser.Parse(source2, "my_file.mojom")
1063 import "foo.mojom" // Missing semicolon.
1068 with self.assertRaisesRegexp(
1070 r"^my_file\.mojom:2: Error: Unexpected 'struct':\n"
1071 r" *struct MyStruct {$"):
1072 parser.Parse(source3, "my_file.mojom")
1074 def testValidNullableTypes(self):
1075 """Tests parsing nullable types."""
1079 int32? a; // This is actually invalid, but handled at a different
1083 array<string ? > ? d;
1084 array<array<int32>?>? e;
1086 array<string?, 1>? g;
1089 handle<data_pipe_consumer>? j;
1090 handle<data_pipe_producer>? k;
1091 handle<message_pipe>? l;
1092 handle<shared_buffer>? m;
1096 expected = ast.Mojom(
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>?',
1114 ast.StructField('k', None, 'handle<data_pipe_producer>?',
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)
1121 def testInvalidNullableTypes(self):
1122 """Tests that invalid nullable types are correctly detected."""
1128 with self.assertRaisesRegexp(
1130 r"^my_file\.mojom:2: Error: Unexpected '\?':\n"
1131 r" *string\?\? a;$"):
1132 parser.Parse(source1, "my_file.mojom")
1136 handle?<data_pipe_consumer> a;
1139 with self.assertRaisesRegexp(
1141 r"^my_file\.mojom:2: Error: Unexpected '<':\n"
1142 r" *handle\?<data_pipe_consumer> a;$"):
1143 parser.Parse(source2, "my_file.mojom")
1150 with self.assertRaisesRegexp(
1152 r"^my_file\.mojom:2: Error: Unexpected '&':\n"
1153 r" *some_interface\?& a;$"):
1154 parser.Parse(source3, "my_file.mojom")
1156 if __name__ == "__main__":