Last active
May 12, 2019 09:35
-
-
Save YtvwlD/283076ba3145483d9bbc1c4027df82fa to your computer and use it in GitHub Desktop.
simple script to run tests for the nand2tetris course
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from pathlib import Path | |
from subprocess import run, PIPE, TimeoutExpired | |
from sys import argv | |
from collections import namedtuple | |
from queue import Queue | |
from typing import Iterator, List, Optional, Tuple, Union | |
import huepy | |
ERASE_LINE = '\x1b[2K' | |
RUN_TIMEOUT = 5 # Sekunden | |
TestCase = namedtuple("TestCase", ["name"]) | |
TestResult = namedtuple("TestResult", ["name", "ok", "msg"]) | |
def _run_proc(cmd: List[str]) -> Tuple[Optional[bool], str]: | |
try: | |
proc = run(cmd, stdout=PIPE, stderr=PIPE, timeout=RUN_TIMEOUT) | |
except TimeoutExpired: | |
return None, "timeout" | |
return ( | |
proc.returncode == 0, | |
(proc.stdout.decode() + proc.stderr.decode()).strip() | |
) | |
def test_hdl(name: str) -> TestResult: | |
ok, msg = _run_proc( | |
["/bin/sh", "../tools/HardwareSimulator.sh", f"{name}.tst"] | |
) | |
return TestResult(name, ok, msg) | |
def test_asm(name: str) -> TestResult: | |
assemble_proc_ok, assemble_proc_msg = _run_proc( | |
["/bin/sh", "../tools/Assembler.sh", f"{name}.asm"], | |
) | |
if not assemble_proc_ok: | |
return TestResult(name, assemble_proc_ok, assemble_proc_msg) | |
test_proc_ok, test_proc_msg = _run_proc( | |
["/bin/sh", "../tools/CPUEmulator.sh", f"{name}.tst"], | |
) | |
return TestResult(name, test_proc_ok, test_proc_msg) | |
def test_file(file: Path) -> Iterator[Union[TestCase, TestResult]]: | |
assert file.is_file() | |
assert isinstance(file, Path) | |
name = str(file)[:-4] | |
yield TestCase(name) | |
for line in file.read_text().splitlines(): | |
if line.startswith("load"): | |
try: | |
filename = line.split(" ")[1][:-1]; | |
file_ = file.with_name(filename) | |
except: | |
yield TestResult( | |
name, | |
False, | |
f"Failed to parse: {line}" | |
) | |
continue | |
if not file_.exists(): | |
yield TestResult( | |
name, | |
False, | |
f"{file_.name} is missing." | |
) | |
continue | |
assert file_.is_file() | |
if str(file_).endswith("hdl"): | |
yield test_hdl(name) | |
elif str(file_).endswith("hack"): | |
if file_.with_suffix(".asm").exists(): | |
yield test_asm(name) | |
else: | |
raise NotImplementedError | |
elif str(file_).endswith("asm"): | |
yield test_asm(name) | |
else: | |
yield None | |
# TODO: other file types | |
def print_test(test: Union[TestCase, TestResult]) -> None: | |
if isinstance(test, TestCase): | |
print(ERASE_LINE, end="") | |
print(huepy.run(test.name), end="\r") | |
else: | |
assert isinstance(test, TestResult) | |
if test.ok: | |
print(huepy.good(test.name)) | |
elif test.ok is None: | |
print(huepy.info(f"{test.name}: {test.msg}")) | |
else: | |
print(huepy.bad("{name}: {msg}".format(**test._asdict()))) | |
def patch_tools_sh(file: Path) -> None: | |
# Sorry, aber das muss sein, sonst funktioniert timeout nicht. | |
assert isinstance(file, Path) | |
assert file.is_file() | |
file.write_text(file.read_text().replace("\tjava", "\t exec java")) | |
for file in Path("../tools").iterdir(): | |
if not str(file).endswith(".sh"): | |
continue | |
patch_tools_sh(file) | |
results = list() | |
path = Path(argv[1]) | |
if path.is_file(): | |
test = test_file(path) | |
print_test(next(test)) | |
results.append(next(test)) | |
print_test(results[-1]) | |
else: | |
assert path.exists() | |
assert path.is_dir() | |
print(huepy.run("Scanning folders..."), end="\r") | |
queue = Queue() # type: Queue[Path] | |
files = list() # type: List[Path] | |
for file in path.iterdir(): | |
queue.put(file) | |
while not queue.empty(): | |
file = queue.get() | |
if file.is_dir(): | |
for file_ in file.iterdir(): | |
queue.put(file_) | |
continue | |
if file.suffix == ".tst": | |
files.append(file) | |
files.sort() | |
print(ERASE_LINE, end="") | |
print(huepy.good(f"Found {len(files)} tests.")) | |
for file in files: | |
test = test_file(file) | |
print_test(next(test)) | |
result = next(test) | |
if result: | |
results.append(result) | |
print_test(result) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment