diff options
Diffstat (limited to 'objectivec/DevTools/pddm_tests.py')
-rwxr-xr-x | objectivec/DevTools/pddm_tests.py | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/objectivec/DevTools/pddm_tests.py b/objectivec/DevTools/pddm_tests.py new file mode 100755 index 00000000..8a73b842 --- /dev/null +++ b/objectivec/DevTools/pddm_tests.py @@ -0,0 +1,515 @@ +#! /usr/bin/python +# +# Protocol Buffers - Google's data interchange format +# Copyright 2015 Google Inc. All rights reserved. +# https://developers.google.com/protocol-buffers/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests for pddm.py.""" + +import io +import unittest + +import pddm + + +class TestParsingMacros(unittest.TestCase): + + def testParseEmpty(self): + f = io.StringIO(u'') + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 0) + + def testParseOne(self): + f = io.StringIO(u"""PDDM-DEFINE foo( ) +body""") + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 1) + macro = result._macros.get('foo') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'foo') + self.assertEquals(macro.args, tuple()) + self.assertEquals(macro.body, 'body') + + def testParseGeneral(self): + # Tests multiple defines, spaces in all places, etc. + f = io.StringIO(u""" +PDDM-DEFINE noArgs( ) +body1 +body2 + +PDDM-DEFINE-END + +PDDM-DEFINE oneArg(foo) +body3 +PDDM-DEFINE twoArgs( bar_ , baz ) +body4 +body5""") + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 3) + macro = result._macros.get('noArgs') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'noArgs') + self.assertEquals(macro.args, tuple()) + self.assertEquals(macro.body, 'body1\nbody2\n') + macro = result._macros.get('oneArg') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'oneArg') + self.assertEquals(macro.args, ('foo',)) + self.assertEquals(macro.body, 'body3') + macro = result._macros.get('twoArgs') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'twoArgs') + self.assertEquals(macro.args, ('bar_', 'baz')) + self.assertEquals(macro.body, 'body4\nbody5') + # Add into existing collection + f = io.StringIO(u""" +PDDM-DEFINE another(a,b,c) +body1 +body2""") + result.ParseInput(f) + self.assertEqual(len(result._macros), 4) + macro = result._macros.get('another') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'another') + self.assertEquals(macro.args, ('a', 'b', 'c')) + self.assertEquals(macro.body, 'body1\nbody2') + + def testParseDirectiveIssues(self): + test_list = [ + # Unknown directive + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINED foo\nbaz', + 'Hit a line with an unknown directive: '), + # End without begin + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nPDDM-DEFINE-END\n', + 'Got DEFINE-END directive without an active macro: '), + # Line not in macro block + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nmumble\n', + 'Hit a line that wasn\'t a directive and no open macro definition: '), + # Redefine macro + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE foo(a)\nmumble\n', + 'Attempt to redefine macro: '), + ] + for idx, (input_str, expected_prefix) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + result = pddm.MacroCollection(f) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertTrue(e.message.startswith(expected_prefix), + 'Entry %d failed: %r' % (idx, e)) + + def testParseBeginIssues(self): + test_list = [ + # 1. No name + (u'PDDM-DEFINE\nmumble', + 'Failed to parse macro definition: '), + # 2. No name (with spaces) + (u'PDDM-DEFINE \nmumble', + 'Failed to parse macro definition: '), + # 3. No open paren + (u'PDDM-DEFINE foo\nmumble', + 'Failed to parse macro definition: '), + # 4. No close paren + (u'PDDM-DEFINE foo(\nmumble', + 'Failed to parse macro definition: '), + # 5. No close paren (with args) + (u'PDDM-DEFINE foo(a, b\nmumble', + 'Failed to parse macro definition: '), + # 6. No name before args + (u'PDDM-DEFINE (a, b)\nmumble', + 'Failed to parse macro definition: '), + # 7. No name before args + (u'PDDM-DEFINE foo bar(a, b)\nmumble', + 'Failed to parse macro definition: '), + # 8. Empty arg name + (u'PDDM-DEFINE foo(a, ,b)\nmumble', + 'Empty arg name in macro definition: '), + (u'PDDM-DEFINE foo(a,,b)\nmumble', + 'Empty arg name in macro definition: '), + # 10. Duplicate name + (u'PDDM-DEFINE foo(a,b,a,c)\nmumble', + 'Arg name "a" used more than once in macro definition: '), + # 11. Invalid arg name + (u'PDDM-DEFINE foo(a b,c)\nmumble', + 'Invalid arg name "a b" in macro definition: '), + (u'PDDM-DEFINE foo(a.b,c)\nmumble', + 'Invalid arg name "a.b" in macro definition: '), + (u'PDDM-DEFINE foo(a-b,c)\nmumble', + 'Invalid arg name "a-b" in macro definition: '), + (u'PDDM-DEFINE foo(a,b,c.)\nmumble', + 'Invalid arg name "c." in macro definition: '), + # 15. Extra stuff after the name + (u'PDDM-DEFINE foo(a,c) foo\nmumble', + 'Failed to parse macro definition: '), + (u'PDDM-DEFINE foo(a,c) foo)\nmumble', + 'Failed to parse macro definition: '), + ] + for idx, (input_str, expected_prefix) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + result = pddm.MacroCollection(f) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertTrue(e.message.startswith(expected_prefix), + 'Entry %d failed: %r' % (idx, e)) + + +class TestExpandingMacros(unittest.TestCase): + + def testExpandBasics(self): + f = io.StringIO(u""" +PDDM-DEFINE noArgs( ) +body1 +body2 + +PDDM-DEFINE-END + +PDDM-DEFINE oneArg(a) +body3 a + +PDDM-DEFINE-END + +PDDM-DEFINE twoArgs(b,c) +body4 b c +body5 +PDDM-DEFINE-END + +""") + mc = pddm.MacroCollection(f) + test_list = [ + (u'noArgs()', + 'body1\nbody2\n'), + (u'oneArg(wee)', + 'body3 wee\n'), + (u'twoArgs(having some, fun)', + 'body4 having some fun\nbody5'), + # One arg, pass empty. + (u'oneArg()', + 'body3 \n'), + # Two args, gets empty in each slot. + (u'twoArgs(, empty)', + 'body4 empty\nbody5'), + (u'twoArgs(empty, )', + 'body4 empty \nbody5'), + (u'twoArgs(, )', + 'body4 \nbody5'), + ] + for idx, (input_str, expected) in enumerate(test_list, 1): + result = mc.Expand(input_str) + self.assertEqual(result, expected, + 'Entry %d --\n Result: %r\n Expected: %r' % + (idx, result, expected)) + + def testExpandArgOptions(self): + f = io.StringIO(u""" +PDDM-DEFINE bar(a) +a-a$S-a$l-a$L-a$u-a$U +PDDM-DEFINE-END +""") + mc = pddm.MacroCollection(f) + + self.assertEqual(mc.Expand('bar(xYz)'), 'xYz- -xYz-xyz-XYz-XYZ') + self.assertEqual(mc.Expand('bar(MnoP)'), 'MnoP- -mnoP-mnop-MnoP-MNOP') + # Test empty + self.assertEqual(mc.Expand('bar()'), '-----') + + def testExpandSimpleMacroErrors(self): + f = io.StringIO(u""" +PDDM-DEFINE foo(a, b) +<a-z> +PDDM-DEFINE baz(a) +a - a$z +""") + mc = pddm.MacroCollection(f) + test_list = [ + # 1. Unknown macro + (u'bar()', + 'No macro named "bar".'), + (u'bar(a)', + 'No macro named "bar".'), + # 3. Arg mismatch + (u'foo()', + 'Expected 2 args, got: "foo()".'), + (u'foo(a b)', + 'Expected 2 args, got: "foo(a b)".'), + (u'foo(a,b,c)', + 'Expected 2 args, got: "foo(a,b,c)".'), + # 6. Unknown option in expansion + (u'baz(mumble)', + 'Unknown arg option "a$z" while expanding "baz(mumble)".'), + ] + for idx, (input_str, expected_err) in enumerate(test_list, 1): + try: + result = mc.Expand(input_str) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, expected_err, + 'Entry %d failed: %r' % (idx, e)) + + def testExpandReferences(self): + f = io.StringIO(u""" +PDDM-DEFINE StartIt() +foo(abc, def) +foo(ghi, jkl) +PDDM-DEFINE foo(a, b) +bar(a, int) +bar(b, NSString *) +PDDM-DEFINE bar(n, t) +- (t)n; +- (void)set##n$u##:(t)value; + +""") + mc = pddm.MacroCollection(f) + expected = """- (int)abc; +- (void)setAbc:(int)value; + +- (NSString *)def; +- (void)setDef:(NSString *)value; + +- (int)ghi; +- (void)setGhi:(int)value; + +- (NSString *)jkl; +- (void)setJkl:(NSString *)value; +""" + self.assertEqual(mc.Expand('StartIt()'), expected) + + def testCatchRecursion(self): + f = io.StringIO(u""" +PDDM-DEFINE foo(a, b) +bar(1, a) +bar(2, b) +PDDM-DEFINE bar(x, y) +foo(x, y) +""") + mc = pddm.MacroCollection(f) + try: + result = mc.Expand('foo(A,B)') + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'Found macro recusion, invoking "foo(1, A)":\n...while expanding "bar(1, A)".\n...while expanding "foo(A,B)".') + + +class TestParsingSource(unittest.TestCase): + + def testBasicParse(self): + test_list = [ + # 1. no directives + (u'a\nb\nc', + (3,) ), + # 2. One define + (u'a\n//%PDDM-DEFINE foo()\n//%body\nc', + (1, 2, 1) ), + # 3. Two defines + (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE bar()\n//%body2\nc', + (1, 4, 1) ), + # 4. Two defines with ends + (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE-END\n' + u'//%PDDM-DEFINE bar()\n//%body2\n//%PDDM-DEFINE-END\nc', + (1, 6, 1) ), + # 5. One expand, one define (that runs to end of file) + (u'a\n//%PDDM-EXPAND foo()\nbody\n//%PDDM-EXPAND-END\n' + u'//%PDDM-DEFINE bar()\n//%body2\n', + (1, 1, 2) ), + # 6. One define ended with an expand. + (u'a\nb\n//%PDDM-DEFINE bar()\n//%body2\n' + u'//%PDDM-EXPAND bar()\nbody2\n//%PDDM-EXPAND-END\n', + (2, 2, 1) ), + # 7. Two expands (one end), one define. + (u'a\n//%PDDM-EXPAND foo(1)\nbody\n//%PDDM-EXPAND foo(2)\nbody2\n//%PDDM-EXPAND-END\n' + u'//%PDDM-DEFINE foo()\n//%body2\n', + (1, 2, 2) ), + ] + for idx, (input_str, line_counts) in enumerate(test_list, 1): + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + sf._ParseFile() + self.assertEqual(len(sf._sections), len(line_counts), + 'Entry %d -- %d != %d' % + (idx, len(sf._sections), len(line_counts))) + for idx2, (sec, expected) in enumerate(zip(sf._sections, line_counts), 1): + self.assertEqual(sec.num_lines_captured, expected, + 'Entry %d, section %d -- %d != %d' % + (idx, idx2, sec.num_lines_captured, expected)) + + def testErrors(self): + test_list = [ + # 1. Directive within expansion + (u'//%PDDM-EXPAND a()\n//%PDDM-BOGUS', + 'Ran into directive ("//%PDDM-BOGUS", line 2) while in "//%PDDM-EXPAND a()".'), + (u'//%PDDM-EXPAND a()\n//%PDDM-DEFINE a()\n//%body\n', + 'Ran into directive ("//%PDDM-DEFINE", line 2) while in "//%PDDM-EXPAND a()".'), + # 3. Expansion ran off end of file + (u'//%PDDM-EXPAND a()\na\nb\n', + 'Hit the end of the file while in "//%PDDM-EXPAND a()".'), + # 4. Directive within define + (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-BOGUS', + 'Ran into directive ("//%PDDM-BOGUS", line 3) while in "//%PDDM-DEFINE a()".'), + (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-EXPAND-END a()', + 'Ran into directive ("//%PDDM-EXPAND-END", line 3) while in "//%PDDM-DEFINE a()".'), + # 6. Directives that shouldn't start sections + (u'a\n//%PDDM-DEFINE-END a()\n//a\n', + 'Unexpected line 2: "//%PDDM-DEFINE-END a()".'), + (u'a\n//%PDDM-EXPAND-END a()\n//a\n', + 'Unexpected line 2: "//%PDDM-EXPAND-END a()".'), + (u'//%PDDM-BOGUS\n//a\n', + 'Unexpected line 1: "//%PDDM-BOGUS".'), + ] + for idx, (input_str, expected_err) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + pddm.SourceFile(f)._ParseFile() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, expected_err, + 'Entry %d failed: %r' % (idx, e)) + +class TestProcessingSource(unittest.TestCase): + + def testBasics(self): + input_str = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +//%PDDM-EXPAND-END +bar +//%PDDM-EXPAND mumble(def) +//%PDDM-EXPAND mumble(ghi) +//%PDDM-EXPAND-END +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + input_str2 = u""" +//%PDDM-DEFINE getName(x_) +//%do##x_$u##(int x_); + +""" + expected = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +// This block of code is generated, do not edit it directly. + +abc: doAbc(int abc); +//%PDDM-EXPAND-END mumble(abc) +bar +//%PDDM-EXPAND mumble(def) +// This block of code is generated, do not edit it directly. + +def: doDef(int def); +//%PDDM-EXPAND mumble(ghi) +// This block of code is generated, do not edit it directly. + +ghi: doGhi(int ghi); +//%PDDM-EXPAND-END (2 expansions) +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + expected_stripped = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +//%PDDM-EXPAND-END mumble(abc) +bar +//%PDDM-EXPAND mumble(def) +//%PDDM-EXPAND mumble(ghi) +//%PDDM-EXPAND-END (2 expansions) +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + def _Resolver(name): + self.assertEqual(name, 'ImportFile') + return io.StringIO(input_str2) + f = io.StringIO(input_str) + sf = pddm.SourceFile(f, _Resolver) + sf.ProcessContent() + self.assertEqual(sf.processed_content, expected) + # Feed it through and nothing should change. + f2 = io.StringIO(sf.processed_content) + sf2 = pddm.SourceFile(f2, _Resolver) + sf2.ProcessContent() + self.assertEqual(sf2.processed_content, expected) + self.assertEqual(sf2.processed_content, sf.processed_content) + # Test stripping (with the original input and expanded version). + f2 = io.StringIO(input_str) + sf2 = pddm.SourceFile(f2) + sf2.ProcessContent(strip_expansion=True) + self.assertEqual(sf2.processed_content, expected_stripped) + f2 = io.StringIO(sf.processed_content) + sf2 = pddm.SourceFile(f2, _Resolver) + sf2.ProcessContent(strip_expansion=True) + self.assertEqual(sf2.processed_content, expected_stripped) + + def testProcessFileWithMacroParseError(self): + input_str = u""" +foo +//%PDDM-DEFINE mumble(a_) +//%body +//%PDDM-DEFINE mumble(x_) +//%body2 + +""" + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + try: + sf.ProcessContent() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'Attempt to redefine macro: "PDDM-DEFINE mumble(x_)"\n' + '...while parsing section that started:\n' + ' Line 3: //%PDDM-DEFINE mumble(a_)') + + def testProcessFileWithExpandError(self): + input_str = u""" +foo +//%PDDM-DEFINE mumble(a_) +//%body +//%PDDM-EXPAND foobar(x_) +//%PDDM-EXPAND-END + +""" + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + try: + sf.ProcessContent() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'No macro named "foobar".\n' + '...while expanding "foobar(x_)" from the section that' + ' started:\n Line 5: //%PDDM-EXPAND foobar(x_)') + + +if __name__ == '__main__': + unittest.main() |