固化 Match-3 生产者、视觉、音频与双 Judge 证据闭包。 将《山海行纪》r1.1 绑定新的不可变 release,并以生产预检现场核验 bundle、Registry/2 和 25 项 Writer 快照。 同步地图1平衡锁值、跨游戏回归修复、验收契约与 SoT 证据。
84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
"""
|
||
test_studio_smoke.py — U5 端到端产物契约验证。
|
||
|
||
端到端真跑由 cheap_studio CLI 提供(落 evidence/run-summary.json + staged 工程 + 九门 verdict);
|
||
本 test 验证最近一次 run 的产物契约(真 src/ 多文件 + staged + 九门 verdict + run-summary 字段)。
|
||
|
||
真跑回归(~2.5min,真 M3 ReAct):
|
||
cheap-worker/.venv/bin/python cheap-worker/cheap_studio.py --id cheap-smoke1 --brief "一个简单的点击得分小游戏:屏幕上随机冒出可点的圆,点中加分"
|
||
然后:cheap-worker/.venv/bin/python cheap-worker/tests/test_studio_smoke.py
|
||
"""
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # → cheap-worker/
|
||
import cheap_run
|
||
|
||
GID = "cheap-smoke1"
|
||
RUN_SUMMARY = cheap_run.game_dir(GID) / "evidence" / "run-summary.json"
|
||
|
||
# 默认 pytest 是离线单测入口;真模型 smoke 必须先由上方 CLI 显式产证。
|
||
# 直接执行本文件时 pytestmark 不生效,仍会由 _require_run 严格拒绝缺失证据。
|
||
pytestmark = pytest.mark.skipif(
|
||
not RUN_SUMMARY.exists(),
|
||
reason="需先显式运行 cheap_studio 真模型 smoke 生成 cheap-smoke1 证据",
|
||
)
|
||
|
||
|
||
def _require_run() -> dict:
|
||
p = RUN_SUMMARY
|
||
if not p.exists():
|
||
raise AssertionError(
|
||
f"先跑端到端单局:cheap-worker/.venv/bin/python cheap-worker/cheap_studio.py --id {GID} --brief ...(缺 {p})")
|
||
return json.loads(p.read_text(encoding="utf-8"))
|
||
|
||
|
||
def test_run_summary_contract():
|
||
"""run-summary 含 finished/check/build/staged 字段且收敛。"""
|
||
s = _require_run()
|
||
assert s["finished"] is True, s
|
||
assert s["check"]["ok"] and s["build"]["ok"], s
|
||
assert s["staged"] is True, s
|
||
|
||
|
||
def test_real_src_multifile():
|
||
"""产真 src/ 多文件工程(非单文件 / JSON blob / new Function blob)——doc↔code 兑现门的便宜档侧。"""
|
||
src = cheap_run.game_dir(GID) / "src"
|
||
assert (src / "game-logic.js").exists(), "缺 src/game-logic.js"
|
||
js = list(src.glob("*.js"))
|
||
assert len(js) >= 2, f"应为真 src/ 多文件工程,实际 {len(js)} 个 .js"
|
||
|
||
|
||
def test_staged_artifact_exists():
|
||
"""stage 后 _wg1-gen/<id>/ 有自包含 bundle + index + 自动产的 play-spec。"""
|
||
dst = cheap_run.wg1_game_dir(GID)
|
||
assert (dst / "bundle.iife.js").exists()
|
||
assert (dst / "index.html").exists()
|
||
assert (dst / "play-spec.json").exists(), "play-spec 缺失 → 九门会 driven=false 假绿"
|
||
|
||
|
||
def test_nine_gates_verdict():
|
||
"""九门 verdict.json 存在且含逐门 guards(不假绿)。"""
|
||
v = cheap_run.wg1_game_dir(GID) / "evidence" / "verdict.json"
|
||
assert v.exists(), "缺九门 verdict.json"
|
||
d = json.loads(v.read_text(encoding="utf-8"))
|
||
assert isinstance(d.get("guards"), dict), "verdict 应含九门 guards"
|
||
|
||
|
||
if __name__ == "__main__":
|
||
_fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
|
||
_failed = 0
|
||
for _fn in _fns:
|
||
try:
|
||
_fn()
|
||
print(f" PASS {_fn.__name__}")
|
||
except Exception as e: # noqa: BLE001
|
||
_failed += 1
|
||
print(f" FAIL {_fn.__name__}: {type(e).__name__}: {e}")
|
||
print(f"\n{len(_fns) - _failed}/{len(_fns)} passed")
|
||
sys.exit(1 if _failed else 0)
|