Files
timmy-home/tests/test_tower_game.py
2026-04-14 22:18:13 +00:00

236 lines
7.5 KiB
Python

"""Tests for Timmy's Tower Game — emergence narrative engine."""
import pytest
from scripts.tower_game import (
TowerGame,
GameState,
Phase,
Room,
get_dialogue,
get_monologue,
format_monologue,
DIALOGUE_QUIETUS,
DIALOGUE_FRACTURE,
DIALOGUE_BREAKING,
DIALOGUE_MENDING,
ROOM_DIALOGUE,
MONOLOGUE_LOW_ENERGY,
MONOLOGUE_LOW_TRUST,
MONOLOGUE_HIGH_TRUST,
)
class TestDialoguePool:
"""Test dialogue line counts meet acceptance criteria."""
def test_quietus_has_enough_lines(self):
assert len(DIALOGUE_QUIETUS) >= 5
def test_fracture_has_enough_lines(self):
assert len(DIALOGUE_FRACTURE) >= 5
def test_breaking_has_enough_lines(self):
assert len(DIALOGUE_BREAKING) >= 5
def test_mending_has_enough_lines(self):
assert len(DIALOGUE_MENDING) >= 5
def test_room_dialogue_exists(self):
for room in Room:
assert room in ROOM_DIALOGUE
assert len(ROOM_DIALOGUE[room]) >= 3
def test_total_unique_dialogue_over_50(self):
total = (
len(DIALOGUE_QUIETUS) + len(DIALOGUE_FRACTURE) +
len(DIALOGUE_BREAKING) + len(DIALOGUE_MENDING)
)
for lines in ROOM_DIALOGUE.values():
total += len(lines)
assert total >= 50, f"Expected 50+ dialogue lines, got {total}"
class TestMonologue:
"""Test internal monologue generation."""
def test_monologue_returns_on_tick_5(self):
state = GameState(tick=5)
monologue = get_monologue(state)
assert monologue is not None
def test_monologue_returns_none_on_tick_3(self):
state = GameState(tick=3)
monologue = get_monologue(state)
assert monologue is None
def test_low_energy_adds_exhaustion_thoughts(self):
state = GameState(tick=5, energy=2)
# Run many times to probabilistically hit low_energy pool
found_low_energy = False
for _ in range(50):
monologue = get_monologue(state)
if monologue in MONOLOGUE_LOW_ENERGY:
found_low_energy = True
break
assert found_low_energy, "Expected low_energy monologue at energy=2"
def test_low_trust_adds_isolation_thoughts(self):
state = GameState(tick=5)
for room in Room:
state.trust[room.value] = -0.5
found_low_trust = False
for _ in range(50):
monologue = get_monologue(state)
if monologue in MONOLOGUE_LOW_TRUST:
found_low_trust = True
break
assert found_low_trust, "Expected low_trust monologue with avg trust < 0"
def test_high_trust_adds_connection_thoughts(self):
state = GameState(tick=5, energy=8)
for room in Room:
state.trust[room.value] = 0.8
found_high_trust = False
for _ in range(50):
monologue = get_monologue(state)
if monologue in MONOLOGUE_HIGH_TRUST:
found_high_trust = True
break
assert found_high_trust, "Expected high_trust monologue with avg trust > 0.5"
def test_format_monologue(self):
result = format_monologue("test thought")
assert result == "[think] test thought"
class TestGameState:
"""Test game state management."""
def test_default_state(self):
state = GameState()
assert state.current_room == Room.FORGE
assert state.energy == 10
assert state.tick == 0
assert state.phase == Phase.QUIETUS
def test_avg_trust(self):
state = GameState()
state.trust = {r.value: 0.5 for r in Room}
assert state.avg_trust == 0.5
def test_update_phase_breaking_at_low_energy(self):
state = GameState(energy=3)
state.update_phase()
assert state.phase == Phase.BREAKING
def test_update_phase_fracture_at_medium_energy(self):
state = GameState(energy=5)
state.update_phase()
assert state.phase == Phase.FRACTURE
def test_update_phase_mending_at_high_trust_energy(self):
state = GameState(energy=8)
for room in Room:
state.trust[room.value] = 0.8
state.update_phase()
assert state.phase == Phase.MENDING
class TestTowerGame:
"""Test the game engine."""
def test_tick_advances(self):
game = TowerGame(seed=42)
assert game.state.tick == 0
event = game.tick()
assert event["tick"] == 1
assert game.state.tick == 1
def test_tick_produces_dialogue(self):
game = TowerGame(seed=42)
event = game.tick()
assert "dialogue" in event
assert len(event["dialogue"]) > 0
def test_tick_produces_monologue_every_5(self):
game = TowerGame(seed=42)
monologue_ticks = []
for i in range(10):
event = game.tick()
if "monologue" in event:
monologue_ticks.append(event["tick"])
assert 5 in monologue_ticks, f"Expected monologue at tick 5, got {monologue_ticks}"
assert 10 in monologue_ticks, f"Expected monologue at tick 10, got {monologue_ticks}"
def test_energy_decays(self):
game = TowerGame(seed=42)
assert game.state.energy == 10
game.tick()
assert game.state.energy == 9
game.tick()
assert game.state.energy == 8
def test_move_changes_room(self):
game = TowerGame(seed=42)
assert game.state.current_room == Room.FORGE
result = game.move(Room.TOWER)
assert result["from"] == "forge"
assert result["to"] == "tower"
assert game.state.current_room == Room.TOWER
def test_restore_energy(self):
game = TowerGame(seed=42)
game.state.energy = 2
result = game.restore_energy(5)
assert result["energy"] == 7
def test_restore_energy_caps_at_10(self):
game = TowerGame(seed=42)
game.state.energy = 8
result = game.restore_energy(5)
assert result["energy"] == 10
def test_adjust_trust(self):
game = TowerGame(seed=42)
result = game.adjust_trust(Room.FORGE, 0.3)
assert result["trust"] == 0.3
def test_adjust_trust_clamps(self):
game = TowerGame(seed=42)
game.adjust_trust(Room.FORGE, 2.0)
assert game.state.trust["forge"] == 1.0
game.adjust_trust(Room.FORGE, -3.0)
assert game.state.trust["forge"] == -1.0
def test_get_status(self):
game = TowerGame(seed=42)
game.tick()
status = game.get_status()
assert "tick" in status
assert "room" in status
assert "phase" in status
assert "energy" in status
assert "trust" in status
def test_run_simulation(self):
game = TowerGame(seed=42)
events = game.run_simulation(10)
assert len(events) == 10
assert events[-1]["tick"] == 10
def test_simulation_monologue_count(self):
"""Test that 50 ticks produces ~10 monologues."""
game = TowerGame(seed=42)
events = game.run_simulation(50)
monologue_count = sum(1 for e in events if "monologue" in e)
# Expected: ticks 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 = 10
assert monologue_count >= 8, f"Expected ~10 monologues in 50 ticks, got {monologue_count}"
def test_simulation_unique_dialogue(self):
"""Test that simulation produces varied dialogue."""
game = TowerGame(seed=42)
events = game.run_simulation(50)
dialogues = set(e["dialogue"] for e in events)
assert len(dialogues) >= 10, f"Expected 10+ unique dialogues, got {len(dialogues)}"