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