from pprint import PrettyPrinter import subprocess import os from pathlib import Path import tomllib # 配置参数 WORKSPACE = Path(__file__).resolve().parent # 测试工作目录 TEST_DIR = Path(WORKSPACE) CC_PATH = Path(WORKSPACE / "../../build/dev/scc") def run_command(cmd, capture_output=True): """执行命令并捕获 stdout""" try: result = subprocess.run( cmd, cwd=WORKSPACE, stdout=subprocess.PIPE if capture_output else None, stderr=subprocess.PIPE, text=True, timeout=5, # 增加超时时间以防虚拟机启动慢 ) # 返回 stdout 用于获取返回值,同时检查是否有运行时错误 return result.stdout.strip(), result.stderr.strip(), result.returncode except subprocess.TimeoutExpired: return None, "Timeout expired", -1 except Exception as e: return None, str(e), -1 def run_test(test_file, expected): print(f"\nTesting {test_file}...") # 1. 编译 compile_cmd = [str(CC_PATH), str(test_file), "-o", "test.exe"] # 编译时关注 stderr 和返回码 _, compile_err, compile_ret = run_command(compile_cmd) exe_path = WORKSPACE / "test.exe" if not exe_path.exists() or compile_ret != 0: print(f" Compilation failed: {compile_err}") return False # 2. 执行虚拟机并获取输出 vm_cmd = [str(exe_path)] actual_output, vm_err, vm_ret = run_command(vm_cmd) # 如果存在 stderr 且返回码异常(例如负数表示信号终止),则视为运行时错误 if vm_err and vm_ret < 0: print(f" Runtime error: {vm_err}") return False # 3. 获取返回值 (修改进程返回值而非 stdout) actual = vm_ret # 4. 验证结果 # 注意:toml 中读取的 expected 可能是整数,actual 也是整数,直接比较 if actual == expected: print(f" PASSED {test_file}") return True else: print(f" FAILED: Expected '{expected}', got '{actual}'") return False def main(): passed = 0 total = 0 config = {} config_path = WORKSPACE / "expect.toml" if not config_path.exists(): print(f"Config file not found: {config_path}") return with open(config_path, "rb") as f: config = tomllib.load(f) PrettyPrinter().pprint(config) for test_file, expected in config.get("return_val_cases", {}).items(): total += 1 if run_test(TEST_DIR / test_file, expected): passed += 1 # 清理中间文件 exe_path = WORKSPACE / "test.exe" if exe_path.exists(): os.remove(exe_path) print(f"\nTest Summary: {passed}/{total} passed") if __name__ == "__main__": main()