Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / public / tools / bindings / pylib / mojom_tests / parse / parser_unittest.py
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 # Disable lint check for finding modules:
11 # pylint: disable=F0401
12
13 def _GetDirAbove(dirname):
14   """Returns the directory "above" this file containing |dirname| (which must
15   also be "above" this file)."""
16   path = os.path.abspath(__file__)
17   while True:
18     path, tail = os.path.split(path)
19     assert tail
20     if tail == dirname:
21       return path
22
23 try:
24   imp.find_module("mojom")
25 except ImportError:
26   sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
27 import mojom.parse.ast as ast
28 import mojom.parse.lexer as lexer
29 import mojom.parse.parser as parser
30
31
32 class ParserTest(unittest.TestCase):
33   """Tests |parser.Parse()|."""
34
35   def testTrivialValidSource(self):
36     """Tests a trivial, but valid, .mojom source."""
37     source = """\
38 // This is a comment.
39
40 module my_module {
41 }
42 """
43     self.assertEquals(parser.Parse(source, "my_file.mojom"),
44                       [("MODULE", "my_module", None)])
45
46   def testSourceWithCrLfs(self):
47     """Tests a .mojom source with CR-LFs instead of LFs."""
48     source = "// This is a comment.\r\n\r\nmodule my_module {\r\n}\r\n"
49     self.assertEquals(parser.Parse(source, "my_file.mojom"),
50                       [("MODULE", "my_module", None)])
51
52   def testUnexpectedEOF(self):
53     """Tests a "truncated" .mojom source."""
54     source = """\
55 // This is a comment.
56
57 module my_module {
58 """
59     with self.assertRaisesRegexp(
60         parser.ParseError,
61         r"^my_file\.mojom: Error: Unexpected end of file$"):
62       parser.Parse(source, "my_file.mojom")
63
64   def testSimpleStruct(self):
65     """Tests a simple .mojom source that just defines a struct."""
66     source = """\
67 module my_module {
68
69 struct MyStruct {
70   int32 a;
71   double b;
72 };
73
74 }  // module my_module
75 """
76     expected = \
77 [('MODULE',
78   'my_module',
79   [('STRUCT',
80     'MyStruct',
81     None,
82     [('FIELD', 'int32', 'a', ast.Ordinal(None), None),
83      ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])]
84     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
85
86   def testSimpleStructWithoutModule(self):
87     """Tests a simple struct without an enclosing module."""
88     source = """\
89 struct MyStruct {
90   int32 a;
91   double b;
92 };
93 """
94     expected = \
95 [('MODULE',
96   '',
97   [('STRUCT',
98     'MyStruct',
99     None,
100     [('FIELD', 'int32', 'a', ast.Ordinal(None), None),
101      ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])]
102     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
103
104   def testMissingModuleName(self):
105     """Tests an (invalid) .mojom with a missing module name."""
106     source1 = """\
107 // Missing module name.
108 module {
109 struct MyStruct {
110   int32 a;
111 };
112 }
113 """
114     with self.assertRaisesRegexp(
115         parser.ParseError,
116         r"^my_file\.mojom:2: Error: Unexpected '{':\nmodule {$"):
117       parser.Parse(source1, "my_file.mojom")
118
119     # Another similar case, but make sure that line-number tracking/reporting
120     # is correct.
121     source2 = """\
122 module
123 // This line intentionally left unblank.
124
125 {
126 }
127 """
128     with self.assertRaisesRegexp(
129         parser.ParseError,
130         r"^my_file\.mojom:4: Error: Unexpected '{':\n{$"):
131       parser.Parse(source2, "my_file.mojom")
132
133   def testEnumExpressions(self):
134     """Tests an enum with values calculated using simple expressions."""
135     source = """\
136 module my_module {
137
138 enum MyEnum {
139   MY_ENUM_1 = 1,
140   MY_ENUM_2 = 1 + 1,
141   MY_ENUM_3 = 1 * 3,
142   MY_ENUM_4 = 2 * (1 + 1),
143   MY_ENUM_5 = 1 + 2 * 2,
144   MY_ENUM_6 = -6 / -2,
145   MY_ENUM_7 = 3 | (1 << 2),
146   MY_ENUM_8 = 16 >> 1,
147   MY_ENUM_9 = 1 ^ 15 & 8,
148   MY_ENUM_10 = 110 % 100,
149   MY_ENUM_MINUS_1 = ~0
150 };
151
152 }  // my_module
153 """
154     expected = \
155 [('MODULE',
156   'my_module',
157   [('ENUM',
158     'MyEnum',
159     [('ENUM_FIELD', 'MY_ENUM_1', ('EXPRESSION', ['1'])),
160      ('ENUM_FIELD', 'MY_ENUM_2', ('EXPRESSION', ['1', '+', '1'])),
161      ('ENUM_FIELD', 'MY_ENUM_3', ('EXPRESSION', ['1', '*', '3'])),
162      ('ENUM_FIELD',
163       'MY_ENUM_4',
164       ('EXPRESSION',
165        ['2', '*', '(', ('EXPRESSION', ['1', '+', '1']), ')'])),
166      ('ENUM_FIELD',
167       'MY_ENUM_5',
168       ('EXPRESSION', ['1', '+', '2', '*', '2'])),
169      ('ENUM_FIELD',
170       'MY_ENUM_6',
171       ('EXPRESSION',
172        ['-', ('EXPRESSION', ['6', '/', '-', ('EXPRESSION', ['2'])])])),
173      ('ENUM_FIELD',
174       'MY_ENUM_7',
175       ('EXPRESSION',
176        ['3', '|', '(', ('EXPRESSION', ['1', '<<', '2']), ')'])),
177      ('ENUM_FIELD', 'MY_ENUM_8', ('EXPRESSION', ['16', '>>', '1'])),
178      ('ENUM_FIELD',
179       'MY_ENUM_9',
180       ('EXPRESSION', ['1', '^', '15', '&', '8'])),
181      ('ENUM_FIELD', 'MY_ENUM_10', ('EXPRESSION', ['110', '%', '100'])),
182      ('ENUM_FIELD',
183       'MY_ENUM_MINUS_1',
184       ('EXPRESSION', ['~', ('EXPRESSION', ['0'])]))])])]
185     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
186
187   def testNoConditionals(self):
188     """Tests that ?: is not allowed."""
189     source = """\
190 module my_module {
191
192 enum MyEnum {
193   MY_ENUM_1 = 1 ? 2 : 3
194 };
195
196 }  // my_module
197 """
198     with self.assertRaisesRegexp(
199         lexer.LexError,
200         r"^my_file\.mojom:4: Error: Illegal character '\?'$"):
201       parser.Parse(source, "my_file.mojom")
202
203   def testSimpleOrdinals(self):
204     """Tests that (valid) ordinal values are scanned correctly."""
205     source = """\
206 module my_module {
207
208 // This isn't actually valid .mojom, but the problem (missing ordinals) should
209 // be handled at a different level.
210 struct MyStruct {
211   int32 a0 @0;
212   int32 a1 @1;
213   int32 a2 @2;
214   int32 a9 @9;
215   int32 a10 @10;
216   int32 a11 @11;
217   int32 a29 @29;
218   int32 a1234567890 @1234567890;
219 };
220
221 }  // module my_module
222 """
223     expected = \
224 [('MODULE',
225   'my_module',
226   [('STRUCT',
227     'MyStruct',
228     None,
229     [('FIELD', 'int32', 'a0', ast.Ordinal(0), None),
230      ('FIELD', 'int32', 'a1', ast.Ordinal(1), None),
231      ('FIELD', 'int32', 'a2', ast.Ordinal(2), None),
232      ('FIELD', 'int32', 'a9', ast.Ordinal(9), None),
233      ('FIELD', 'int32', 'a10', ast.Ordinal(10), None),
234      ('FIELD', 'int32', 'a11', ast.Ordinal(11), None),
235      ('FIELD', 'int32', 'a29', ast.Ordinal(29), None),
236      ('FIELD', 'int32', 'a1234567890', ast.Ordinal(1234567890), None)])])]
237     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
238
239   def testInvalidOrdinals(self):
240     """Tests that (lexically) invalid ordinals are correctly detected."""
241     source1 = """\
242 module my_module {
243
244 struct MyStruct {
245   int32 a_missing @;
246 };
247
248 }  // module my_module
249 """
250     with self.assertRaisesRegexp(
251         lexer.LexError,
252         r"^my_file\.mojom:4: Error: Missing ordinal value$"):
253       parser.Parse(source1, "my_file.mojom")
254
255     source2 = """\
256 module my_module {
257
258 struct MyStruct {
259   int32 a_octal @01;
260 };
261
262 }  // module my_module
263 """
264     with self.assertRaisesRegexp(
265         lexer.LexError,
266         r"^my_file\.mojom:4: Error: "
267             r"Octal and hexadecimal ordinal values not allowed$"):
268       parser.Parse(source2, "my_file.mojom")
269
270     source3 = """\
271 module my_module { struct MyStruct { int32 a_invalid_octal @08; }; }
272 """
273     with self.assertRaisesRegexp(
274         lexer.LexError,
275         r"^my_file\.mojom:1: Error: "
276             r"Octal and hexadecimal ordinal values not allowed$"):
277       parser.Parse(source3, "my_file.mojom")
278
279     source4 = """\
280 module my_module { struct MyStruct { int32 a_hex @0x1aB9; }; }
281 """
282     with self.assertRaisesRegexp(
283         lexer.LexError,
284         r"^my_file\.mojom:1: Error: "
285             r"Octal and hexadecimal ordinal values not allowed$"):
286       parser.Parse(source4, "my_file.mojom")
287
288     source5 = """\
289 module my_module { struct MyStruct { int32 a_hex @0X0; }; }
290 """
291     with self.assertRaisesRegexp(
292         lexer.LexError,
293         r"^my_file\.mojom:1: Error: "
294             r"Octal and hexadecimal ordinal values not allowed$"):
295       parser.Parse(source5, "my_file.mojom")
296
297     source6 = """\
298 struct MyStruct {
299   int32 a_too_big @999999999999;
300 };
301 """
302     with self.assertRaisesRegexp(
303         parser.ParseError,
304         r"^my_file\.mojom:2: Error: "
305             r"Ordinal value 999999999999 too large:\n"
306             r"  int32 a_too_big @999999999999;$"):
307       parser.Parse(source6, "my_file.mojom")
308
309   def testNestedNamespace(self):
310     """Tests nested namespaces work."""
311     source = """\
312 module my.mod {
313
314 struct MyStruct {
315   int32 a;
316 };
317
318 }  // module my.mod
319 """
320     expected = \
321 [('MODULE',
322   'my.mod',
323   [('STRUCT',
324     'MyStruct',
325     None,
326     [('FIELD', 'int32', 'a', ast.Ordinal(None), None)])])]
327     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
328
329
330 if __name__ == "__main__":
331   unittest.main()