b5ad3219492c6013561d4c1c2dc7880cffff129a
[fur] / integration_tests.py
1 import os
2 import os.path
3 import subprocess
4 import unittest
5
6 # Go to the directory of the current file so we know where we are in the filesystem
7 os.chdir(os.path.dirname(os.path.abspath(__file__)))
8
9 class InterpreterOutputTests(unittest.TestCase):
10     pass
11
12 def add_example_interpreter_output_test(filename):
13     def test(self):
14         try:
15             p = subprocess.Popen(
16                 'python main.py interpret {}'.format(
17                     os.path.join('examples', filename),
18                 ),
19                 stdout=subprocess.PIPE,
20                 stderr=subprocess.PIPE,
21             )
22
23             actual_stdout, actual_stderr = p.communicate()
24
25             expected_stdout_path = os.path.join('examples', filename + '.stdout.txt')
26
27             if os.path.isfile(expected_stdout_path):
28                 with open(expected_stdout_path, 'rb') as f:
29                     expected_stdout = f.read()
30             else:
31                 expected_stdout = b''
32
33             expected_stderr_path = os.path.join('examples', filename + '.stderr.txt')
34
35             if os.path.isfile(expected_stderr_path):
36                 with open(expected_stderr_path, 'rb') as f:
37                     expected_stderr = f.read()
38             else:
39                 expected_stderr = b''
40
41             self.assertEqual(expected_stderr, actual_stderr)
42
43             # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
44             os.remove(os.path.join('examples', filename + '.c'))
45
46         finally:
47             try:
48                 os.remove('a.out')
49             except OSError:
50                 pass
51
52     setattr(InterpreterOutputTests, 'test_' + filename, test)
53
54 class CompilerOutputTests(unittest.TestCase):
55     pass
56
57 def add_example_compiler_output_test(filename):
58     def test(self):
59         compile_fur_to_c_result = subprocess.call([
60             'python',
61             'main.py',
62             'compile',
63             os.path.join('examples', filename),
64         ])
65
66         if compile_fur_to_c_result != 0:
67             raise Exception('Example "{}" did not compile'.format(filename))
68
69         compile_c_to_executable_result = subprocess.call([
70             'gcc',
71             os.path.join('examples', filename + '.c'),
72         ])
73
74         if compile_c_to_executable_result != 0:
75             raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
76
77         try:
78             p = subprocess.Popen('./a.out', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
79             actual_stdout, actual_stderr = p.communicate()
80
81             expected_stdout_path = os.path.join('examples', filename + '.stdout.txt')
82
83             if os.path.isfile(expected_stdout_path):
84                 with open(expected_stdout_path, 'rb') as f:
85                     expected_stdout = f.read()
86             else:
87                 expected_stdout = b''
88
89             expected_stderr_path = os.path.join('examples', filename + '.stderr.txt')
90
91             if os.path.isfile(expected_stderr_path):
92                 with open(expected_stderr_path, 'rb') as f:
93                     expected_stderr = f.read()
94             else:
95                 expected_stderr = b''
96
97             self.assertEqual(expected_stderr, actual_stderr)
98
99             # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
100             os.remove(os.path.join('examples', filename + '.c'))
101
102         finally:
103             try:
104                 os.remove('a.out')
105             except OSError:
106                 pass
107
108     setattr(CompilerOutputTests, 'test_' + filename, test)
109
110 class MemoryLeakTests(unittest.TestCase):
111     pass
112
113 def add_example_memory_leak_test(filename):
114     def test(self):
115         compile_fur_to_c_result = subprocess.call([
116             'python',
117             'main.py',
118             os.path.join('examples', filename),
119         ])
120
121         if compile_fur_to_c_result != 0:
122             raise Exception('Example "{}" did not compile'.format(filename))
123
124         compile_c_to_executable_result = subprocess.call([
125             'gcc',
126             '-ggdb3',
127             os.path.join('examples', filename + '.c'),
128         ])
129
130         if compile_c_to_executable_result != 0:
131             raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
132
133         try:
134             with open(os.devnull, 'w') as devnull:
135                 expected_return = 0
136                 actual_return = subprocess.call(
137                     [
138                         'valgrind',
139                         '--tool=memcheck',
140                         '--leak-check=yes',
141                         '--show-reachable=yes',
142                         '--num-callers=20',
143                         '--track-fds=yes',
144                         '--error-exitcode=42',
145                         '-q',
146                         './a.out',
147                     ],
148                     stdout=devnull,
149                     stderr=devnull,
150                 )
151
152                 self.assertEqual(expected_return, actual_return)
153
154                 # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
155                 os.remove(os.path.join('examples', filename + '.c'))
156
157         finally:
158             try:
159                 os.remove('a.out')
160             except OSError:
161                 pass
162
163     setattr(MemoryLeakTests, 'test_' + filename, test)
164
165 filenames = (
166     entry.name
167     for entry in os.scandir('examples')
168     if entry.is_file()
169     if entry.name.endswith('.fur')
170 )
171
172 for filename in filenames:
173     add_example_compiler_output_test(filename)
174     add_example_interpreter_output_test(filename)
175     add_example_memory_leak_test(filename)
176
177 unittest.main()