-
Notifications
You must be signed in to change notification settings - Fork 1
/
test.py
executable file
·164 lines (137 loc) · 4.93 KB
/
test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/python
"""Test runner for 6.172, fall 2010.
TODO(rnk): Fill out the docstring comment with usage.
"""
from __future__ import with_statement
__author__ = 'Reid Kleckner <rnk@mit.edu>'
import difflib
import os
import re
import subprocess
import sys
import time
GREEN = '\033[92;1m'
RED = '\033[91;1m'
END = '\033[0m'
QUIET = False
def print_result(result):
"""If result is True, print a green PASSED or red FAILED line otherwise."""
if result:
print GREEN + 'PASSED' + END
else:
print RED + 'FAILED' + END
def wait_for_test_process(proc, timeout):
"""Waits for a test process with a timeout, and reads stderr.
Reading stderr while polling is important, or a deadlock can occur if the
pipe's internal buffer fills up.
"""
endtime = time.time() + timeout
err_chunks = []
while proc.returncode is None and time.time() < endtime:
time.sleep(0.1)
err_chunks.append(os.read(proc.stderr.fileno(), 4096))
proc.poll()
# Kill the child if it hasn't stopped yet, and wait for it.
timed_out = False
if proc.returncode is None:
proc.kill()
proc.wait()
timed_out = True
print 'Test process timed out after 30s...'
# Read the rest of stderr.
chunk = True
while chunk:
chunk = os.read(proc.stderr.fileno(), 4096)
err_chunks.append(chunk)
lines = ''.join(err_chunks).split('\n')
return (timed_out, lines)
def test_project1(binary):
"""Test runner for project1 problems.
Apologies for the complicatedness of the testing protocol, and also of how
hard it is to properly run a process with a timeout.
"""
testdir = os.path.join(os.path.dirname(binary), 'tests')
test_files = [os.path.join(testdir, file) for file in os.listdir(testdir)]
num_passed = 0
num_failed = 0
test_index_total = 0
for filename in test_files:
testfileNameBegin = len(filename) - filename[::-1].index('/')
if filename[testfileNameBegin] == '.':
print "Skipping file beginning with '.'"
continue
done_testing = False
test_index = 0
while not done_testing:
with open(os.devnull) as null:
proc = subprocess.Popen([binary, '-t', filename],
stdout=null, stderr=subprocess.PIPE)
(timed_out, lines) = wait_for_test_process(proc, 30.0)
# Interpret each line.
for lineIndex in range(0, len(lines)):
line = lines[lineIndex]
lineIndex += 1;
match = re.match('Running test #(\d+)\.\.\.', line)
if match:
test_index = int(match.group(1))
match = re.match(' --> (.*): (PASS|FAIL)', line)
if match:
passed = match.group(2) == 'PASS'
if passed:
num_passed += 1
else:
num_failed += 1
# NOTE(TFK): Added 'or' to print failed tests.
if not QUIET or (QUIET and not passed):
testname = os.path.basename(binary) + ' ' + match.group(1)
print testname.ljust(64),
print_result(passed)
if not passed:
print lines[lineIndex];
lineIndex += 1;
print lines[lineIndex];
lineIndex += 1;
print lines[lineIndex];
lineIndex += 1;
if line.startswith('Done testing'):
test_index_total += (test_index + 1)
done_testing = True
# If there was a timeout, skip the last test.
if timed_out:
test_index += 1
num_failed += 1
elif proc.returncode != 0:
print 'Nonzero return code.'
done_testing = True
test_index += 1
num_failed += 1
# NOTE(TFK): No need for this when we're printing failed tests above.
if QUIET and False:
testname = os.path.basename(binary)
print testname.ljust(64),
print_result(num_failed == 0)
return (test_index_total, num_passed, num_failed)
def main(argv):
if len(argv) < 2:
print 'Usage: test.py [--quiet] <binary> ...'
sys.exit(1)
args = argv[1:]
if '--quiet' in args:
global QUIET
args.remove('--quiet')
QUIET = True
binaries = [os.path.join(os.getcwd(), arg) for arg in args]
total_tests = 0
total_passes = 0
total_failed = 0
for binary in binaries:
(num_tests, num_passes, num_failed) = test_project1(binary)
total_tests += num_tests
total_passes += num_passes
total_failed += num_failed
print ('Ran %d test functions, %d individual tests passed, '
'%d individual tests failed.' % (total_tests-1, total_passes,
total_failed))
print_result(total_failed == 0)
if __name__ == '__main__':
main(sys.argv)