This repository was archived by the owner on Apr 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathtest.py
133 lines (112 loc) · 3.87 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
#!/usr/bin/env python
import os
import re
import signal
import subprocess
import sys
import time
import traceback
lab_dir_path = os.getcwd()
tests_dir_path = os.path.join(os.getcwd(), "tests")
logisim_path = os.path.join(os.getcwd(),"..", "tools", "logisim-evolution.jar")
# logisim_env = os.environ.copy()
# logisim_env["CS61C_TOOLS_ARGS"] = logisim_env.get("CS61C_TOOLS_ARGS", "") + " -q"
class TestCase():
"""
Runs specified circuit file and compares output against the provided reference trace file.
"""
def __init__(self, id, name):
self.id = id
self.name = name
def fix_circ(self):
old_data = None
data = None
with open(self.get_circ_path(), "rt") as test_circ:
old_data = test_circ.read()
import_regex = re.compile(rf"desc=\"(file#[^\"]*\b{self.id}\.circ)\"")
correct_desc = f"desc=\"file#../{self.id}.circ\""
match = re.search(import_regex, old_data)
if not match or match.group(0) == correct_desc:
return
print(f"Fixing bad import in {self.id}-test.circ")
data = re.sub(import_regex, correct_desc, old_data)
with open(self.get_circ_path(), "wt") as test_circ:
test_circ.write(data)
def get_circ_path(self):
return os.path.join(tests_dir_path, f"{self.id}-test.circ")
def get_expected_table_path(self):
return os.path.join(tests_dir_path, "reference-output", f"{self.id}-test.out")
def get_actual_table_path(self):
return os.path.join(tests_dir_path, "student-output", f"{self.id}-test.out")
def run(self):
passed = False
proc = None
try:
self.fix_circ()
proc = subprocess.Popen(["java", "-jar", logisim_path, "-tty", "table,binary,tabs", self.get_circ_path()], stdout=subprocess.PIPE)
with open(self.get_expected_table_path(), "r") as reference:
passed = self.check_output(proc.stdout, reference)
kill_proc(proc)
if passed:
return (True, "Matched expected output")
else:
return (False, "Did not match expected output")
except KeyboardInterrupt:
sys.exit(1)
except SystemExit:
raise
except:
traceback.print_exc()
if proc:
kill_proc(proc)
return (False, "Errored while running test")
def check_output(self, student, reference):
passed = True
student_lines = []
while True:
student_line = student.readline().decode("ascii", errors="ignore").strip()
reference_line = reference.readline().strip()
if reference_line == "":
break
student_lines.append(student_line)
if student_line != reference_line:
passed = False
output_path = self.get_actual_table_path()
os.makedirs(os.path.dirname(output_path), mode=0o755, exist_ok=True)
with open(output_path, "w") as f:
for line in student_lines:
f.write(f"{line}\n")
return passed
def kill_proc(proc):
if proc.poll() == None:
if sys.platform == "win32":
os.kill(proc.pid, signal.CTRL_C_EVENT)
for _ in range(10):
if proc.poll() != None:
break
time.sleep(0.1)
if proc.poll() == None:
proc.kill()
tests = [
TestCase("ex2", "Exercise 2: Sub-Circuits"),
TestCase("ex3", "Exercise 3: Add Machine"),
TestCase("ex4", "Exercise 4: FSM"),
TestCase("ex5", "Exercise 5: Splitter"),
TestCase("ex6", "Exercise 6: Rotate"),
TestCase("ex7", "Exercise 7: Buggy Traffic Lights")
]
def run_tests(tests):
print("Testing files...")
tests_failed = 0
tests_passed = 0
for test in tests:
did_pass, reason = test.run()
if did_pass:
print(f"PASSED test: {test.name}")
tests_passed += 1
else:
print(f"FAILED test: {test.name} ({reason})")
tests_failed += 1
print(f"Passed {tests_passed}/{tests_failed + tests_passed} tests")
if __name__ == '__main__':
run_tests(tests)