update
This commit is contained in:
77
engine/tests/test_harness.py
Normal file
77
engine/tests/test_harness.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import pytest
|
||||
|
||||
from engine.harness import calibrate_cprofile_overhead, collect_environment, load_source
|
||||
|
||||
|
||||
def test_calibrate_returns_well_formed_calibration():
|
||||
"""校准应该返回一个 well-formed Calibration:ratio > 0,两段耗时 > 0,workloadName 已知。
|
||||
|
||||
不强求 ratio > 1.0:在极快的机器上校准本身 < 5ms,会走 fallback ratio=1.0;
|
||||
此时 instrumentedWorkloadSec 可能比 clean 略小(perf_counter 在 1ms 量级有 noise),
|
||||
也不强求 instrumented >= clean。这条测试只锁住「返回结构对 + 数值非负」。
|
||||
"""
|
||||
calib = calibrate_cprofile_overhead()
|
||||
assert calib.ratio > 0, f"ratio 必须正:{calib.ratio}"
|
||||
assert calib.ratio <= 10.0, f"ratio 太大,可能校准失效:{calib.ratio}"
|
||||
assert calib.cleanWorkloadSec > 0
|
||||
assert calib.instrumentedWorkloadSec > 0
|
||||
assert calib.workloadName == "tight-loop"
|
||||
|
||||
|
||||
def test_calibrate_fallback_when_workload_too_fast(monkeypatch):
|
||||
"""校准本身耗时 < 5ms 时应回退 ratio=1.0 —— 见 calibrate_cprofile_overhead 的边界处理。
|
||||
|
||||
直接 mock calibrate_cprofile_overhead 内部的 _exec_once_* 行为不可行(它们是模块内 helper),
|
||||
改成 monkeypatch time.perf_counter 返回极短耗时:第一次返回 t0=0.0,第二次返回 t0+1e-6。
|
||||
"""
|
||||
from engine import harness
|
||||
|
||||
counter = {"n": 0}
|
||||
base = {"t": 1000.0}
|
||||
|
||||
def fake_perf_counter():
|
||||
counter["n"] += 1
|
||||
# 第一次调用返回 0,之后每次 + 极小 delta,让 elapsed = ~3us (远小于 5ms)
|
||||
idx = counter["n"]
|
||||
return base["t"] + idx * 1e-6
|
||||
|
||||
monkeypatch.setattr(harness.time, "perf_counter", fake_perf_counter)
|
||||
calib = harness.calibrate_cprofile_overhead()
|
||||
assert calib.ratio == 1.0, f"短耗时下应回退 ratio=1.0,实际:{calib.ratio}"
|
||||
|
||||
|
||||
def test_calibrate_does_not_leak_files(monkeypatch, tmp_path):
|
||||
"""校准自己 scratch 一个临时文件,跑完应清干净 —— 不污染系统临时目录。"""
|
||||
# 让 mkstemp 落到 tmp_path 方便断言
|
||||
import tempfile
|
||||
monkeypatch.setattr(tempfile, "gettempdir", lambda: str(tmp_path))
|
||||
before = set(tmp_path.iterdir())
|
||||
calibrate_cprofile_overhead()
|
||||
after = set(tmp_path.iterdir())
|
||||
# 不应有残留 —— 之前 / 之后 iterdir 集合应相等
|
||||
assert after == before, f"残留文件: {after - before}"
|
||||
|
||||
|
||||
def test_collect_environment():
|
||||
env = collect_environment()
|
||||
assert env.python.count(".") >= 2
|
||||
assert env.timerResolution > 0
|
||||
|
||||
|
||||
def test_load_source_strips_bom(tmp_path):
|
||||
"""load_source 必须剥掉 BOM —— 引擎内所有读源码的地方都依赖这一点。"""
|
||||
script = tmp_path / "bom.py"
|
||||
script.write_text("x = 1\n", encoding="utf-8-sig")
|
||||
assert script.read_bytes().startswith(b"\xef\xbb\xbf")
|
||||
src = load_source(str(script))
|
||||
assert not src.startswith("")
|
||||
# 剥离后必须能直接过 compile(),这正是 runner 语法预检做的事
|
||||
compile(src, str(script), "exec")
|
||||
|
||||
|
||||
def test_load_source_raises_on_binary(tmp_path):
|
||||
"""二进制文件抛 UnicodeDecodeError(而不是 OSError)—— runner 依赖这个类型来归类错误。"""
|
||||
script = tmp_path / "bin.py"
|
||||
script.write_bytes(b"\xff\xfe\x00\x01\x80\x81")
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
load_source(str(script))
|
||||
Reference in New Issue
Block a user