brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 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 | |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 5 | import mock |
| 6 | import textwrap |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 7 | import unittest |
| 8 | |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 9 | import gn_helpers |
| 10 | |
| 11 | |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 12 | class UnitTest(unittest.TestCase): |
| 13 | def test_ToGNString(self): |
| 14 | self.assertEqual( |
| 15 | gn_helpers.ToGNString([1, 'two', [ '"thr$\\', True, False, [] ]]), |
| 16 | '[ 1, "two", [ "\\"thr\\$\\\\", true, false, [ ] ] ]') |
| 17 | |
| 18 | def test_UnescapeGNString(self): |
| 19 | # Backslash followed by a \, $, or " means the folling character without |
| 20 | # the special meaning. Backslash followed by everything else is a literal. |
| 21 | self.assertEqual( |
| 22 | gn_helpers.UnescapeGNString('\\as\\$\\\\asd\\"'), |
| 23 | '\\as$\\asd"') |
| 24 | |
| 25 | def test_FromGNString(self): |
| 26 | self.assertEqual( |
| 27 | gn_helpers.FromGNString('[1, -20, true, false,["as\\"", []]]'), |
| 28 | [ 1, -20, True, False, [ 'as"', [] ] ]) |
| 29 | |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 30 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 31 | parser = gn_helpers.GNValueParser('123 456') |
| 32 | parser.Parse() |
| 33 | |
dpranke | e031ec2 | 2016-04-02 00:17:34 | [diff] [blame] | 34 | def test_ParseBool(self): |
| 35 | parser = gn_helpers.GNValueParser('true') |
| 36 | self.assertEqual(parser.Parse(), True) |
| 37 | |
| 38 | parser = gn_helpers.GNValueParser('false') |
| 39 | self.assertEqual(parser.Parse(), False) |
| 40 | |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 41 | def test_ParseNumber(self): |
| 42 | parser = gn_helpers.GNValueParser('123') |
| 43 | self.assertEqual(parser.ParseNumber(), 123) |
| 44 | |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 45 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 46 | parser = gn_helpers.GNValueParser('') |
| 47 | parser.ParseNumber() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 48 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 49 | parser = gn_helpers.GNValueParser('a123') |
| 50 | parser.ParseNumber() |
| 51 | |
| 52 | def test_ParseString(self): |
| 53 | parser = gn_helpers.GNValueParser('"asdf"') |
| 54 | self.assertEqual(parser.ParseString(), 'asdf') |
| 55 | |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 56 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 57 | parser = gn_helpers.GNValueParser('') # Empty. |
| 58 | parser.ParseString() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 59 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 60 | parser = gn_helpers.GNValueParser('asdf') # Unquoted. |
| 61 | parser.ParseString() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 62 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 63 | parser = gn_helpers.GNValueParser('"trailing') # Unterminated. |
| 64 | parser.ParseString() |
| 65 | |
| 66 | def test_ParseList(self): |
| 67 | parser = gn_helpers.GNValueParser('[1,]') # Optional end comma OK. |
| 68 | self.assertEqual(parser.ParseList(), [ 1 ]) |
| 69 | |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 70 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 71 | parser = gn_helpers.GNValueParser('') # Empty. |
| 72 | parser.ParseList() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 73 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 74 | parser = gn_helpers.GNValueParser('asdf') # No []. |
| 75 | parser.ParseList() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 76 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 77 | parser = gn_helpers.GNValueParser('[1, 2') # Unterminated |
| 78 | parser.ParseList() |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 79 | with self.assertRaises(gn_helpers.GNError): |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 80 | parser = gn_helpers.GNValueParser('[1 2]') # No separating comma. |
| 81 | parser.ParseList() |
| 82 | |
dpranke | 65d84dc0 | 2016-04-06 00:07:18 | [diff] [blame] | 83 | def test_FromGNArgs(self): |
| 84 | # Booleans and numbers should work; whitespace is allowed works. |
| 85 | self.assertEqual(gn_helpers.FromGNArgs('foo = true\nbar = 1\n'), |
| 86 | {'foo': True, 'bar': 1}) |
| 87 | |
| 88 | # Whitespace is not required; strings should also work. |
| 89 | self.assertEqual(gn_helpers.FromGNArgs('foo="bar baz"'), |
| 90 | {'foo': 'bar baz'}) |
| 91 | |
Ben Pastene | 9b24d85 | 2018-11-06 00:42:09 | [diff] [blame] | 92 | # Comments should work (and be ignored). |
| 93 | gn_args_lines = [ |
| 94 | '# Top-level comment.', |
| 95 | 'foo = true', |
Ben Pastene | b75f8ec | 2020-06-04 22:09:28 | [diff] [blame^] | 96 | 'bar = 1 # In-line comment followed by whitespace.', |
| 97 | ' ', |
| 98 | 'baz = false', |
Ben Pastene | 9b24d85 | 2018-11-06 00:42:09 | [diff] [blame] | 99 | ] |
Ben Pastene | b75f8ec | 2020-06-04 22:09:28 | [diff] [blame^] | 100 | self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), { |
| 101 | 'foo': True, |
| 102 | 'bar': 1, |
| 103 | 'baz': False |
| 104 | }) |
Ben Pastene | 9b24d85 | 2018-11-06 00:42:09 | [diff] [blame] | 105 | |
dpranke | 65d84dc0 | 2016-04-06 00:07:18 | [diff] [blame] | 106 | # Lists should work. |
| 107 | self.assertEqual(gn_helpers.FromGNArgs('foo=[1, 2, 3]'), |
| 108 | {'foo': [1, 2, 3]}) |
| 109 | |
| 110 | # Empty strings should return an empty dict. |
| 111 | self.assertEqual(gn_helpers.FromGNArgs(''), {}) |
| 112 | self.assertEqual(gn_helpers.FromGNArgs(' \n '), {}) |
| 113 | |
| 114 | # Non-identifiers should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 115 | with self.assertRaises(gn_helpers.GNError): |
dpranke | 65d84dc0 | 2016-04-06 00:07:18 | [diff] [blame] | 116 | gn_helpers.FromGNArgs('123 = true') |
| 117 | |
| 118 | # References to other variables should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 119 | with self.assertRaises(gn_helpers.GNError): |
dpranke | 65d84dc0 | 2016-04-06 00:07:18 | [diff] [blame] | 120 | gn_helpers.FromGNArgs('foo = bar') |
| 121 | |
| 122 | # References to functions should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 123 | with self.assertRaises(gn_helpers.GNError): |
dpranke | 65d84dc0 | 2016-04-06 00:07:18 | [diff] [blame] | 124 | gn_helpers.FromGNArgs('foo = exec_script("//build/baz.py")') |
| 125 | |
| 126 | # Underscores in identifiers should work. |
| 127 | self.assertEqual(gn_helpers.FromGNArgs('_foo = true'), |
| 128 | {'_foo': True}) |
| 129 | self.assertEqual(gn_helpers.FromGNArgs('foo_bar = true'), |
| 130 | {'foo_bar': True}) |
| 131 | self.assertEqual(gn_helpers.FromGNArgs('foo_=true'), |
| 132 | {'foo_': True}) |
| 133 | |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 134 | def test_ReplaceImports(self): |
| 135 | # Should be a no-op on args inputs without any imports. |
| 136 | parser = gn_helpers.GNValueParser( |
| 137 | textwrap.dedent(""" |
| 138 | some_arg1 = "val1" |
| 139 | some_arg2 = "val2" |
| 140 | """)) |
| 141 | parser.ReplaceImports() |
| 142 | self.assertEquals( |
| 143 | parser.input, |
| 144 | textwrap.dedent(""" |
| 145 | some_arg1 = "val1" |
| 146 | some_arg2 = "val2" |
| 147 | """)) |
| 148 | |
| 149 | # A single "import(...)" line should be replaced with the contents of the |
| 150 | # file being imported. |
| 151 | parser = gn_helpers.GNValueParser( |
| 152 | textwrap.dedent(""" |
| 153 | some_arg1 = "val1" |
| 154 | import("//some/args/file.gni") |
| 155 | some_arg2 = "val2" |
| 156 | """)) |
| 157 | fake_import = 'some_imported_arg = "imported_val"' |
| 158 | with mock.patch('__builtin__.open', mock.mock_open(read_data=fake_import)): |
| 159 | parser.ReplaceImports() |
| 160 | self.assertEquals( |
| 161 | parser.input, |
| 162 | textwrap.dedent(""" |
| 163 | some_arg1 = "val1" |
| 164 | some_imported_arg = "imported_val" |
| 165 | some_arg2 = "val2" |
| 166 | """)) |
| 167 | |
| 168 | # No trailing parenthesis should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 169 | with self.assertRaises(gn_helpers.GNError): |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 170 | parser = gn_helpers.GNValueParser( |
| 171 | textwrap.dedent('import("//some/args/file.gni"')) |
| 172 | parser.ReplaceImports() |
| 173 | |
| 174 | # No double quotes should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 175 | with self.assertRaises(gn_helpers.GNError): |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 176 | parser = gn_helpers.GNValueParser( |
| 177 | textwrap.dedent('import(//some/args/file.gni)')) |
| 178 | parser.ReplaceImports() |
| 179 | |
| 180 | # A path that's not source absolute should raise an exception. |
Samuel Huang | 1ea5180e | 2020-05-25 16:29:40 | [diff] [blame] | 181 | with self.assertRaises(gn_helpers.GNError): |
Ben Pastene | 00156a2 | 2020-03-23 18:13:10 | [diff] [blame] | 182 | parser = gn_helpers.GNValueParser( |
| 183 | textwrap.dedent('import("some/relative/args/file.gni")')) |
| 184 | parser.ReplaceImports() |
| 185 | |
| 186 | |
brettw | 9dffb54 | 2016-01-22 18:40:03 | [diff] [blame] | 187 | if __name__ == '__main__': |
| 188 | unittest.main() |