Move .output.txt to .stdout.txt to reflect which output stream the files contain
[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 OutputTests(unittest.TestCase):
10     pass
11
12 def add_example_output_test(filename):
13     def test(self):
14         compile_fur_to_c_result = subprocess.call([
15             'python',
16             'main.py',
17             os.path.join('examples', filename),
18         ])
19
20         if compile_fur_to_c_result != 0:
21             raise Exception('Example "{}" did not compile'.format(filename))
22
23         compile_c_to_executable_result = subprocess.call([
24             'gcc',
25             os.path.join('examples', filename + '.c'),
26         ])
27
28         if compile_c_to_executable_result != 0:
29             raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
30
31         try:
32             p = subprocess.Popen('./a.out', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
33             actual_stdout, actual_stderr = p.communicate()
34
35             expected_stdout_path = os.path.join('examples', filename + '.stdout.txt')
36
37             if os.path.isfile(expected_stdout_path):
38                 with open(expected_stdout_path, 'rb') as f:
39                     expected_stdout = f.read()
40             else:
41                 expected_stdout = b''
42
43             expected_stderr_path = os.path.join('examples', filename + '.stderr.txt')
44
45             if os.path.isfile(expected_stderr_path):
46                 with open(expected_stderr_path, 'rb') as f:
47                     expected_stderr = f.read()
48             else:
49                 expected_stderr = b''
50
51             self.assertEqual(expected_stderr, actual_stderr)
52
53             # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
54             os.remove(os.path.join('examples', filename + '.c'))
55
56         finally:
57             try:
58                 os.remove('a.out')
59             except OSError:
60                 pass
61
62     setattr(OutputTests, 'test_' + filename, test)
63
64 class MemoryLeakTest(unittest.TestCase):
65     pass
66
67 def add_example_memory_leak_test(filename):
68     def test(self):
69         compile_fur_to_c_result = subprocess.call([
70             'python',
71             'main.py',
72             os.path.join('examples', filename),
73         ])
74
75         if compile_fur_to_c_result != 0:
76             raise Exception('Example "{}" did not compile'.format(filename))
77
78         compile_c_to_executable_result = subprocess.call([
79             'gcc',
80             '-ggdb3',
81             os.path.join('examples', filename + '.c'),
82         ])
83
84         if compile_c_to_executable_result != 0:
85             raise Exception('Example output "{}" did not compile'.format(filename + '.c'))
86
87         try:
88             with open(os.devnull, 'w') as devnull:
89                 expected_return = 0
90                 actual_return = subprocess.call(
91                     [
92                         'valgrind',
93                         '--tool=memcheck',
94                         '--leak-check=yes',
95                         '--show-reachable=yes',
96                         '--num-callers=20',
97                         '--track-fds=yes',
98                         '--error-exitcode=666',
99                         '-q',
100                         './a.out',
101                     ],
102                     stdout=devnull,
103                     stderr=devnull,
104                 )
105
106                 self.assertEqual(expected_return, actual_return)
107
108                 # We don't clean up the C file in the finally clause because it can be useful to have in case of errors
109                 os.remove(os.path.join('examples', filename + '.c'))
110
111         finally:
112             try:
113                 os.remove('a.out')
114             except OSError:
115                 pass
116
117     setattr(MemoryLeakTest, 'test_' + filename, test)
118
119 filenames = (
120     entry.name
121     for entry in os.scandir('examples')
122     if entry.is_file()
123     if entry.name.endswith('.fur')
124 )
125
126 for filename in filenames:
127     add_example_output_test(filename)
128     add_example_memory_leak_test(filename)
129
130 unittest.main()