blob: 5886577ea2b26e63682de9e68f7897a8cf1a0d17 [file] [log] [blame]
brettw9dffb542016-01-22 18:40:031# 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
Ben Pastene00156a22020-03-23 18:13:105import mock
Samuel Huang007ab8b82020-06-05 21:44:346import sys
Ben Pastene00156a22020-03-23 18:13:107import textwrap
brettw9dffb542016-01-22 18:40:038import unittest
9
Ben Pastene00156a22020-03-23 18:13:1010import gn_helpers
11
12
brettw9dffb542016-01-22 18:40:0313class UnitTest(unittest.TestCase):
14 def test_ToGNString(self):
Samuel Huang007ab8b82020-06-05 21:44:3415 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 for obj, exp_ugly, exp_pretty in test_cases:
61 out_ugly = gn_helpers.ToGNString(obj)
62 self.assertEqual(exp_ugly, out_ugly)
63 out_pretty = gn_helpers.ToGNString(obj, pretty=True)
64 self.assertEqual(exp_pretty, out_pretty)
brettw9dffb542016-01-22 18:40:0365
66 def test_UnescapeGNString(self):
67 # Backslash followed by a \, $, or " means the folling character without
68 # the special meaning. Backslash followed by everything else is a literal.
69 self.assertEqual(
70 gn_helpers.UnescapeGNString('\\as\\$\\\\asd\\"'),
71 '\\as$\\asd"')
72
73 def test_FromGNString(self):
74 self.assertEqual(
75 gn_helpers.FromGNString('[1, -20, true, false,["as\\"", []]]'),
76 [ 1, -20, True, False, [ 'as"', [] ] ])
77
Samuel Huang1ea5180e2020-05-25 16:29:4078 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:0379 parser = gn_helpers.GNValueParser('123 456')
80 parser.Parse()
81
dprankee031ec22016-04-02 00:17:3482 def test_ParseBool(self):
83 parser = gn_helpers.GNValueParser('true')
84 self.assertEqual(parser.Parse(), True)
85
86 parser = gn_helpers.GNValueParser('false')
87 self.assertEqual(parser.Parse(), False)
88
brettw9dffb542016-01-22 18:40:0389 def test_ParseNumber(self):
90 parser = gn_helpers.GNValueParser('123')
91 self.assertEqual(parser.ParseNumber(), 123)
92
Samuel Huang1ea5180e2020-05-25 16:29:4093 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:0394 parser = gn_helpers.GNValueParser('')
95 parser.ParseNumber()
Samuel Huang1ea5180e2020-05-25 16:29:4096 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:0397 parser = gn_helpers.GNValueParser('a123')
98 parser.ParseNumber()
99
100 def test_ParseString(self):
101 parser = gn_helpers.GNValueParser('"asdf"')
102 self.assertEqual(parser.ParseString(), 'asdf')
103
Samuel Huang1ea5180e2020-05-25 16:29:40104 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03105 parser = gn_helpers.GNValueParser('') # Empty.
106 parser.ParseString()
Samuel Huang1ea5180e2020-05-25 16:29:40107 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03108 parser = gn_helpers.GNValueParser('asdf') # Unquoted.
109 parser.ParseString()
Samuel Huang1ea5180e2020-05-25 16:29:40110 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03111 parser = gn_helpers.GNValueParser('"trailing') # Unterminated.
112 parser.ParseString()
113
114 def test_ParseList(self):
115 parser = gn_helpers.GNValueParser('[1,]') # Optional end comma OK.
116 self.assertEqual(parser.ParseList(), [ 1 ])
117
Samuel Huang1ea5180e2020-05-25 16:29:40118 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03119 parser = gn_helpers.GNValueParser('') # Empty.
120 parser.ParseList()
Samuel Huang1ea5180e2020-05-25 16:29:40121 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03122 parser = gn_helpers.GNValueParser('asdf') # No [].
123 parser.ParseList()
Samuel Huang1ea5180e2020-05-25 16:29:40124 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03125 parser = gn_helpers.GNValueParser('[1, 2') # Unterminated
126 parser.ParseList()
Samuel Huang1ea5180e2020-05-25 16:29:40127 with self.assertRaises(gn_helpers.GNError):
brettw9dffb542016-01-22 18:40:03128 parser = gn_helpers.GNValueParser('[1 2]') # No separating comma.
129 parser.ParseList()
130
dpranke65d84dc02016-04-06 00:07:18131 def test_FromGNArgs(self):
132 # Booleans and numbers should work; whitespace is allowed works.
133 self.assertEqual(gn_helpers.FromGNArgs('foo = true\nbar = 1\n'),
134 {'foo': True, 'bar': 1})
135
136 # Whitespace is not required; strings should also work.
137 self.assertEqual(gn_helpers.FromGNArgs('foo="bar baz"'),
138 {'foo': 'bar baz'})
139
Ben Pastene9b24d852018-11-06 00:42:09140 # Comments should work (and be ignored).
141 gn_args_lines = [
142 '# Top-level comment.',
143 'foo = true',
Ben Pasteneb75f8ec2020-06-04 22:09:28144 'bar = 1 # In-line comment followed by whitespace.',
145 ' ',
146 'baz = false',
Ben Pastene9b24d852018-11-06 00:42:09147 ]
Ben Pasteneb75f8ec2020-06-04 22:09:28148 self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
149 'foo': True,
150 'bar': 1,
151 'baz': False
152 })
Ben Pastene9b24d852018-11-06 00:42:09153
dpranke65d84dc02016-04-06 00:07:18154 # Lists should work.
155 self.assertEqual(gn_helpers.FromGNArgs('foo=[1, 2, 3]'),
156 {'foo': [1, 2, 3]})
157
158 # Empty strings should return an empty dict.
159 self.assertEqual(gn_helpers.FromGNArgs(''), {})
160 self.assertEqual(gn_helpers.FromGNArgs(' \n '), {})
161
162 # Non-identifiers should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40163 with self.assertRaises(gn_helpers.GNError):
dpranke65d84dc02016-04-06 00:07:18164 gn_helpers.FromGNArgs('123 = true')
165
166 # References to other variables should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40167 with self.assertRaises(gn_helpers.GNError):
dpranke65d84dc02016-04-06 00:07:18168 gn_helpers.FromGNArgs('foo = bar')
169
170 # References to functions should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40171 with self.assertRaises(gn_helpers.GNError):
dpranke65d84dc02016-04-06 00:07:18172 gn_helpers.FromGNArgs('foo = exec_script("//build/baz.py")')
173
174 # Underscores in identifiers should work.
175 self.assertEqual(gn_helpers.FromGNArgs('_foo = true'),
176 {'_foo': True})
177 self.assertEqual(gn_helpers.FromGNArgs('foo_bar = true'),
178 {'foo_bar': True})
179 self.assertEqual(gn_helpers.FromGNArgs('foo_=true'),
180 {'foo_': True})
181
Ben Pastene00156a22020-03-23 18:13:10182 def test_ReplaceImports(self):
183 # Should be a no-op on args inputs without any imports.
184 parser = gn_helpers.GNValueParser(
185 textwrap.dedent("""
186 some_arg1 = "val1"
187 some_arg2 = "val2"
188 """))
189 parser.ReplaceImports()
Samuel Huang007ab8b82020-06-05 21:44:34190 self.assertEqual(
Ben Pastene00156a22020-03-23 18:13:10191 parser.input,
192 textwrap.dedent("""
193 some_arg1 = "val1"
194 some_arg2 = "val2"
195 """))
196
197 # A single "import(...)" line should be replaced with the contents of the
198 # file being imported.
199 parser = gn_helpers.GNValueParser(
200 textwrap.dedent("""
201 some_arg1 = "val1"
202 import("//some/args/file.gni")
203 some_arg2 = "val2"
204 """))
205 fake_import = 'some_imported_arg = "imported_val"'
Samuel Huang007ab8b82020-06-05 21:44:34206 builtin_var = '__builtin__' if sys.version_info.major < 3 else 'builtins'
207 open_fun = '{}.open'.format(builtin_var)
208 with mock.patch(open_fun, mock.mock_open(read_data=fake_import)):
Ben Pastene00156a22020-03-23 18:13:10209 parser.ReplaceImports()
Samuel Huang007ab8b82020-06-05 21:44:34210 self.assertEqual(
Ben Pastene00156a22020-03-23 18:13:10211 parser.input,
212 textwrap.dedent("""
213 some_arg1 = "val1"
214 some_imported_arg = "imported_val"
215 some_arg2 = "val2"
216 """))
217
218 # No trailing parenthesis should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40219 with self.assertRaises(gn_helpers.GNError):
Ben Pastene00156a22020-03-23 18:13:10220 parser = gn_helpers.GNValueParser(
221 textwrap.dedent('import("//some/args/file.gni"'))
222 parser.ReplaceImports()
223
224 # No double quotes should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40225 with self.assertRaises(gn_helpers.GNError):
Ben Pastene00156a22020-03-23 18:13:10226 parser = gn_helpers.GNValueParser(
227 textwrap.dedent('import(//some/args/file.gni)'))
228 parser.ReplaceImports()
229
230 # A path that's not source absolute should raise an exception.
Samuel Huang1ea5180e2020-05-25 16:29:40231 with self.assertRaises(gn_helpers.GNError):
Ben Pastene00156a22020-03-23 18:13:10232 parser = gn_helpers.GNValueParser(
233 textwrap.dedent('import("some/relative/args/file.gni")'))
234 parser.ReplaceImports()
235
236
brettw9dffb542016-01-22 18:40:03237if __name__ == '__main__':
238 unittest.main()