summaryrefslogtreecommitdiff
path: root/test/convert.py
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-01-28 20:49:26 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-01-28 20:49:26 -0400
commite851c02d2747be0acc336bc278da9e0460b75738 (patch)
treedf813c5c572922cf05a6317b7eb1d6062dedac05 /test/convert.py
parent3020f0f8513d8cef04d4a291dc9b5fa50e1b832c (diff)
downloadfork-ledger-e851c02d2747be0acc336bc278da9e0460b75738.tar.gz
fork-ledger-e851c02d2747be0acc336bc278da9e0460b75738.tar.bz2
fork-ledger-e851c02d2747be0acc336bc278da9e0460b75738.zip
Unit test for Python are now auto-generated from the C++ tests.
Diffstat (limited to 'test/convert.py')
-rwxr-xr-xtest/convert.py174
1 files changed, 174 insertions, 0 deletions
diff --git a/test/convert.py b/test/convert.py
new file mode 100755
index 00000000..54118720
--- /dev/null
+++ b/test/convert.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+
+# convert.py: This script converts a C++ Ledger unit test into an equivalent
+# Python unit test.
+#
+# Copyright (c) 2003-2009, John Wiegley. All rights reserved.
+#
+# 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 New Artisans LLC 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.
+
+import re
+import sys
+import os
+
+source = os.path.abspath(sys.argv[1])
+base = os.path.splitext(source)[0]
+target = os.path.abspath(sys.argv[2])
+
+dirname = os.path.dirname(target)
+if not os.path.isdir(dirname):
+ os.makedirs(dirname)
+
+fd = open(source, "r")
+fo = open(target, "w")
+
+fo.write('''# -*- coding: utf-8 -*-
+
+import unittest
+import exceptions
+import operator
+
+from ledger import *
+from StringIO import *
+from datetime import *
+
+internalAmount = Amount.exact
+
+class %sTestCase(unittest.TestCase):
+ testSession = None
+
+ def assertValid(self, amt):
+ self.assertTrue(amt.valid())''' % os.path.basename(base))
+
+not_for_python = 0
+
+for line in fd.readlines():
+ if re.match('^#ifndef NOT_FOR_PYTHON', line):
+ not_for_python += 1
+ continue
+ elif not_for_python > 0:
+ if re.match('^#endif // NOT_FOR_PYTHON', line):
+ not_for_python -= 1
+ continue
+
+ if re.match('^(using|CPP|[#{}/])', line):
+ continue
+ if re.match('^\s+[{}]\s+$', line):
+ continue
+
+ if not re.search('assert', line):
+ match = re.match('void [^:]+::(test[^(]+|setUp|tearDown)\(\)', line)
+ if match:
+ fo.write(' def %s(self):\n' % match.group(1))
+ continue
+
+ match = re.search(' ([a-z:_<>]+?)&?\s+([a-z0-9_]+)(\((.+?)\))?;', line)
+ if match:
+ if match.group(1) != "std::string":
+ line = ' %s = %s(%s)\n' % (match.group(2), match.group(1),
+ match.group(4) or "")
+ else:
+ line = ''
+
+ match = re.search(' ([a-z:_<>]+?)&?\s+([a-z0-9]+)\s*=\s*([^(]+);', line)
+ if match:
+ line = ' %s = %s(%s)\n' % (match.group(2), match.group(1),
+ match.group(3))
+
+ match = re.search(' ([a-z:_<>]+?)\s+([a-z0-9]+)\s*=\s*(.+?)$', line)
+ if match:
+ line = ' %s = %s\n' % (match.group(2), match.group(3))
+
+ line = re.sub('CPPUNIT_ASSERT', 'self.assertTrue', line)
+ line = re.sub('assertValid', 'self.assertValid', line)
+ line = re.sub('assertTrue', 'self.assertTrue', line)
+ line = re.sub('assertFalse', 'self.assertFalse', line)
+ line = re.sub('assertNotEqual', 'self.assertNotEqual', line)
+ line = re.sub('assertEqual', 'self.assertEqual', line)
+ line = re.sub('assertThrow\(([^,]+), ([^,)]+?)\)',
+ 'self.assertRaises(\\2, lambda: \\1)', line)
+ #line = re.sub('optional<([^>]+?)>', '\\1', line)
+ line = re.sub('amount_t::precision_t\(([^)]+?)\)', '\\1', line)
+
+ # Determine this list automatically by scanning the class_ lines in
+ # python/*.cc
+ line = re.sub('amount_t::', 'Amount.', line)
+ line = re.sub('commodity_t\(([^)]+?)\)', '\\1', line)
+ line = re.sub('commodity_t::', 'Commodity.', line)
+ line = re.sub('balance_t::', 'Balance.', line)
+ line = re.sub('balance_pair_t::', 'BalancePair.', line)
+ line = re.sub('value_t::', 'Value.', line)
+
+ line = re.sub('amount_t', 'Amount', line)
+ line = re.sub('commodity_t', 'Commodity', line)
+ line = re.sub('balance_t', 'Balance', line)
+ line = re.sub('balance_pair_t', 'BalancePair', line)
+ line = re.sub('value_t', 'Value', line)
+
+ line = re.sub('ledger::', '', line)
+ line = re.sub('std::istringstream', 'StringIO', line)
+ line = re.sub('std::ostringstream', 'StringIO', line)
+ line = re.sub('set_session_context\(&session\)',
+ 'self.testSession = session()\n set_session_context(self.testSession)', line)
+ line = re.sub('set_session_context\(\)',
+ 'set_session_context()\n self.testSession = None', line)
+ line = re.sub('([a-z_]+?)_t\b', '\\1', line)
+ line = re.sub('std::string\(([^)]+?)\)', '\\1', line)
+ line = re.sub('string\(([^)]+?)\)', '\\1', line)
+ line = re.sub('\.print\(([^)]+?)\)', '.print_(\\1)', line)
+ line = re.sub('true', 'True', line)
+ line = re.sub('false', 'False', line)
+ line = re.sub('([0-9]+)[FL]', '\\1', line)
+ line = re.sub('([0-9]+)UL', '\\1L', line)
+ line = re.sub(';', '', line)
+ line = re.sub('//', '#', line)
+ line = re.sub('->', '.', line)
+ line = re.sub('(\s+|\()(\S+?) \? (.+?) : (.+?)\)',
+ '\\1\\3 if \\2 else \\4)', line)
+ line = re.sub('if \((.+?)\)( {)?$', 'if \\1:', line)
+ line = re.sub('(} )?else( {)?$', 'else:', line)
+
+ line = re.sub('amount_error', 'exceptions.ArithmeticError', line)
+
+ match = re.match('^ ', line)
+ if match:
+ fo.write(' ' + line)
+ else:
+ fo.write(line)
+
+fo.write('''
+
+def suite():
+ return unittest.TestLoader().loadTestsFromTestCase(%sTestCase)
+
+if __name__ == '__main__':
+ unittest.main()
+''' % os.path.basename(base))
+
+fo.close()
+fd.close()