| OLD | NEW |
| (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 mojo_lexer | |
| 6 import mojo_parser | |
| 7 import unittest | |
| 8 | |
| 9 | |
| 10 class MojoParserTest(unittest.TestCase): | |
| 11 """Tests mojo_parser (in particular, Parse()).""" | |
| 12 | |
| 13 def testTrivialValidSource(self): | |
| 14 """Tests a trivial, but valid, .mojom source.""" | |
| 15 source = """\ | |
| 16 // This is a comment. | |
| 17 | |
| 18 module my_module { | |
| 19 } | |
| 20 """ | |
| 21 self.assertEquals(mojo_parser.Parse(source, "my_file.mojom"), | |
| 22 [("MODULE", "my_module", None)]) | |
| 23 | |
| 24 def testSourceWithCrLfs(self): | |
| 25 """Tests a .mojom source with CR-LFs instead of LFs.""" | |
| 26 source = "// This is a comment.\r\n\r\nmodule my_module {\r\n}\r\n"; | |
| 27 self.assertEquals(mojo_parser.Parse(source, "my_file.mojom"), | |
| 28 [("MODULE", "my_module", None)]) | |
| 29 | |
| 30 def testUnexpectedEOF(self): | |
| 31 """Tests a "truncated" .mojom source.""" | |
| 32 source = """\ | |
| 33 // This is a comment. | |
| 34 | |
| 35 module my_module { | |
| 36 """ | |
| 37 with self.assertRaisesRegexp( | |
| 38 mojo_parser.ParseError, | |
| 39 r"^my_file\.mojom: Error: Unexpected end of file$"): | |
| 40 mojo_parser.Parse(source, "my_file.mojom") | |
| 41 | |
| 42 def testSimpleStruct(self): | |
| 43 """Tests a simple .mojom source that just defines a struct.""" | |
| 44 source ="""\ | |
| 45 module my_module { | |
| 46 | |
| 47 struct MyStruct { | |
| 48 int32 a; | |
| 49 double b; | |
| 50 }; | |
| 51 | |
| 52 } // module my_module | |
| 53 """ | |
| 54 # Note: Output as pretty-printed on failure by the test harness. | |
| 55 expected = \ | |
| 56 [('MODULE', | |
| 57 'my_module', | |
| 58 [('STRUCT', | |
| 59 'MyStruct', | |
| 60 None, | |
| 61 [('FIELD', 'int32', 'a', None, None), | |
| 62 ('FIELD', 'double', 'b', None, None)])])] | |
| 63 self.assertEquals(mojo_parser.Parse(source, "my_file.mojom"), expected) | |
| 64 | |
| 65 def testEnumExpressions(self): | |
| 66 """Tests an enum with values calculated using simple expressions.""" | |
| 67 source = """\ | |
| 68 module my_module { | |
| 69 | |
| 70 enum MyEnum { | |
| 71 MY_ENUM_1 = 1, | |
| 72 MY_ENUM_2 = 1 + 1, | |
| 73 MY_ENUM_3 = 1 * 3, | |
| 74 MY_ENUM_4 = 2 * (1 + 1), | |
| 75 MY_ENUM_5 = 1 + 2 * 2, | |
| 76 MY_ENUM_6 = -6 / -2, | |
| 77 MY_ENUM_7 = 3 | (1 << 2), | |
| 78 MY_ENUM_8 = 16 >> 1, | |
| 79 MY_ENUM_9 = 1 ^ 15 & 8, | |
| 80 MY_ENUM_10 = 110 % 100, | |
| 81 MY_ENUM_MINUS_1 = ~0 | |
| 82 }; | |
| 83 | |
| 84 } // my_module | |
| 85 """ | |
| 86 expected = \ | |
| 87 [('MODULE', | |
| 88 'my_module', | |
| 89 [('ENUM', | |
| 90 'MyEnum', | |
| 91 [('ENUM_FIELD', 'MY_ENUM_1', ('EXPRESSION', ['1'])), | |
| 92 ('ENUM_FIELD', 'MY_ENUM_2', ('EXPRESSION', ['1', '+', '1'])), | |
| 93 ('ENUM_FIELD', 'MY_ENUM_3', ('EXPRESSION', ['1', '*', '3'])), | |
| 94 ('ENUM_FIELD', | |
| 95 'MY_ENUM_4', | |
| 96 ('EXPRESSION', | |
| 97 ['2', '*', '(', ('EXPRESSION', ['1', '+', '1']), ')'])), | |
| 98 ('ENUM_FIELD', | |
| 99 'MY_ENUM_5', | |
| 100 ('EXPRESSION', ['1', '+', '2', '*', '2'])), | |
| 101 ('ENUM_FIELD', | |
| 102 'MY_ENUM_6', | |
| 103 ('EXPRESSION', | |
| 104 ['-', ('EXPRESSION', ['6', '/', '-', ('EXPRESSION', ['2'])])])), | |
| 105 ('ENUM_FIELD', | |
| 106 'MY_ENUM_7', | |
| 107 ('EXPRESSION', | |
| 108 ['3', '|', '(', ('EXPRESSION', ['1', '<<', '2']), ')'])), | |
| 109 ('ENUM_FIELD', 'MY_ENUM_8', ('EXPRESSION', ['16', '>>', '1'])), | |
| 110 ('ENUM_FIELD', | |
| 111 'MY_ENUM_9', | |
| 112 ('EXPRESSION', ['1', '^', '15', '&', '8'])), | |
| 113 ('ENUM_FIELD', 'MY_ENUM_10', ('EXPRESSION', ['110', '%', '100'])), | |
| 114 ('ENUM_FIELD', | |
| 115 'MY_ENUM_MINUS_1', | |
| 116 ('EXPRESSION', ['~', ('EXPRESSION', ['0'])]))])])] | |
| 117 self.assertEquals(mojo_parser.Parse(source, "my_file.mojom"), expected) | |
| 118 | |
| 119 def testNoConditionals(self): | |
| 120 """Tests that ?: is not allowed.""" | |
| 121 source = """\ | |
| 122 module my_module { | |
| 123 | |
| 124 enum MyEnum { | |
| 125 MY_ENUM_1 = 1 ? 2 : 3 | |
| 126 }; | |
| 127 | |
| 128 } // my_module | |
| 129 """ | |
| 130 with self.assertRaisesRegexp( | |
| 131 mojo_lexer.LexError, | |
| 132 r"^my_file\.mojom:4: Error: Illegal character '\?'$"): | |
| 133 mojo_parser.Parse(source, "my_file.mojom") | |
| 134 | |
| 135 def testSimpleOrdinals(self): | |
| 136 """Tests that (valid) ordinal values are scanned correctly.""" | |
| 137 source = """\ | |
| 138 module my_module { | |
| 139 | |
| 140 // This isn't actually valid .mojom, but the problem (missing ordinals) should | |
| 141 // be handled at a different level. | |
| 142 struct MyStruct { | |
| 143 int32 a0 @0; | |
| 144 int32 a1 @1; | |
| 145 int32 a2 @2; | |
| 146 int32 a9 @9; | |
| 147 int32 a10 @10; | |
| 148 int32 a11 @11; | |
| 149 int32 a29 @29; | |
| 150 int32 a1234567890 @1234567890; | |
| 151 }; | |
| 152 | |
| 153 } // module my_module | |
| 154 """ | |
| 155 expected = \ | |
| 156 [('MODULE', | |
| 157 'my_module', | |
| 158 [('STRUCT', | |
| 159 'MyStruct', | |
| 160 None, | |
| 161 [('FIELD', 'int32', 'a0', '@0', None), | |
| 162 ('FIELD', 'int32', 'a1', '@1', None), | |
| 163 ('FIELD', 'int32', 'a2', '@2', None), | |
| 164 ('FIELD', 'int32', 'a9', '@9', None), | |
| 165 ('FIELD', 'int32', 'a10', '@10', None), | |
| 166 ('FIELD', 'int32', 'a11', '@11', None), | |
| 167 ('FIELD', 'int32', 'a29', '@29', None), | |
| 168 ('FIELD', 'int32', 'a1234567890', '@1234567890', None)])])] | |
| 169 self.assertEquals(mojo_parser.Parse(source, "my_file.mojom"), expected) | |
| 170 | |
| 171 def testInvalidOrdinals(self): | |
| 172 """Tests that (lexically) invalid ordinals are correctly detected.""" | |
| 173 source1 = """\ | |
| 174 module my_module { | |
| 175 | |
| 176 struct MyStruct { | |
| 177 int32 a_missing @; | |
| 178 }; | |
| 179 | |
| 180 } // module my_module | |
| 181 """ | |
| 182 with self.assertRaisesRegexp( | |
| 183 mojo_lexer.LexError, | |
| 184 r"^my_file\.mojom:4: Error: Missing ordinal value$"): | |
| 185 mojo_parser.Parse(source1, "my_file.mojom") | |
| 186 | |
| 187 source2 = """\ | |
| 188 module my_module { | |
| 189 | |
| 190 struct MyStruct { | |
| 191 int32 a_octal @01; | |
| 192 }; | |
| 193 | |
| 194 } // module my_module | |
| 195 """ | |
| 196 with self.assertRaisesRegexp( | |
| 197 mojo_lexer.LexError, | |
| 198 r"^my_file\.mojom:4: Error: " | |
| 199 r"Octal and hexadecimal ordinal values not allowed$"): | |
| 200 mojo_parser.Parse(source2, "my_file.mojom") | |
| 201 | |
| 202 source3 = """\ | |
| 203 module my_module { struct MyStruct { int32 a_invalid_octal @08; }; } | |
| 204 """ | |
| 205 with self.assertRaisesRegexp( | |
| 206 mojo_lexer.LexError, | |
| 207 r"^my_file\.mojom:1: Error: " | |
| 208 r"Octal and hexadecimal ordinal values not allowed$"): | |
| 209 mojo_parser.Parse(source3, "my_file.mojom") | |
| 210 | |
| 211 source4 = """\ | |
| 212 module my_module { struct MyStruct { int32 a_hex @0x1aB9; }; } | |
| 213 """ | |
| 214 with self.assertRaisesRegexp( | |
| 215 mojo_lexer.LexError, | |
| 216 r"^my_file\.mojom:1: Error: " | |
| 217 r"Octal and hexadecimal ordinal values not allowed$"): | |
| 218 mojo_parser.Parse(source4, "my_file.mojom") | |
| 219 | |
| 220 source5 = """\ | |
| 221 module my_module { struct MyStruct { int32 a_hex @0X0; }; } | |
| 222 """ | |
| 223 with self.assertRaisesRegexp( | |
| 224 mojo_lexer.LexError, | |
| 225 r"^my_file\.mojom:1: Error: " | |
| 226 r"Octal and hexadecimal ordinal values not allowed$"): | |
| 227 mojo_parser.Parse(source5, "my_file.mojom") | |
| 228 | |
| 229 | |
| 230 if __name__ == "__main__": | |
| 231 unittest.main() | |
| OLD | NEW |