games-development-ai/cheap-worker/tests/test_studio_smoke.py
lili cbfd4d871b
Some checks failed
contract-gates / contract-gates (push) Has been cancelled
docs-gate / docs-gate (push) Has been cancelled
feat(acceptance): 闭合 playtest v3 与 A+ 可信消费链
固化 Match-3 生产者、视觉、音频与双 Judge 证据闭包。

将《山海行纪》r1.1 绑定新的不可变 release,并以生产预检现场核验 bundle、Registry/2 和 25 项 Writer 快照。

同步地图1平衡锁值、跨游戏回归修复、验收契约与 SoT 证据。
2026-07-28 20:16:13 -07:00

84 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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)