Hackathon-IA-VisualNovel / tests /test_engine_split.py
WillHbx's picture
test: engine split, llm helpers, and orchestrator guard coverage
1ea8154
Raw
History Blame Contribute Delete
2.67 kB
"""The two-phase turn: play_turn_text must return dialogue without painting,
play_turn_images must complete the view afterwards — including from a fresh Engine
(the ZeroGPU cross-worker contract via the state file)."""
from __future__ import annotations
import pytest
from visualnovel import engine as engine_mod
from visualnovel.engine import Engine
from visualnovel.schemas import SetupForm
@pytest.fixture()
def isolated_state_file(monkeypatch, tmp_path):
monkeypatch.setattr(engine_mod, "_STATE_FILE", tmp_path / "vn_game_state.json")
def _started_engine() -> Engine:
eng = Engine()
eng.start(SetupForm(theme="school", tone="romantic", seed=7))
return eng
def test_turn_text_then_images(isolated_state_file):
eng = _started_engine()
v1 = eng.play_turn_text("hello there")
assert v1.dialogue
assert v1.backdrop_url is None
assert v1.present == []
v2 = eng.play_turn_images()
assert v2.backdrop_url
assert v2.present
assert v2.dialogue == v1.dialogue
def test_turn_images_survives_worker_restart(isolated_state_file):
eng = _started_engine()
v1 = eng.play_turn_text("hello there")
# ZeroGPU may dispatch the second call to a fresh worker: a new Engine must
# recover the pending turn from the state file.
fresh = Engine()
v2 = fresh.play_turn_images()
assert v2.backdrop_url
assert v2.dialogue == v1.dialogue
def test_composed_play_turn_still_full(isolated_state_file):
eng = _started_engine()
v = eng.play_turn("hello there")
assert v.dialogue
assert v.backdrop_url
assert v.present
def test_resume_roundtrip(isolated_state_file):
eng = _started_engine()
v1 = eng.play_turn("hello there")
fresh = Engine()
v = fresh.resume()
assert v is not None
assert v.turn_index == v1.turn_index
assert v.dialogue == v1.dialogue
assert v.backdrop_url
# journal recap: the recent exchanges travel with display names, not ids
assert v.history
assert v.history[-1].dialogue == v1.dialogue
assert v.history[-1].speaker == "Hana" # mock first character's name, not "hana"
def test_resume_without_state_returns_none(isolated_state_file):
assert Engine().resume() is None
def test_session_info(isolated_state_file, monkeypatch):
from visualnovel import engine as engine_mod
assert engine_mod.session_info() == {"exists": False}
eng = _started_engine()
eng.play_turn("hello there")
info = engine_mod.session_info()
assert info["exists"] is True
assert info["turn_index"] == eng.state.turn_index
assert info["place"] == eng.state.scene.place
assert info["ended"] is False