Upstream version 8.37.180.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, 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, 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 testCommentLineNumbers(self):
65     """Tests that line numbers are correctly tracked when comments are
66     present."""
67     source1 = """\
68 // Isolated C++-style comments.
69
70 // Foo.
71 asdf1
72 """
73     with self.assertRaisesRegexp(
74         parser.ParseError,
75         r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\nasdf1$"):
76       parser.Parse(source1, "my_file.mojom")
77
78     source2 = """\
79 // Consecutive C++-style comments.
80 // Foo.
81   // Bar.
82
83 struct Yada {  // Baz.
84 // Quux.
85   int32 x;
86 };
87
88 asdf2
89 """
90     with self.assertRaisesRegexp(
91         parser.ParseError,
92         r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\nasdf2$"):
93       parser.Parse(source2, "my_file.mojom")
94
95     source3 = """\
96 /* Single-line C-style comments. */
97 /* Foobar. */
98
99 /* Baz. */
100 asdf3
101 """
102     with self.assertRaisesRegexp(
103         parser.ParseError,
104         r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\nasdf3$"):
105       parser.Parse(source3, "my_file.mojom")
106
107     source4 = """\
108 /* Multi-line C-style comments.
109 */
110 /*
111 Foo.
112 Bar.
113 */
114
115 /* Baz
116    Quux. */
117 asdf4
118 """
119     with self.assertRaisesRegexp(
120         parser.ParseError,
121         r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\nasdf4$"):
122       parser.Parse(source4, "my_file.mojom")
123
124
125   def testSimpleStruct(self):
126     """Tests a simple .mojom source that just defines a struct."""
127     source = """\
128 module my_module {
129
130 struct MyStruct {
131   int32 a;
132   double b;
133 };
134
135 }  // module my_module
136 """
137     expected = \
138 [('MODULE',
139   'my_module',
140   None,
141   [('STRUCT',
142     'MyStruct',
143     None,
144     [('FIELD', 'int32', 'a', ast.Ordinal(None), None),
145      ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])]
146     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
147
148   def testSimpleStructWithoutModule(self):
149     """Tests a simple struct without an enclosing module."""
150     source = """\
151 struct MyStruct {
152   int32 a;
153   double b;
154 };
155 """
156     expected = \
157 [('MODULE',
158   '',
159   None,
160   [('STRUCT',
161     'MyStruct',
162     None,
163     [('FIELD', 'int32', 'a', ast.Ordinal(None), None),
164      ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])]
165     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
166
167   def testMissingModuleName(self):
168     """Tests an (invalid) .mojom with a missing module name."""
169     source1 = """\
170 // Missing module name.
171 module {
172 struct MyStruct {
173   int32 a;
174 };
175 }
176 """
177     with self.assertRaisesRegexp(
178         parser.ParseError,
179         r"^my_file\.mojom:2: Error: Unexpected '{':\nmodule {$"):
180       parser.Parse(source1, "my_file.mojom")
181
182     # Another similar case, but make sure that line-number tracking/reporting
183     # is correct.
184     source2 = """\
185 module
186 // This line intentionally left unblank.
187
188 {
189 }
190 """
191     with self.assertRaisesRegexp(
192         parser.ParseError,
193         r"^my_file\.mojom:4: Error: Unexpected '{':\n{$"):
194       parser.Parse(source2, "my_file.mojom")
195
196   def testEnumInitializers(self):
197     """Tests an enum with simple initialized values."""
198     source = """\
199 module my_module {
200
201 enum MyEnum {
202   MY_ENUM_NEG1 = -1,
203   MY_ENUM_ZERO = 0,
204   MY_ENUM_1 = +1,
205   MY_ENUM_2,
206 };
207
208 }  // my_module
209 """
210     expected = \
211 [('MODULE',
212   'my_module',
213   None,
214   [('ENUM',
215     'MyEnum',
216     [('ENUM_FIELD', 'MY_ENUM_NEG1', '-1'),
217      ('ENUM_FIELD', 'MY_ENUM_ZERO', '0'),
218      ('ENUM_FIELD', 'MY_ENUM_1', '+1'),
219      ('ENUM_FIELD', 'MY_ENUM_2', None)])])]
220     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
221
222   def testConst(self):
223     """Tests some constants and struct memebers initialized with them."""
224     source = """\
225 module my_module {
226
227 struct MyStruct {
228   const int8 kNumber = -1;
229   int8 number@0 = kNumber;
230 };
231
232 }  // my_module
233 """
234     expected = \
235 [('MODULE',
236   'my_module',
237   None,
238   [('STRUCT',
239     'MyStruct', None,
240     [('CONST', 'int8', 'kNumber', '-1'),
241      ('FIELD', 'int8', 'number',
242         ast.Ordinal(0), ('IDENTIFIER', 'kNumber'))])])]
243     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
244
245   def testNoConditionals(self):
246     """Tests that ?: is not allowed."""
247     source = """\
248 module my_module {
249
250 enum MyEnum {
251   MY_ENUM_1 = 1 ? 2 : 3
252 };
253
254 }  // my_module
255 """
256     with self.assertRaisesRegexp(
257         lexer.LexError,
258         r"^my_file\.mojom:4: Error: Illegal character '\?'$"):
259       parser.Parse(source, "my_file.mojom")
260
261   def testSimpleOrdinals(self):
262     """Tests that (valid) ordinal values are scanned correctly."""
263     source = """\
264 module my_module {
265
266 // This isn't actually valid .mojom, but the problem (missing ordinals) should
267 // be handled at a different level.
268 struct MyStruct {
269   int32 a0@0;
270   int32 a1@1;
271   int32 a2@2;
272   int32 a9@9;
273   int32 a10 @10;
274   int32 a11 @11;
275   int32 a29 @29;
276   int32 a1234567890 @1234567890;
277 };
278
279 }  // module my_module
280 """
281     expected = \
282 [('MODULE',
283   'my_module',
284   None,
285   [('STRUCT',
286     'MyStruct',
287     None,
288     [('FIELD', 'int32', 'a0', ast.Ordinal(0), None),
289      ('FIELD', 'int32', 'a1', ast.Ordinal(1), None),
290      ('FIELD', 'int32', 'a2', ast.Ordinal(2), None),
291      ('FIELD', 'int32', 'a9', ast.Ordinal(9), None),
292      ('FIELD', 'int32', 'a10', ast.Ordinal(10), None),
293      ('FIELD', 'int32', 'a11', ast.Ordinal(11), None),
294      ('FIELD', 'int32', 'a29', ast.Ordinal(29), None),
295      ('FIELD', 'int32', 'a1234567890', ast.Ordinal(1234567890), None)])])]
296     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
297
298   def testInvalidOrdinals(self):
299     """Tests that (lexically) invalid ordinals are correctly detected."""
300     source1 = """\
301 module my_module {
302
303 struct MyStruct {
304   int32 a_missing@;
305 };
306
307 }  // module my_module
308 """
309     with self.assertRaisesRegexp(
310         lexer.LexError,
311         r"^my_file\.mojom:4: Error: Missing ordinal value$"):
312       parser.Parse(source1, "my_file.mojom")
313
314     source2 = """\
315 module my_module {
316
317 struct MyStruct {
318   int32 a_octal@01;
319 };
320
321 }  // module my_module
322 """
323     with self.assertRaisesRegexp(
324         lexer.LexError,
325         r"^my_file\.mojom:4: Error: "
326             r"Octal and hexadecimal ordinal values not allowed$"):
327       parser.Parse(source2, "my_file.mojom")
328
329     source3 = """\
330 module my_module { struct MyStruct { int32 a_invalid_octal@08; }; }
331 """
332     with self.assertRaisesRegexp(
333         lexer.LexError,
334         r"^my_file\.mojom:1: Error: "
335             r"Octal and hexadecimal ordinal values not allowed$"):
336       parser.Parse(source3, "my_file.mojom")
337
338     source4 = """\
339 module my_module { struct MyStruct { int32 a_hex@0x1aB9; }; }
340 """
341     with self.assertRaisesRegexp(
342         lexer.LexError,
343         r"^my_file\.mojom:1: Error: "
344             r"Octal and hexadecimal ordinal values not allowed$"):
345       parser.Parse(source4, "my_file.mojom")
346
347     source5 = """\
348 module my_module { struct MyStruct { int32 a_hex@0X0; }; }
349 """
350     with self.assertRaisesRegexp(
351         lexer.LexError,
352         r"^my_file\.mojom:1: Error: "
353             r"Octal and hexadecimal ordinal values not allowed$"):
354       parser.Parse(source5, "my_file.mojom")
355
356     source6 = """\
357 struct MyStruct {
358   int32 a_too_big@999999999999;
359 };
360 """
361     with self.assertRaisesRegexp(
362         parser.ParseError,
363         r"^my_file\.mojom:2: Error: "
364             r"Ordinal value 999999999999 too large:\n"
365             r"  int32 a_too_big@999999999999;$"):
366       parser.Parse(source6, "my_file.mojom")
367
368   def testNestedNamespace(self):
369     """Tests that "nested" namespaces work."""
370     source = """\
371 module my.mod {
372
373 struct MyStruct {
374   int32 a;
375 };
376
377 }  // module my.mod
378 """
379     expected = \
380 [('MODULE',
381   'my.mod',
382   None,
383   [('STRUCT',
384     'MyStruct',
385     None,
386     [('FIELD', 'int32', 'a', ast.Ordinal(None), None)])])]
387     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
388
389   def testValidHandleTypes(self):
390     """Tests (valid) handle types."""
391     source = """\
392 struct MyStruct {
393   handle a;
394   handle<data_pipe_consumer> b;
395   handle <data_pipe_producer> c;
396   handle < message_pipe > d;
397   handle
398     < shared_buffer
399     > e;
400 };
401 """
402     expected = \
403 [('MODULE',
404   '',
405   None,
406   [('STRUCT',
407     'MyStruct',
408     None,
409     [('FIELD', 'handle', 'a', ast.Ordinal(None), None),
410      ('FIELD', 'handle<data_pipe_consumer>', 'b', ast.Ordinal(None), None),
411      ('FIELD', 'handle<data_pipe_producer>', 'c', ast.Ordinal(None), None),
412      ('FIELD', 'handle<message_pipe>', 'd', ast.Ordinal(None), None),
413      ('FIELD', 'handle<shared_buffer>', 'e', ast.Ordinal(None), None)])])]
414     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
415
416   def testInvalidHandleType(self):
417     """Tests an invalid (unknown) handle type."""
418     source = """\
419 struct MyStruct {
420   handle<wtf_is_this> foo;
421 };
422 """
423     with self.assertRaisesRegexp(
424         parser.ParseError,
425         r"^my_file\.mojom:2: Error: "
426             r"Invalid handle type 'wtf_is_this':\n"
427             r"  handle<wtf_is_this> foo;$"):
428       parser.Parse(source, "my_file.mojom")
429
430   def testValidDefaultValues(self):
431     """Tests default values that are valid (to the parser)."""
432     source = """\
433 struct MyStruct {
434   int16 a0 = 0;
435   uint16 a1 = 0x0;
436   uint16 a2 = 0x00;
437   uint16 a3 = 0x01;
438   uint16 a4 = 0xcd;
439   int32 a5 = 12345;
440   int64 a6 = -12345;
441   int64 a7 = +12345;
442   uint32 a8 = 0x12cd3;
443   uint32 a9 = -0x12cD3;
444   uint32 a10 = +0x12CD3;
445   bool a11 = true;
446   bool a12 = false;
447   float a13 = 1.2345;
448   float a14 = -1.2345;
449   float a15 = +1.2345;
450   float a16 = 123.;
451   float a17 = .123;
452   double a18 = 1.23E10;
453   double a19 = 1.E-10;
454   double a20 = .5E+10;
455   double a21 = -1.23E10;
456   double a22 = +.123E10;
457 };
458 """
459     expected = \
460 [('MODULE',
461   '',
462   None,
463   [('STRUCT',
464     'MyStruct',
465     None,
466     [('FIELD', 'int16', 'a0', ast.Ordinal(None), '0'),
467      ('FIELD', 'uint16', 'a1', ast.Ordinal(None), '0x0'),
468      ('FIELD', 'uint16', 'a2', ast.Ordinal(None), '0x00'),
469      ('FIELD', 'uint16', 'a3', ast.Ordinal(None), '0x01'),
470      ('FIELD', 'uint16', 'a4', ast.Ordinal(None), '0xcd'),
471      ('FIELD', 'int32', 'a5' , ast.Ordinal(None), '12345'),
472      ('FIELD', 'int64', 'a6', ast.Ordinal(None), '-12345'),
473      ('FIELD', 'int64', 'a7', ast.Ordinal(None), '+12345'),
474      ('FIELD', 'uint32', 'a8', ast.Ordinal(None), '0x12cd3'),
475      ('FIELD', 'uint32', 'a9', ast.Ordinal(None), '-0x12cD3'),
476      ('FIELD', 'uint32', 'a10', ast.Ordinal(None), '+0x12CD3'),
477      ('FIELD', 'bool', 'a11', ast.Ordinal(None), 'true'),
478      ('FIELD', 'bool', 'a12', ast.Ordinal(None), 'false'),
479      ('FIELD', 'float', 'a13', ast.Ordinal(None), '1.2345'),
480      ('FIELD', 'float', 'a14', ast.Ordinal(None), '-1.2345'),
481      ('FIELD', 'float', 'a15', ast.Ordinal(None), '+1.2345'),
482      ('FIELD', 'float', 'a16', ast.Ordinal(None), '123.'),
483      ('FIELD', 'float', 'a17', ast.Ordinal(None), '.123'),
484      ('FIELD', 'double', 'a18', ast.Ordinal(None), '1.23E10'),
485      ('FIELD', 'double', 'a19', ast.Ordinal(None), '1.E-10'),
486      ('FIELD', 'double', 'a20', ast.Ordinal(None), '.5E+10'),
487      ('FIELD', 'double', 'a21', ast.Ordinal(None), '-1.23E10'),
488      ('FIELD', 'double', 'a22', ast.Ordinal(None), '+.123E10')])])]
489     self.assertEquals(parser.Parse(source, "my_file.mojom"), expected)
490
491
492 if __name__ == "__main__":
493   unittest.main()