123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- # Copyright 2016 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- import mock
- import sys
- import textwrap
- import unittest
- import gn_helpers
- class UnitTest(unittest.TestCase):
- def test_ToGNString(self):
- test_cases = [
- (42, '42', '42'), ('foo', '"foo"', '"foo"'), (True, 'true', 'true'),
- (False, 'false', 'false'), ('', '""', '""'),
- ('\\$"$\\', '"\\\\\\$\\"\\$\\\\"', '"\\\\\\$\\"\\$\\\\"'),
- (' \t\r\n', '" $0x09$0x0D$0x0A"', '" $0x09$0x0D$0x0A"'),
- (u'\u2713', '"$0xE2$0x9C$0x93"', '"$0xE2$0x9C$0x93"'),
- ([], '[ ]', '[]'), ([1], '[ 1 ]', '[\n 1\n]\n'),
- ([3, 1, 4, 1], '[ 3, 1, 4, 1 ]', '[\n 3,\n 1,\n 4,\n 1\n]\n'),
- (['a', True, 2], '[ "a", true, 2 ]', '[\n "a",\n true,\n 2\n]\n'),
- ({
- 'single': 'item'
- }, 'single = "item"\n', 'single = "item"\n'),
- ({
- 'kEy': 137,
- '_42A_Zaz_': [False, True]
- }, '_42A_Zaz_ = [ false, true ]\nkEy = 137\n',
- '_42A_Zaz_ = [\n false,\n true\n]\nkEy = 137\n'),
- ([1, 'two',
- ['"thr,.$\\', True, False, [],
- u'(\u2713)']], '[ 1, "two", [ "\\"thr,.\\$\\\\", true, false, ' +
- '[ ], "($0xE2$0x9C$0x93)" ] ]', '''[
- 1,
- "two",
- [
- "\\"thr,.\\$\\\\",
- true,
- false,
- [],
- "($0xE2$0x9C$0x93)"
- ]
- ]
- '''),
- ({
- 's': 'foo',
- 'n': 42,
- 'b': True,
- 'a': [3, 'x']
- }, 'a = [ 3, "x" ]\nb = true\nn = 42\ns = "foo"\n',
- 'a = [\n 3,\n "x"\n]\nb = true\nn = 42\ns = "foo"\n'),
- (
- [[[], [[]]], []],
- '[ [ [ ], [ [ ] ] ], [ ] ]',
- '[\n [\n [],\n [\n []\n ]\n ],\n []\n]\n',
- ),
- (
- [{
- 'a': 1,
- 'c': {
- 'z': 8
- },
- 'b': []
- }],
- '[ { a = 1\nb = [ ]\nc = { z = 8 } } ]\n',
- '[\n {\n a = 1\n b = []\n c = {\n' +
- ' z = 8\n }\n }\n]\n',
- )
- ]
- for obj, exp_ugly, exp_pretty in test_cases:
- out_ugly = gn_helpers.ToGNString(obj)
- self.assertEqual(exp_ugly, out_ugly)
- out_pretty = gn_helpers.ToGNString(obj, pretty=True)
- self.assertEqual(exp_pretty, out_pretty)
- def test_UnescapeGNString(self):
- # Backslash followed by a \, $, or " means the folling character without
- # the special meaning. Backslash followed by everything else is a literal.
- self.assertEqual(
- gn_helpers.UnescapeGNString('\\as\\$\\\\asd\\"'),
- '\\as$\\asd"')
- def test_FromGNString(self):
- self.assertEqual(
- gn_helpers.FromGNString('[1, -20, true, false,["as\\"", []]]'),
- [ 1, -20, True, False, [ 'as"', [] ] ])
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('123 456')
- parser.Parse()
- def test_ParseBool(self):
- parser = gn_helpers.GNValueParser('true')
- self.assertEqual(parser.Parse(), True)
- parser = gn_helpers.GNValueParser('false')
- self.assertEqual(parser.Parse(), False)
- def test_ParseNumber(self):
- parser = gn_helpers.GNValueParser('123')
- self.assertEqual(parser.ParseNumber(), 123)
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('')
- parser.ParseNumber()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('a123')
- parser.ParseNumber()
- def test_ParseString(self):
- parser = gn_helpers.GNValueParser('"asdf"')
- self.assertEqual(parser.ParseString(), 'asdf')
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('') # Empty.
- parser.ParseString()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('asdf') # Unquoted.
- parser.ParseString()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('"trailing') # Unterminated.
- parser.ParseString()
- def test_ParseList(self):
- parser = gn_helpers.GNValueParser('[1,]') # Optional end comma OK.
- self.assertEqual(parser.ParseList(), [ 1 ])
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('') # Empty.
- parser.ParseList()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('asdf') # No [].
- parser.ParseList()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('[1, 2') # Unterminated
- parser.ParseList()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('[1 2]') # No separating comma.
- parser.ParseList()
- def test_ParseScope(self):
- parser = gn_helpers.GNValueParser('{a = 1}')
- self.assertEqual(parser.ParseScope(), {'a': 1})
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('') # Empty.
- parser.ParseScope()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('asdf') # No {}.
- parser.ParseScope()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('{a = 1') # Unterminated.
- parser.ParseScope()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('{"a" = 1}') # Not identifier.
- parser.ParseScope()
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser('{a = }') # No value.
- parser.ParseScope()
- def test_FromGNArgs(self):
- # Booleans and numbers should work; whitespace is allowed works.
- self.assertEqual(gn_helpers.FromGNArgs('foo = true\nbar = 1\n'),
- {'foo': True, 'bar': 1})
- # Whitespace is not required; strings should also work.
- self.assertEqual(gn_helpers.FromGNArgs('foo="bar baz"'),
- {'foo': 'bar baz'})
- # Comments should work (and be ignored).
- gn_args_lines = [
- '# Top-level comment.',
- 'foo = true',
- 'bar = 1 # In-line comment followed by whitespace.',
- ' ',
- 'baz = false',
- ]
- self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
- 'foo': True,
- 'bar': 1,
- 'baz': False
- })
- # Lists should work.
- self.assertEqual(gn_helpers.FromGNArgs('foo=[1, 2, 3]'),
- {'foo': [1, 2, 3]})
- # Empty strings should return an empty dict.
- self.assertEqual(gn_helpers.FromGNArgs(''), {})
- self.assertEqual(gn_helpers.FromGNArgs(' \n '), {})
- # Comments should work everywhere (and be ignored).
- gn_args_lines = [
- '# Top-level comment.',
- '',
- '# Variable comment.',
- 'foo = true',
- 'bar = [',
- ' # Value comment in list.',
- ' 1,',
- ' 2,',
- ']',
- '',
- 'baz # Comment anywhere, really',
- ' = # also here',
- ' 4',
- ]
- self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
- 'foo': True,
- 'bar': [1, 2],
- 'baz': 4
- })
- # Scope should be parsed, even empty ones.
- gn_args_lines = [
- 'foo = {',
- ' a = 1',
- ' b = [',
- ' { },',
- ' {',
- ' c = 1',
- ' },',
- ' ]',
- '}',
- ]
- self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)),
- {'foo': {
- 'a': 1,
- 'b': [
- {},
- {
- 'c': 1,
- },
- ]
- }})
- # Non-identifiers should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- gn_helpers.FromGNArgs('123 = true')
- # References to other variables should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- gn_helpers.FromGNArgs('foo = bar')
- # References to functions should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- gn_helpers.FromGNArgs('foo = exec_script("//build/baz.py")')
- # Underscores in identifiers should work.
- self.assertEqual(gn_helpers.FromGNArgs('_foo = true'),
- {'_foo': True})
- self.assertEqual(gn_helpers.FromGNArgs('foo_bar = true'),
- {'foo_bar': True})
- self.assertEqual(gn_helpers.FromGNArgs('foo_=true'),
- {'foo_': True})
- def test_ReplaceImports(self):
- # Should be a no-op on args inputs without any imports.
- parser = gn_helpers.GNValueParser(
- textwrap.dedent("""
- some_arg1 = "val1"
- some_arg2 = "val2"
- """))
- parser.ReplaceImports()
- self.assertEqual(
- parser.input,
- textwrap.dedent("""
- some_arg1 = "val1"
- some_arg2 = "val2"
- """))
- # A single "import(...)" line should be replaced with the contents of the
- # file being imported.
- parser = gn_helpers.GNValueParser(
- textwrap.dedent("""
- some_arg1 = "val1"
- import("//some/args/file.gni")
- some_arg2 = "val2"
- """))
- fake_import = 'some_imported_arg = "imported_val"'
- builtin_var = '__builtin__' if sys.version_info.major < 3 else 'builtins'
- open_fun = '{}.open'.format(builtin_var)
- with mock.patch(open_fun, mock.mock_open(read_data=fake_import)):
- parser.ReplaceImports()
- self.assertEqual(
- parser.input,
- textwrap.dedent("""
- some_arg1 = "val1"
- some_imported_arg = "imported_val"
- some_arg2 = "val2"
- """))
- # No trailing parenthesis should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser(
- textwrap.dedent('import("//some/args/file.gni"'))
- parser.ReplaceImports()
- # No double quotes should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser(
- textwrap.dedent('import(//some/args/file.gni)'))
- parser.ReplaceImports()
- # A path that's not source absolute should raise an exception.
- with self.assertRaises(gn_helpers.GNError):
- parser = gn_helpers.GNValueParser(
- textwrap.dedent('import("some/relative/args/file.gni")'))
- parser.ReplaceImports()
- if __name__ == '__main__':
- unittest.main()
|