Index: mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py |
diff --git a/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py b/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py |
deleted file mode 100644 |
index 65c2fca42ed700e28e7919503fd1f562627b6be8..0000000000000000000000000000000000000000 |
--- a/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py |
+++ /dev/null |
@@ -1,1330 +0,0 @@ |
-# Copyright 2014 The Chromium Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-import imp |
-import os.path |
-import sys |
-import unittest |
- |
-def _GetDirAbove(dirname): |
- """Returns the directory "above" this file containing |dirname| (which must |
- also be "above" this file).""" |
- path = os.path.abspath(__file__) |
- while True: |
- path, tail = os.path.split(path) |
- assert tail |
- if tail == dirname: |
- return path |
- |
-try: |
- imp.find_module("mojom") |
-except ImportError: |
- sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) |
-import mojom.parse.ast as ast |
-import mojom.parse.lexer as lexer |
-import mojom.parse.parser as parser |
- |
- |
-class ParserTest(unittest.TestCase): |
- """Tests |parser.Parse()|.""" |
- |
- def testTrivialValidSource(self): |
- """Tests a trivial, but valid, .mojom source.""" |
- |
- source = """\ |
- // This is a comment. |
- |
- module my_module; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- []) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testSourceWithCrLfs(self): |
- """Tests a .mojom source with CR-LFs instead of LFs.""" |
- |
- source = "// This is a comment.\r\n\r\nmodule my_module;\r\n" |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- []) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testUnexpectedEOF(self): |
- """Tests a "truncated" .mojom source.""" |
- |
- source = """\ |
- // This is a comment. |
- |
- module my_module |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom: Error: Unexpected end of file$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testCommentLineNumbers(self): |
- """Tests that line numbers are correctly tracked when comments are |
- present.""" |
- |
- source1 = """\ |
- // Isolated C++-style comments. |
- |
- // Foo. |
- asdf1 |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\n *asdf1$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- // Consecutive C++-style comments. |
- // Foo. |
- // Bar. |
- |
- struct Yada { // Baz. |
- // Quux. |
- int32 x; |
- }; |
- |
- asdf2 |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\n *asdf2$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- /* Single-line C-style comments. */ |
- /* Foobar. */ |
- |
- /* Baz. */ |
- asdf3 |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\n *asdf3$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- source4 = """\ |
- /* Multi-line C-style comments. |
- */ |
- /* |
- Foo. |
- Bar. |
- */ |
- |
- /* Baz |
- Quux. */ |
- asdf4 |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\n *asdf4$"): |
- parser.Parse(source4, "my_file.mojom") |
- |
- |
- def testSimpleStruct(self): |
- """Tests a simple .mojom source that just defines a struct.""" |
- |
- source = """\ |
- module my_module; |
- |
- struct MyStruct { |
- int32 a; |
- double b; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a', None, 'int32', None), |
- ast.StructField('b', None, 'double', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testSimpleStructWithoutModule(self): |
- """Tests a simple struct without an explict module statement.""" |
- |
- source = """\ |
- struct MyStruct { |
- int32 a; |
- double b; |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a', None, 'int32', None), |
- ast.StructField('b', None, 'double', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testValidStructDefinitions(self): |
- """Tests all types of definitions that can occur in a struct.""" |
- |
- source = """\ |
- struct MyStruct { |
- enum MyEnum { VALUE }; |
- const double kMyConst = 1.23; |
- int32 a; |
- SomeOtherStruct b; // Invalidity detected at another stage. |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.Enum('MyEnum', |
- ast.EnumValueList(ast.EnumValue('VALUE', None))), |
- ast.Const('kMyConst', 'double', '1.23'), |
- ast.StructField('a', None, 'int32', None), |
- ast.StructField('b', None, 'SomeOtherStruct', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidStructDefinitions(self): |
- """Tests that definitions that aren't allowed in a struct are correctly |
- detected.""" |
- |
- source1 = """\ |
- struct MyStruct { |
- MyMethod(int32 a); |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '\(':\n" |
- r" *MyMethod\(int32 a\);$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- struct MyStruct { |
- struct MyInnerStruct { |
- int32 a; |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'struct':\n" |
- r" *struct MyInnerStruct {$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- struct MyStruct { |
- interface MyInterface { |
- MyMethod(int32 a); |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'interface':\n" |
- r" *interface MyInterface {$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testMissingModuleName(self): |
- """Tests an (invalid) .mojom with a missing module name.""" |
- |
- source1 = """\ |
- // Missing module name. |
- module ; |
- struct MyStruct { |
- int32 a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected ';':\n *module ;$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- # Another similar case, but make sure that line-number tracking/reporting |
- # is correct. |
- source2 = """\ |
- module |
- // This line intentionally left unblank. |
- |
- struct MyStruct { |
- int32 a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'struct':\n" |
- r" *struct MyStruct {$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- def testMultipleModuleStatements(self): |
- """Tests an (invalid) .mojom with multiple module statements.""" |
- |
- source = """\ |
- module foo; |
- module bar; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Multiple \"module\" statements not " |
- r"allowed:\n *module bar;$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testModuleStatementAfterImport(self): |
- """Tests an (invalid) .mojom with a module statement after an import.""" |
- |
- source = """\ |
- import "foo.mojom"; |
- module foo; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: \"module\" statements must precede imports " |
- r"and definitions:\n *module foo;$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testModuleStatementAfterDefinition(self): |
- """Tests an (invalid) .mojom with a module statement after a definition.""" |
- |
- source = """\ |
- struct MyStruct { |
- int32 a; |
- }; |
- module foo; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: \"module\" statements must precede imports " |
- r"and definitions:\n *module foo;$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testImportStatementAfterDefinition(self): |
- """Tests an (invalid) .mojom with an import statement after a definition.""" |
- |
- source = """\ |
- struct MyStruct { |
- int32 a; |
- }; |
- import "foo.mojom"; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: \"import\" statements must precede " |
- r"definitions:\n *import \"foo.mojom\";$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testEnums(self): |
- """Tests that enum statements are correctly parsed.""" |
- |
- source = """\ |
- module my_module; |
- enum MyEnum1 { VALUE1, VALUE2 }; // No trailing comma. |
- enum MyEnum2 { |
- VALUE1 = -1, |
- VALUE2 = 0, |
- VALUE3 = + 987, // Check that space is allowed. |
- VALUE4 = 0xAF12, |
- VALUE5 = -0x09bcd, |
- VALUE6 = VALUE5, |
- VALUE7, // Leave trailing comma. |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Enum( |
- 'MyEnum1', |
- ast.EnumValueList([ast.EnumValue('VALUE1', None), |
- ast.EnumValue('VALUE2', None)])), |
- ast.Enum( |
- 'MyEnum2', |
- ast.EnumValueList([ast.EnumValue('VALUE1', '-1'), |
- ast.EnumValue('VALUE2', '0'), |
- ast.EnumValue('VALUE3', '+987'), |
- ast.EnumValue('VALUE4', '0xAF12'), |
- ast.EnumValue('VALUE5', '-0x09bcd'), |
- ast.EnumValue('VALUE6', ('IDENTIFIER', |
- 'VALUE5')), |
- ast.EnumValue('VALUE7', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidEnumInitializers(self): |
- """Tests that invalid enum initializers are correctly detected.""" |
- |
- # No values. |
- source1 = """\ |
- enum MyEnum { |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '}':\n" |
- r" *};$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- # Floating point value. |
- source2 = "enum MyEnum { VALUE = 0.123 };" |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:1: Error: Unexpected '0\.123':\n" |
- r"enum MyEnum { VALUE = 0\.123 };$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- # Boolean value. |
- source2 = "enum MyEnum { VALUE = true };" |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:1: Error: Unexpected 'true':\n" |
- r"enum MyEnum { VALUE = true };$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- def testConsts(self): |
- """Tests some constants and struct members initialized with them.""" |
- |
- source = """\ |
- module my_module; |
- |
- struct MyStruct { |
- const int8 kNumber = -1; |
- int8 number@0 = kNumber; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', None, |
- ast.StructBody( |
- [ast.Const('kNumber', 'int8', '-1'), |
- ast.StructField('number', ast.Ordinal(0), 'int8', |
- ('IDENTIFIER', 'kNumber'))]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testNoConditionals(self): |
- """Tests that ?: is not allowed.""" |
- |
- source = """\ |
- module my_module; |
- |
- enum MyEnum { |
- MY_ENUM_1 = 1 ? 2 : 3 |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected '\?':\n" |
- r" *MY_ENUM_1 = 1 \? 2 : 3$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testSimpleOrdinals(self): |
- """Tests that (valid) ordinal values are scanned correctly.""" |
- |
- source = """\ |
- module my_module; |
- |
- // This isn't actually valid .mojom, but the problem (missing ordinals) |
- // should be handled at a different level. |
- struct MyStruct { |
- int32 a0@0; |
- int32 a1@1; |
- int32 a2@2; |
- int32 a9@9; |
- int32 a10 @10; |
- int32 a11 @11; |
- int32 a29 @29; |
- int32 a1234567890 @1234567890; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a0', ast.Ordinal(0), 'int32', None), |
- ast.StructField('a1', ast.Ordinal(1), 'int32', None), |
- ast.StructField('a2', ast.Ordinal(2), 'int32', None), |
- ast.StructField('a9', ast.Ordinal(9), 'int32', None), |
- ast.StructField('a10', ast.Ordinal(10), 'int32', None), |
- ast.StructField('a11', ast.Ordinal(11), 'int32', None), |
- ast.StructField('a29', ast.Ordinal(29), 'int32', None), |
- ast.StructField('a1234567890', ast.Ordinal(1234567890), |
- 'int32', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidOrdinals(self): |
- """Tests that (lexically) invalid ordinals are correctly detected.""" |
- |
- source1 = """\ |
- module my_module; |
- |
- struct MyStruct { |
- int32 a_missing@; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- lexer.LexError, |
- r"^my_file\.mojom:4: Error: Missing ordinal value$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- module my_module; |
- |
- struct MyStruct { |
- int32 a_octal@01; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- lexer.LexError, |
- r"^my_file\.mojom:4: Error: " |
- r"Octal and hexadecimal ordinal values not allowed$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- module my_module; struct MyStruct { int32 a_invalid_octal@08; }; |
- """ |
- with self.assertRaisesRegexp( |
- lexer.LexError, |
- r"^my_file\.mojom:1: Error: " |
- r"Octal and hexadecimal ordinal values not allowed$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- source4 = "module my_module; struct MyStruct { int32 a_hex@0x1aB9; };" |
- with self.assertRaisesRegexp( |
- lexer.LexError, |
- r"^my_file\.mojom:1: Error: " |
- r"Octal and hexadecimal ordinal values not allowed$"): |
- parser.Parse(source4, "my_file.mojom") |
- |
- source5 = "module my_module; struct MyStruct { int32 a_hex@0X0; };" |
- with self.assertRaisesRegexp( |
- lexer.LexError, |
- r"^my_file\.mojom:1: Error: " |
- r"Octal and hexadecimal ordinal values not allowed$"): |
- parser.Parse(source5, "my_file.mojom") |
- |
- source6 = """\ |
- struct MyStruct { |
- int32 a_too_big@999999999999; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: " |
- r"Ordinal value 999999999999 too large:\n" |
- r" *int32 a_too_big@999999999999;$"): |
- parser.Parse(source6, "my_file.mojom") |
- |
- def testNestedNamespace(self): |
- """Tests that "nested" namespaces work.""" |
- |
- source = """\ |
- module my.mod; |
- |
- struct MyStruct { |
- int32 a; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my.mod'), None), |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody(ast.StructField('a', None, 'int32', None)))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testValidHandleTypes(self): |
- """Tests (valid) handle types.""" |
- |
- source = """\ |
- struct MyStruct { |
- handle a; |
- handle<data_pipe_consumer> b; |
- handle <data_pipe_producer> c; |
- handle < message_pipe > d; |
- handle |
- < shared_buffer |
- > e; |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a', None, 'handle', None), |
- ast.StructField('b', None, 'handle<data_pipe_consumer>', None), |
- ast.StructField('c', None, 'handle<data_pipe_producer>', None), |
- ast.StructField('d', None, 'handle<message_pipe>', None), |
- ast.StructField('e', None, 'handle<shared_buffer>', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidHandleType(self): |
- """Tests an invalid (unknown) handle type.""" |
- |
- source = """\ |
- struct MyStruct { |
- handle<wtf_is_this> foo; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: " |
- r"Invalid handle type 'wtf_is_this':\n" |
- r" *handle<wtf_is_this> foo;$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testValidDefaultValues(self): |
- """Tests default values that are valid (to the parser).""" |
- |
- source = """\ |
- struct MyStruct { |
- int16 a0 = 0; |
- uint16 a1 = 0x0; |
- uint16 a2 = 0x00; |
- uint16 a3 = 0x01; |
- uint16 a4 = 0xcd; |
- int32 a5 = 12345; |
- int64 a6 = -12345; |
- int64 a7 = +12345; |
- uint32 a8 = 0x12cd3; |
- uint32 a9 = -0x12cD3; |
- uint32 a10 = +0x12CD3; |
- bool a11 = true; |
- bool a12 = false; |
- float a13 = 1.2345; |
- float a14 = -1.2345; |
- float a15 = +1.2345; |
- float a16 = 123.; |
- float a17 = .123; |
- double a18 = 1.23E10; |
- double a19 = 1.E-10; |
- double a20 = .5E+10; |
- double a21 = -1.23E10; |
- double a22 = +.123E10; |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a0', None, 'int16', '0'), |
- ast.StructField('a1', None, 'uint16', '0x0'), |
- ast.StructField('a2', None, 'uint16', '0x00'), |
- ast.StructField('a3', None, 'uint16', '0x01'), |
- ast.StructField('a4', None, 'uint16', '0xcd'), |
- ast.StructField('a5' , None, 'int32', '12345'), |
- ast.StructField('a6', None, 'int64', '-12345'), |
- ast.StructField('a7', None, 'int64', '+12345'), |
- ast.StructField('a8', None, 'uint32', '0x12cd3'), |
- ast.StructField('a9', None, 'uint32', '-0x12cD3'), |
- ast.StructField('a10', None, 'uint32', '+0x12CD3'), |
- ast.StructField('a11', None, 'bool', 'true'), |
- ast.StructField('a12', None, 'bool', 'false'), |
- ast.StructField('a13', None, 'float', '1.2345'), |
- ast.StructField('a14', None, 'float', '-1.2345'), |
- ast.StructField('a15', None, 'float', '+1.2345'), |
- ast.StructField('a16', None, 'float', '123.'), |
- ast.StructField('a17', None, 'float', '.123'), |
- ast.StructField('a18', None, 'double', '1.23E10'), |
- ast.StructField('a19', None, 'double', '1.E-10'), |
- ast.StructField('a20', None, 'double', '.5E+10'), |
- ast.StructField('a21', None, 'double', '-1.23E10'), |
- ast.StructField('a22', None, 'double', '+.123E10')]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testValidFixedSizeArray(self): |
- """Tests parsing a fixed size array.""" |
- |
- source = """\ |
- struct MyStruct { |
- array<int32> normal_array; |
- array<int32, 1> fixed_size_array_one_entry; |
- array<int32, 10> fixed_size_array_ten_entries; |
- array<array<array<int32, 1>>, 2> nested_arrays; |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('normal_array', None, 'int32[]', None), |
- ast.StructField('fixed_size_array_one_entry', None, 'int32[1]', |
- None), |
- ast.StructField('fixed_size_array_ten_entries', None, |
- 'int32[10]', None), |
- ast.StructField('nested_arrays', None, |
- 'int32[1][][2]', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testValidNestedArray(self): |
- """Tests parsing a nested array.""" |
- |
- source = "struct MyStruct { array<array<int32>> nested_array; };" |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- ast.StructField('nested_array', None, 'int32[][]', None)))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidFixedArraySize(self): |
- """Tests that invalid fixed array bounds are correctly detected.""" |
- |
- source1 = """\ |
- struct MyStruct { |
- array<int32, 0> zero_size_array; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Fixed array size 0 invalid:\n" |
- r" *array<int32, 0> zero_size_array;$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- struct MyStruct { |
- array<int32, 999999999999> too_big_array; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Fixed array size 999999999999 invalid:\n" |
- r" *array<int32, 999999999999> too_big_array;$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- struct MyStruct { |
- array<int32, abcdefg> not_a_number; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'abcdefg':\n" |
- r" *array<int32, abcdefg> not_a_number;"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testValidAssociativeArrays(self): |
- """Tests that we can parse valid associative array structures.""" |
- |
- source1 = "struct MyStruct { map<string, uint8> data; };" |
- expected1 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('data', None, 'uint8{string}', None)]))]) |
- self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1) |
- |
- source2 = "interface MyInterface { MyMethod(map<string, uint8> a); };" |
- expected2 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Interface( |
- 'MyInterface', |
- None, |
- ast.InterfaceBody( |
- ast.Method( |
- 'MyMethod', |
- None, |
- ast.ParameterList( |
- ast.Parameter('a', None, 'uint8{string}')), |
- None)))]) |
- self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2) |
- |
- source3 = "struct MyStruct { map<string, array<uint8>> data; };" |
- expected3 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('data', None, 'uint8[]{string}', None)]))]) |
- self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3) |
- |
- def testValidMethod(self): |
- """Tests parsing method declarations.""" |
- |
- source1 = "interface MyInterface { MyMethod(int32 a); };" |
- expected1 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Interface( |
- 'MyInterface', |
- None, |
- ast.InterfaceBody( |
- ast.Method( |
- 'MyMethod', |
- None, |
- ast.ParameterList(ast.Parameter('a', None, 'int32')), |
- None)))]) |
- self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1) |
- |
- source2 = """\ |
- interface MyInterface { |
- MyMethod1@0(int32 a@0, int64 b@1); |
- MyMethod2@1() => (); |
- }; |
- """ |
- expected2 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Interface( |
- 'MyInterface', |
- None, |
- ast.InterfaceBody( |
- [ast.Method( |
- 'MyMethod1', |
- ast.Ordinal(0), |
- ast.ParameterList([ast.Parameter('a', ast.Ordinal(0), |
- 'int32'), |
- ast.Parameter('b', ast.Ordinal(1), |
- 'int64')]), |
- None), |
- ast.Method( |
- 'MyMethod2', |
- ast.Ordinal(1), |
- ast.ParameterList(), |
- ast.ParameterList())]))]) |
- self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2) |
- |
- source3 = """\ |
- interface MyInterface { |
- MyMethod(string a) => (int32 a, bool b); |
- }; |
- """ |
- expected3 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Interface( |
- 'MyInterface', |
- None, |
- ast.InterfaceBody( |
- ast.Method( |
- 'MyMethod', |
- None, |
- ast.ParameterList(ast.Parameter('a', None, 'string')), |
- ast.ParameterList([ast.Parameter('a', None, 'int32'), |
- ast.Parameter('b', None, 'bool')]))))]) |
- self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3) |
- |
- def testInvalidMethods(self): |
- """Tests that invalid method declarations are correctly detected.""" |
- |
- # No trailing commas. |
- source1 = """\ |
- interface MyInterface { |
- MyMethod(string a,); |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '\)':\n" |
- r" *MyMethod\(string a,\);$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- # No leading commas. |
- source2 = """\ |
- interface MyInterface { |
- MyMethod(, string a); |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected ',':\n" |
- r" *MyMethod\(, string a\);$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- def testValidInterfaceDefinitions(self): |
- """Tests all types of definitions that can occur in an interface.""" |
- |
- source = """\ |
- interface MyInterface { |
- enum MyEnum { VALUE }; |
- const int32 kMyConst = 123; |
- MyMethod(int32 x) => (MyEnum y); |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Interface( |
- 'MyInterface', |
- None, |
- ast.InterfaceBody( |
- [ast.Enum('MyEnum', |
- ast.EnumValueList(ast.EnumValue('VALUE', None))), |
- ast.Const('kMyConst', 'int32', '123'), |
- ast.Method( |
- 'MyMethod', |
- None, |
- ast.ParameterList(ast.Parameter('x', None, 'int32')), |
- ast.ParameterList(ast.Parameter('y', None, 'MyEnum')))]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidInterfaceDefinitions(self): |
- """Tests that definitions that aren't allowed in an interface are correctly |
- detected.""" |
- |
- source1 = """\ |
- interface MyInterface { |
- struct MyStruct { |
- int32 a; |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'struct':\n" |
- r" *struct MyStruct {$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- interface MyInterface { |
- interface MyInnerInterface { |
- MyMethod(int32 x); |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'interface':\n" |
- r" *interface MyInnerInterface {$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- interface MyInterface { |
- int32 my_field; |
- }; |
- """ |
- # The parser thinks that "int32" is a plausible name for a method, so it's |
- # "my_field" that gives it away. |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'my_field':\n" |
- r" *int32 my_field;$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testValidAttributes(self): |
- """Tests parsing attributes (and attribute lists).""" |
- |
- # Note: We use structs because they have (optional) attribute lists. |
- |
- # Empty attribute list. |
- source1 = "[] struct MyStruct {};" |
- expected1 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct('MyStruct', ast.AttributeList(), ast.StructBody())]) |
- self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1) |
- |
- # One-element attribute list, with name value. |
- source2 = "[MyAttribute=MyName] struct MyStruct {};" |
- expected2 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- ast.AttributeList(ast.Attribute("MyAttribute", "MyName")), |
- ast.StructBody())]) |
- self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2) |
- |
- # Two-element attribute list, with one string value and one integer value. |
- source3 = "[MyAttribute1 = \"hello\", MyAttribute2 = 5] struct MyStruct {};" |
- expected3 = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- ast.AttributeList([ast.Attribute("MyAttribute1", "hello"), |
- ast.Attribute("MyAttribute2", 5)]), |
- ast.StructBody())]) |
- self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3) |
- |
- # TODO(vtl): Boolean attributes don't work yet. (In fact, we just |eval()| |
- # literal (non-name) values, which is extremely dubious.) |
- |
- def testInvalidAttributes(self): |
- """Tests that invalid attributes and attribute lists are correctly |
- detected.""" |
- |
- # Trailing commas not allowed. |
- source1 = "[MyAttribute=MyName,] struct MyStruct {};" |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:1: Error: Unexpected '\]':\n" |
- r"\[MyAttribute=MyName,\] struct MyStruct {};$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- # Missing value. |
- source2 = "[MyAttribute=] struct MyStruct {};" |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:1: Error: Unexpected '\]':\n" |
- r"\[MyAttribute=\] struct MyStruct {};$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- # Missing key. |
- source3 = "[=MyName] struct MyStruct {};" |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:1: Error: Unexpected '=':\n" |
- r"\[=MyName\] struct MyStruct {};$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testValidImports(self): |
- """Tests parsing import statements.""" |
- |
- # One import (no module statement). |
- source1 = "import \"somedir/my.mojom\";" |
- expected1 = ast.Mojom( |
- None, |
- ast.ImportList(ast.Import("somedir/my.mojom")), |
- []) |
- self.assertEquals(parser.Parse(source1, "my_file.mojom"), expected1) |
- |
- # Two imports (no module statement). |
- source2 = """\ |
- import "somedir/my1.mojom"; |
- import "somedir/my2.mojom"; |
- """ |
- expected2 = ast.Mojom( |
- None, |
- ast.ImportList([ast.Import("somedir/my1.mojom"), |
- ast.Import("somedir/my2.mojom")]), |
- []) |
- self.assertEquals(parser.Parse(source2, "my_file.mojom"), expected2) |
- |
- # Imports with module statement. |
- source3 = """\ |
- module my_module; |
- import "somedir/my1.mojom"; |
- import "somedir/my2.mojom"; |
- """ |
- expected3 = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList([ast.Import("somedir/my1.mojom"), |
- ast.Import("somedir/my2.mojom")]), |
- []) |
- self.assertEquals(parser.Parse(source3, "my_file.mojom"), expected3) |
- |
- def testInvalidImports(self): |
- """Tests that invalid import statements are correctly detected.""" |
- |
- source1 = """\ |
- // Make the error occur on line 2. |
- import invalid |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'invalid':\n" |
- r" *import invalid$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- import // Missing string. |
- struct MyStruct { |
- int32 a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'struct':\n" |
- r" *struct MyStruct {$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- import "foo.mojom" // Missing semicolon. |
- struct MyStruct { |
- int32 a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected 'struct':\n" |
- r" *struct MyStruct {$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testValidNullableTypes(self): |
- """Tests parsing nullable types.""" |
- |
- source = """\ |
- struct MyStruct { |
- int32? a; // This is actually invalid, but handled at a different |
- // level. |
- string? b; |
- array<int32> ? c; |
- array<string ? > ? d; |
- array<array<int32>?>? e; |
- array<int32, 1>? f; |
- array<string?, 1>? g; |
- some_struct? h; |
- handle? i; |
- handle<data_pipe_consumer>? j; |
- handle<data_pipe_producer>? k; |
- handle<message_pipe>? l; |
- handle<shared_buffer>? m; |
- some_interface&? n; |
- }; |
- """ |
- expected = ast.Mojom( |
- None, |
- ast.ImportList(), |
- [ast.Struct( |
- 'MyStruct', |
- None, |
- ast.StructBody( |
- [ast.StructField('a', None, 'int32?', None), |
- ast.StructField('b', None, 'string?', None), |
- ast.StructField('c', None, 'int32[]?', None), |
- ast.StructField('d', None, 'string?[]?', None), |
- ast.StructField('e', None, 'int32[]?[]?', None), |
- ast.StructField('f', None, 'int32[1]?', None), |
- ast.StructField('g', None, 'string?[1]?', None), |
- ast.StructField('h', None, 'some_struct?', None), |
- ast.StructField('i', None, 'handle?', None), |
- ast.StructField('j', None, 'handle<data_pipe_consumer>?', |
- None), |
- ast.StructField('k', None, 'handle<data_pipe_producer>?', |
- None), |
- ast.StructField('l', None, 'handle<message_pipe>?', None), |
- ast.StructField('m', None, 'handle<shared_buffer>?', None), |
- ast.StructField('n', None, 'some_interface&?', None)]))]) |
- self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) |
- |
- def testInvalidNullableTypes(self): |
- """Tests that invalid nullable types are correctly detected.""" |
- source1 = """\ |
- struct MyStruct { |
- string?? a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '\?':\n" |
- r" *string\?\? a;$"): |
- parser.Parse(source1, "my_file.mojom") |
- |
- source2 = """\ |
- struct MyStruct { |
- handle?<data_pipe_consumer> a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '<':\n" |
- r" *handle\?<data_pipe_consumer> a;$"): |
- parser.Parse(source2, "my_file.mojom") |
- |
- source3 = """\ |
- struct MyStruct { |
- some_interface?& a; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:2: Error: Unexpected '&':\n" |
- r" *some_interface\?& a;$"): |
- parser.Parse(source3, "my_file.mojom") |
- |
- def testSimpleUnion(self): |
- """Tests a simple .mojom source that just defines a union.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- int32 a; |
- double b; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Union( |
- 'MyUnion', |
- ast.UnionBody([ |
- ast.UnionField('a', None, 'int32'), |
- ast.UnionField('b', None, 'double') |
- ]))]) |
- actual = parser.Parse(source, "my_file.mojom") |
- self.assertEquals(actual, expected) |
- |
- def testUnionWithOrdinals(self): |
- """Test that ordinals are assigned to fields.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- int32 a @10; |
- double b @30; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Union( |
- 'MyUnion', |
- ast.UnionBody([ |
- ast.UnionField('a', ast.Ordinal(10), 'int32'), |
- ast.UnionField('b', ast.Ordinal(30), 'double') |
- ]))]) |
- actual = parser.Parse(source, "my_file.mojom") |
- self.assertEquals(actual, expected) |
- |
- def testUnionWithStructMembers(self): |
- """Test that struct members are accepted.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- SomeStruct s; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Union( |
- 'MyUnion', |
- ast.UnionBody([ |
- ast.UnionField('s', None, 'SomeStruct') |
- ]))]) |
- actual = parser.Parse(source, "my_file.mojom") |
- self.assertEquals(actual, expected) |
- |
- def testUnionWithArrayMember(self): |
- """Test that array members are accepted.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- array<int32> a; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Union( |
- 'MyUnion', |
- ast.UnionBody([ |
- ast.UnionField('a', None, 'int32[]') |
- ]))]) |
- actual = parser.Parse(source, "my_file.mojom") |
- self.assertEquals(actual, expected) |
- |
- def testUnionWithMapMember(self): |
- """Test that map members are accepted.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- map<int32, string> m; |
- }; |
- """ |
- expected = ast.Mojom( |
- ast.Module(('IDENTIFIER', 'my_module'), None), |
- ast.ImportList(), |
- [ast.Union( |
- 'MyUnion', |
- ast.UnionBody([ |
- ast.UnionField('m', None, 'string{int32}') |
- ]))]) |
- actual = parser.Parse(source, "my_file.mojom") |
- self.assertEquals(actual, expected) |
- |
- def testUnionDisallowNestedStruct(self): |
- """Tests that structs cannot be nested in unions.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- struct MyStruct { |
- int32 a; |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'struct':\n" |
- r" *struct MyStruct {$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testUnionDisallowNestedInterfaces(self): |
- """Tests that interfaces cannot be nested in unions.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- interface MyInterface { |
- MyMethod(int32 a); |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'interface':\n" |
- r" *interface MyInterface {$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testUnionDisallowNestedUnion(self): |
- """Tests that unions cannot be nested in unions.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- union MyOtherUnion { |
- int32 a; |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'union':\n" |
- r" *union MyOtherUnion {$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- def testUnionDisallowNestedEnum(self): |
- """Tests that enums cannot be nested in unions.""" |
- source = """\ |
- module my_module; |
- |
- union MyUnion { |
- enum MyEnum { |
- A, |
- }; |
- }; |
- """ |
- with self.assertRaisesRegexp( |
- parser.ParseError, |
- r"^my_file\.mojom:4: Error: Unexpected 'enum':\n" |
- r" *enum MyEnum {$"): |
- parser.Parse(source, "my_file.mojom") |
- |
- |
-if __name__ == "__main__": |
- unittest.main() |