From 7e81a8a8f9650a9df8c879b817941927447d43c3 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Tue, 5 Jun 2012 15:02:45 +0200 Subject: [PATCH] Improve parser readability + add unit tests Change-Id: I7dd8c394e6543d1ee545648af32c9025c522b6e0 Signed-off-by: Zane Bitter --- heat/engine/parser.py | 19 ++++----- heat/tests/test_parser.py | 82 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 heat/tests/test_parser.py diff --git a/heat/engine/parser.py b/heat/engine/parser.py index a31e7cffc0..b37a79ae9a 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -426,19 +426,14 @@ def _resolve(match, handle, snippet): Returns a copy of the original snippet with the substitutions performed. ''' - recurse = lambda k: _resolve(match, handle, snippet[k]) + recurse = lambda s: _resolve(match, handle, s) if isinstance(snippet, dict): - should_handle = lambda k: match(k, snippet[k]) - matches = itertools.imap(recurse, - itertools.ifilter(should_handle, snippet)) - try: - args = next(matches) - except StopIteration: - # No matches - return dict((k, recurse(k)) for k in snippet) - else: - return handle(args) + if len(snippet) == 1: + k, v = snippet.items()[0] + if match(k, v): + return handle(recurse(v)) + return dict((k, recurse(v)) for k, v in snippet.items()) elif isinstance(snippet, list): - return [recurse(i) for i in range(len(snippet))] + return [recurse(v) for v in snippet] return snippet diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py new file mode 100644 index 0000000000..449e8f46cf --- /dev/null +++ b/heat/tests/test_parser.py @@ -0,0 +1,82 @@ +import nose +import unittest +from nose.plugins.attrib import attr + +from heat.engine.parser import _resolve as resolve + + +def join(raw): + def handle_join(args): + delim, strs = args + return delim.join(strs) + + return resolve(lambda k, v: k == 'Fn::Join', handle_join, raw) + + +@attr(tag=['unit', 'parser']) +@attr(speed='fast') +class ParserTest(unittest.TestCase): + + def test_list(self): + raw = ['foo', 'bar', 'baz'] + parsed = join(raw) + for i in xrange(len(raw)): + self.assertEqual(parsed[i], raw[i]) + self.assertTrue(parsed is not raw) + + def test_dict(self): + raw = {'foo': 'bar', 'blarg': 'wibble'} + parsed = join(raw) + for k in raw: + self.assertEqual(parsed[k], raw[k]) + self.assertTrue(parsed is not raw) + + def test_dict_list(self): + raw = {'foo': ['bar', 'baz'], 'blarg': 'wibble'} + parsed = join(raw) + self.assertEqual(parsed['blarg'], raw['blarg']) + for i in xrange(len(raw['foo'])): + self.assertEqual(parsed['foo'][i], raw['foo'][i]) + self.assertTrue(parsed is not raw) + self.assertTrue(parsed['foo'] is not raw['foo']) + + def test_list_dict(self): + raw = [{'foo': 'bar', 'blarg': 'wibble'}, 'baz', 'quux'] + parsed = join(raw) + for i in xrange(1, len(raw)): + self.assertEqual(parsed[i], raw[i]) + for k in raw[0]: + self.assertEqual(parsed[0][k], raw[0][k]) + self.assertTrue(parsed is not raw) + self.assertTrue(parsed[0] is not raw[0]) + + def test_join(self): + raw = {'Fn::Join': [' ', ['foo', 'bar', 'baz']]} + self.assertEqual(join(raw), 'foo bar baz') + + def test_join_list(self): + raw = [{'Fn::Join': [' ', ['foo', 'bar', 'baz']]}, 'blarg', 'wibble'] + parsed = join(raw) + self.assertEqual(parsed[0], 'foo bar baz') + for i in xrange(1, len(raw)): + self.assertEqual(parsed[i], raw[i]) + self.assertTrue(parsed is not raw) + + def test_join_dict_val(self): + raw = {'quux': {'Fn::Join': [' ', ['foo', 'bar', 'baz']]}, + 'blarg': 'wibble'} + parsed = join(raw) + self.assertEqual(parsed['quux'], 'foo bar baz') + self.assertEqual(parsed['blarg'], raw['blarg']) + self.assertTrue(parsed is not raw) + + def test_join_recursive(self): + raw = {'Fn::Join': ['\n', [{'Fn::Join': [' ', ['foo', 'bar']]}, + 'baz']]} + self.assertEqual(join(raw), 'foo bar\nbaz') + + +# allows testing of the test directly, shown below +if __name__ == '__main__': + sys.argv.append(__file__) + nose.main()