from pprint import PrettyPrinter import subprocess from pathlib import Path import tomllib import uuid # 配置参数 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}...") # 使用唯一文件名避免并发冲突 unique_id = str(uuid.uuid4())[:8] # 简短的唯一标识符 exe_filename = f"test_{unique_id}.exe" exe_path = WORKSPACE / exe_filename # 1. 编译 compile_cmd = [str(CC_PATH), str(test_file), "-o", exe_filename, "--entry-point-symbol", "main"] # 编译时关注 stderr 和返回码 _, compile_err, compile_ret = run_command(compile_cmd) if not exe_path.exists() or compile_ret != 0: print(f" Compilation failed: {compile_err}") # 确保清理失败的输出文件 if exe_path.exists(): try: exe_path.unlink() except: pass # 忽略清理失败 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}") # 清理文件后返回 try: exe_path.unlink() except: pass # 忽略清理失败 return False # 3. 获取返回值 (修改进程返回值而非 stdout) actual = vm_ret # 4. 清理输出文件 try: exe_path.unlink() except: pass # 忽略清理失败 # 5. 验证结果 # 注意: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 print(f"\nTest Summary: {passed}/{total} passed") if __name__ == "__main__": main()