import subprocess
import unittest
-EXAMPLES_PATH = os.path.join(os.path.dirname(__file__), 'examples')
+# Go to the directory of the current file so we know where we are in the filesystem
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
class OutputTests(unittest.TestCase):
pass
compile_fur_to_c_result = subprocess.call([
'python',
'main.py',
- os.path.join(EXAMPLES_PATH, filename),
+ os.path.join('examples', filename),
])
if compile_fur_to_c_result != 0:
compile_c_to_executable_result = subprocess.call([
'gcc',
- os.path.join(EXAMPLES_PATH, filename + '.c'),
+ os.path.join('examples', filename + '.c'),
])
if compile_c_to_executable_result != 0:
raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
- actual_output = subprocess.check_output(['./a.out'])
+ try:
+ p = subprocess.Popen('./a.out', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ actual_stdout, actual_stderr = p.communicate()
- with open(os.path.join(EXAMPLES_PATH, filename + '.output.txt'), 'rb') as f:
- expected_output = f.read()
+ expected_stdout_path = os.path.join('examples', filename + '.stdout.txt')
- self.assertEqual(expected_output, actual_output)
+ if os.path.isfile(expected_stdout_path):
+ with open(expected_stdout_path, 'rb') as f:
+ expected_stdout = f.read()
+ else:
+ expected_stdout = b''
+
+ expected_stderr_path = os.path.join('examples', filename + '.stderr.txt')
+
+ if os.path.isfile(expected_stderr_path):
+ with open(expected_stderr_path, 'rb') as f:
+ expected_stderr = f.read()
+ else:
+ expected_stderr = b''
+
+ self.assertEqual(expected_stderr, actual_stderr)
+
+ # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
+ os.remove(os.path.join('examples', filename + '.c'))
+
+ finally:
+ try:
+ os.remove('a.out')
+ except OSError:
+ pass
setattr(OutputTests, 'test_' + filename, test)
+class MemoryLeakTests(unittest.TestCase):
+ pass
+
+def add_example_memory_leak_test(filename):
+ def test(self):
+ compile_fur_to_c_result = subprocess.call([
+ 'python',
+ 'main.py',
+ os.path.join('examples', filename),
+ ])
+
+ if compile_fur_to_c_result != 0:
+ raise Exception('Example "{}" did not compile'.format(filename))
+
+ compile_c_to_executable_result = subprocess.call([
+ 'gcc',
+ '-ggdb3',
+ os.path.join('examples', filename + '.c'),
+ ])
+
+ if compile_c_to_executable_result != 0:
+ raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
+
+ try:
+ with open(os.devnull, 'w') as devnull:
+ expected_return = 0
+ actual_return = subprocess.call(
+ [
+ 'valgrind',
+ '--tool=memcheck',
+ '--leak-check=yes',
+ '--show-reachable=yes',
+ '--num-callers=20',
+ '--track-fds=yes',
+ '--error-exitcode=42',
+ '-q',
+ './a.out',
+ ],
+ stdout=devnull,
+ stderr=devnull,
+ )
+
+ self.assertEqual(expected_return, actual_return)
+
+ # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
+ os.remove(os.path.join('examples', filename + '.c'))
+
+ finally:
+ try:
+ os.remove('a.out')
+ except OSError:
+ pass
+
+ setattr(MemoryLeakTests, 'test_' + filename, test)
+
filenames = (
entry.name
- for entry in os.scandir(EXAMPLES_PATH)
+ for entry in os.scandir('examples')
if entry.is_file()
if entry.name.endswith('.fur')
)
for filename in filenames:
add_example_output_test(filename)
+ add_example_memory_leak_test(filename)
unittest.main()