Upload upstream chromium 94.0.4606.31
[platform/framework/web/chromium-efl.git] / build / gn_helpers_unittest.py
1 # Copyright 2016 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 mock
6 import sys
7 import textwrap
8 import unittest
9
10 import gn_helpers
11
12
13 class UnitTest(unittest.TestCase):
14   def test_ToGNString(self):
15     test_cases = [
16         (42, '42', '42'), ('foo', '"foo"', '"foo"'), (True, 'true', 'true'),
17         (False, 'false', 'false'), ('', '""', '""'),
18         ('\\$"$\\', '"\\\\\\$\\"\\$\\\\"', '"\\\\\\$\\"\\$\\\\"'),
19         (' \t\r\n', '" $0x09$0x0D$0x0A"', '" $0x09$0x0D$0x0A"'),
20         (u'\u2713', '"$0xE2$0x9C$0x93"', '"$0xE2$0x9C$0x93"'),
21         ([], '[  ]', '[]'), ([1], '[ 1 ]', '[\n  1\n]\n'),
22         ([3, 1, 4, 1], '[ 3, 1, 4, 1 ]', '[\n  3,\n  1,\n  4,\n  1\n]\n'),
23         (['a', True, 2], '[ "a", true, 2 ]', '[\n  "a",\n  true,\n  2\n]\n'),
24         ({
25             'single': 'item'
26         }, 'single = "item"\n', 'single = "item"\n'),
27         ({
28             'kEy': 137,
29             '_42A_Zaz_': [False, True]
30         }, '_42A_Zaz_ = [ false, true ]\nkEy = 137\n',
31          '_42A_Zaz_ = [\n  false,\n  true\n]\nkEy = 137\n'),
32         ([1, 'two',
33           ['"thr,.$\\', True, False, [],
34            u'(\u2713)']], '[ 1, "two", [ "\\"thr,.\\$\\\\", true, false, ' +
35          '[  ], "($0xE2$0x9C$0x93)" ] ]', '''[
36   1,
37   "two",
38   [
39     "\\"thr,.\\$\\\\",
40     true,
41     false,
42     [],
43     "($0xE2$0x9C$0x93)"
44   ]
45 ]
46 '''),
47         ({
48             's': 'foo',
49             'n': 42,
50             'b': True,
51             'a': [3, 'x']
52         }, 'a = [ 3, "x" ]\nb = true\nn = 42\ns = "foo"\n',
53          'a = [\n  3,\n  "x"\n]\nb = true\nn = 42\ns = "foo"\n'),
54         (
55             [[[], [[]]], []],
56             '[ [ [  ], [ [  ] ] ], [  ] ]',
57             '[\n  [\n    [],\n    [\n      []\n    ]\n  ],\n  []\n]\n',
58         ),
59         (
60             [{
61                 'a': 1,
62                 'c': {
63                     'z': 8
64                 },
65                 'b': []
66             }],
67             '[ { a = 1\nb = [  ]\nc = { z = 8 } } ]\n',
68             '[\n  {\n    a = 1\n    b = []\n    c = {\n' +
69             '      z = 8\n    }\n  }\n]\n',
70         )
71     ]
72     for obj, exp_ugly, exp_pretty in test_cases:
73       out_ugly = gn_helpers.ToGNString(obj)
74       self.assertEqual(exp_ugly, out_ugly)
75       out_pretty = gn_helpers.ToGNString(obj, pretty=True)
76       self.assertEqual(exp_pretty, out_pretty)
77
78   def test_UnescapeGNString(self):
79     # Backslash followed by a \, $, or " means the folling character without
80     # the special meaning. Backslash followed by everything else is a literal.
81     self.assertEqual(
82         gn_helpers.UnescapeGNString('\\as\\$\\\\asd\\"'),
83         '\\as$\\asd"')
84
85   def test_FromGNString(self):
86     self.assertEqual(
87         gn_helpers.FromGNString('[1, -20, true, false,["as\\"", []]]'),
88         [ 1, -20, True, False, [ 'as"', [] ] ])
89
90     with self.assertRaises(gn_helpers.GNError):
91       parser = gn_helpers.GNValueParser('123 456')
92       parser.Parse()
93
94   def test_ParseBool(self):
95     parser = gn_helpers.GNValueParser('true')
96     self.assertEqual(parser.Parse(), True)
97
98     parser = gn_helpers.GNValueParser('false')
99     self.assertEqual(parser.Parse(), False)
100
101   def test_ParseNumber(self):
102     parser = gn_helpers.GNValueParser('123')
103     self.assertEqual(parser.ParseNumber(), 123)
104
105     with self.assertRaises(gn_helpers.GNError):
106       parser = gn_helpers.GNValueParser('')
107       parser.ParseNumber()
108     with self.assertRaises(gn_helpers.GNError):
109       parser = gn_helpers.GNValueParser('a123')
110       parser.ParseNumber()
111
112   def test_ParseString(self):
113     parser = gn_helpers.GNValueParser('"asdf"')
114     self.assertEqual(parser.ParseString(), 'asdf')
115
116     with self.assertRaises(gn_helpers.GNError):
117       parser = gn_helpers.GNValueParser('')  # Empty.
118       parser.ParseString()
119     with self.assertRaises(gn_helpers.GNError):
120       parser = gn_helpers.GNValueParser('asdf')  # Unquoted.
121       parser.ParseString()
122     with self.assertRaises(gn_helpers.GNError):
123       parser = gn_helpers.GNValueParser('"trailing')  # Unterminated.
124       parser.ParseString()
125
126   def test_ParseList(self):
127     parser = gn_helpers.GNValueParser('[1,]')  # Optional end comma OK.
128     self.assertEqual(parser.ParseList(), [ 1 ])
129
130     with self.assertRaises(gn_helpers.GNError):
131       parser = gn_helpers.GNValueParser('')  # Empty.
132       parser.ParseList()
133     with self.assertRaises(gn_helpers.GNError):
134       parser = gn_helpers.GNValueParser('asdf')  # No [].
135       parser.ParseList()
136     with self.assertRaises(gn_helpers.GNError):
137       parser = gn_helpers.GNValueParser('[1, 2')  # Unterminated
138       parser.ParseList()
139     with self.assertRaises(gn_helpers.GNError):
140       parser = gn_helpers.GNValueParser('[1 2]')  # No separating comma.
141       parser.ParseList()
142
143   def test_ParseScope(self):
144     parser = gn_helpers.GNValueParser('{a = 1}')
145     self.assertEqual(parser.ParseScope(), {'a': 1})
146
147     with self.assertRaises(gn_helpers.GNError):
148       parser = gn_helpers.GNValueParser('')  # Empty.
149       parser.ParseScope()
150     with self.assertRaises(gn_helpers.GNError):
151       parser = gn_helpers.GNValueParser('asdf')  # No {}.
152       parser.ParseScope()
153     with self.assertRaises(gn_helpers.GNError):
154       parser = gn_helpers.GNValueParser('{a = 1')  # Unterminated.
155       parser.ParseScope()
156     with self.assertRaises(gn_helpers.GNError):
157       parser = gn_helpers.GNValueParser('{"a" = 1}')  # Not identifier.
158       parser.ParseScope()
159     with self.assertRaises(gn_helpers.GNError):
160       parser = gn_helpers.GNValueParser('{a = }')  # No value.
161       parser.ParseScope()
162
163   def test_FromGNArgs(self):
164     # Booleans and numbers should work; whitespace is allowed works.
165     self.assertEqual(gn_helpers.FromGNArgs('foo = true\nbar = 1\n'),
166                      {'foo': True, 'bar': 1})
167
168     # Whitespace is not required; strings should also work.
169     self.assertEqual(gn_helpers.FromGNArgs('foo="bar baz"'),
170                      {'foo': 'bar baz'})
171
172     # Comments should work (and be ignored).
173     gn_args_lines = [
174         '# Top-level comment.',
175         'foo = true',
176         'bar = 1  # In-line comment followed by whitespace.',
177         ' ',
178         'baz = false',
179     ]
180     self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
181         'foo': True,
182         'bar': 1,
183         'baz': False
184     })
185
186     # Lists should work.
187     self.assertEqual(gn_helpers.FromGNArgs('foo=[1, 2, 3]'),
188                      {'foo': [1, 2, 3]})
189
190     # Empty strings should return an empty dict.
191     self.assertEqual(gn_helpers.FromGNArgs(''), {})
192     self.assertEqual(gn_helpers.FromGNArgs(' \n '), {})
193
194     # Comments should work everywhere (and be ignored).
195     gn_args_lines = [
196         '# Top-level comment.',
197         '',
198         '# Variable comment.',
199         'foo = true',
200         'bar = [',
201         '    # Value comment in list.',
202         '    1,',
203         '    2,',
204         ']',
205         '',
206         'baz # Comment anywhere, really',
207         '  = # also here',
208         '    4',
209     ]
210     self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
211         'foo': True,
212         'bar': [1, 2],
213         'baz': 4
214     })
215
216     # Scope should be parsed, even empty ones.
217     gn_args_lines = [
218         'foo = {',
219         '  a = 1',
220         '  b = [',
221         '    { },',
222         '    {',
223         '      c = 1',
224         '    },',
225         '  ]',
226         '}',
227     ]
228     self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)),
229                      {'foo': {
230                          'a': 1,
231                          'b': [
232                              {},
233                              {
234                                  'c': 1,
235                              },
236                          ]
237                      }})
238
239     # Non-identifiers should raise an exception.
240     with self.assertRaises(gn_helpers.GNError):
241       gn_helpers.FromGNArgs('123 = true')
242
243     # References to other variables should raise an exception.
244     with self.assertRaises(gn_helpers.GNError):
245       gn_helpers.FromGNArgs('foo = bar')
246
247     # References to functions should raise an exception.
248     with self.assertRaises(gn_helpers.GNError):
249       gn_helpers.FromGNArgs('foo = exec_script("//build/baz.py")')
250
251     # Underscores in identifiers should work.
252     self.assertEqual(gn_helpers.FromGNArgs('_foo = true'),
253                      {'_foo': True})
254     self.assertEqual(gn_helpers.FromGNArgs('foo_bar = true'),
255                      {'foo_bar': True})
256     self.assertEqual(gn_helpers.FromGNArgs('foo_=true'),
257                      {'foo_': True})
258
259   def test_ReplaceImports(self):
260     # Should be a no-op on args inputs without any imports.
261     parser = gn_helpers.GNValueParser(
262         textwrap.dedent("""
263         some_arg1 = "val1"
264         some_arg2 = "val2"
265     """))
266     parser.ReplaceImports()
267     self.assertEqual(
268         parser.input,
269         textwrap.dedent("""
270         some_arg1 = "val1"
271         some_arg2 = "val2"
272     """))
273
274     # A single "import(...)" line should be replaced with the contents of the
275     # file being imported.
276     parser = gn_helpers.GNValueParser(
277         textwrap.dedent("""
278         some_arg1 = "val1"
279         import("//some/args/file.gni")
280         some_arg2 = "val2"
281     """))
282     fake_import = 'some_imported_arg = "imported_val"'
283     builtin_var = '__builtin__' if sys.version_info.major < 3 else 'builtins'
284     open_fun = '{}.open'.format(builtin_var)
285     with mock.patch(open_fun, mock.mock_open(read_data=fake_import)):
286       parser.ReplaceImports()
287     self.assertEqual(
288         parser.input,
289         textwrap.dedent("""
290         some_arg1 = "val1"
291         some_imported_arg = "imported_val"
292         some_arg2 = "val2"
293     """))
294
295     # No trailing parenthesis should raise an exception.
296     with self.assertRaises(gn_helpers.GNError):
297       parser = gn_helpers.GNValueParser(
298           textwrap.dedent('import("//some/args/file.gni"'))
299       parser.ReplaceImports()
300
301     # No double quotes should raise an exception.
302     with self.assertRaises(gn_helpers.GNError):
303       parser = gn_helpers.GNValueParser(
304           textwrap.dedent('import(//some/args/file.gni)'))
305       parser.ReplaceImports()
306
307     # A path that's not source absolute should raise an exception.
308     with self.assertRaises(gn_helpers.GNError):
309       parser = gn_helpers.GNValueParser(
310           textwrap.dedent('import("some/relative/args/file.gni")'))
311       parser.ReplaceImports()
312
313
314 if __name__ == '__main__':
315   unittest.main()