| """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") |
| |
| |
| 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 |
| |
| assert v.history |
| assert v.history[-1].dialogue == v1.dialogue |
| assert v.history[-1].speaker == "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 |
|
|