amogus/tests/test_simulator.py

213 lines
6.7 KiB
Python

"""
Tests for the discrete event simulator.
"""
import unittest
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.engine.simulator import Simulator
from src.engine.types import Event, Player, Position, Role, GamePhase
class TestEvent(unittest.TestCase):
"""Tests for Event dataclass."""
def test_event_creation(self):
event = Event(time=10.0, event_type="TEST", data={"key": "value"})
self.assertEqual(event.time, 10.0)
self.assertEqual(event.event_type, "TEST")
self.assertEqual(event.data["key"], "value")
def test_event_ordering(self):
e1 = Event(time=5.0, event_type="A")
e2 = Event(time=10.0, event_type="B")
e3 = Event(time=5.0, event_type="C")
self.assertTrue(e1 < e2)
self.assertFalse(e2 < e1)
# Same time - order undefined but should not error
self.assertFalse(e1 < e3 and e3 < e1)
class TestPlayer(unittest.TestCase):
"""Tests for Player dataclass."""
def test_player_creation(self):
player = Player(
id="p1", name="Red", color="red",
role=Role.CREWMATE,
position=Position(x=1000, y=400, room_id="cafeteria")
)
self.assertEqual(player.id, "p1")
self.assertEqual(player.role, Role.CREWMATE)
self.assertTrue(player.is_alive)
def test_position_distance(self):
pos1 = Position(x=0, y=0)
pos2 = Position(x=3, y=4)
self.assertAlmostEqual(pos1.distance_to(pos2), 5.0)
def test_position_with_room(self):
pos = Position(x=100, y=200, room_id="cafeteria")
self.assertEqual(pos.room_id, "cafeteria")
self.assertEqual(pos.x, 100)
class TestSimulator(unittest.TestCase):
"""Tests for the Simulator class."""
def setUp(self):
self.sim = Simulator()
def test_initial_state(self):
self.assertEqual(self.sim.time, 0.0)
self.assertEqual(self.sim.phase, GamePhase.LOBBY)
self.assertEqual(len(self.sim.players), 0)
def test_schedule_event(self):
event = Event(time=5.0, event_type="TEST")
self.sim.schedule(event)
self.assertEqual(self.sim.peek_next_time(), 5.0)
def test_schedule_at(self):
event = self.sim.schedule_at(10.0, "TEST", {"data": 1})
self.assertEqual(event.time, 10.0)
self.assertEqual(self.sim.peek_next_time(), 10.0)
def test_schedule_in(self):
self.sim.time = 5.0
event = self.sim.schedule_in(3.0, "TEST")
self.assertEqual(event.time, 8.0)
def test_step_processes_event(self):
self.sim.schedule_at(5.0, "TEST")
event = self.sim.step()
self.assertIsNotNone(event)
self.assertEqual(event.event_type, "TEST")
self.assertEqual(self.sim.time, 5.0)
def test_step_empty_queue(self):
event = self.sim.step()
self.assertIsNone(event)
def test_event_ordering(self):
self.sim.schedule_at(10.0, "SECOND")
self.sim.schedule_at(5.0, "FIRST")
self.sim.schedule_at(15.0, "THIRD")
e1 = self.sim.step()
e2 = self.sim.step()
e3 = self.sim.step()
self.assertEqual(e1.event_type, "FIRST")
self.assertEqual(e2.event_type, "SECOND")
self.assertEqual(e3.event_type, "THIRD")
def test_event_handler(self):
received = []
def handler(event):
received.append(event.data.get("value"))
self.sim.on("TEST", handler)
self.sim.schedule_at(5.0, "TEST", {"value": 42})
self.sim.step()
self.assertEqual(received, [42])
def test_multiple_handlers(self):
calls = []
self.sim.on("TEST", lambda e: calls.append("A"))
self.sim.on("TEST", lambda e: calls.append("B"))
self.sim.schedule_at(5.0, "TEST")
self.sim.step()
self.assertEqual(calls, ["A", "B"])
def test_wildcard_handler(self):
events = []
self.sim.on("*", lambda e: events.append(e.event_type))
self.sim.schedule_at(1.0, "A")
self.sim.schedule_at(2.0, "B")
self.sim.step()
self.sim.step()
self.assertEqual(events, ["A", "B"])
def test_run_until(self):
self.sim.schedule_at(5.0, "A")
self.sim.schedule_at(10.0, "B")
self.sim.schedule_at(15.0, "C")
self.sim.run_until(10.0)
self.assertEqual(self.sim.time, 10.0)
self.assertEqual(self.sim.peek_next_time(), 15.0)
def test_run_until_empty(self):
self.sim.schedule_at(5.0, "A")
self.sim.run_until_empty()
self.assertEqual(self.sim.time, 5.0)
self.assertIsNone(self.sim.peek_next_time())
def test_event_log(self):
self.sim.schedule_at(5.0, "TEST", {"foo": "bar"})
self.sim.step()
self.assertEqual(len(self.sim.event_log), 1)
self.assertEqual(self.sim.event_log[0]["type"], "TEST")
self.assertEqual(self.sim.event_log[0]["t"], 5.0)
def test_add_player(self):
player = Player(id="p1", name="Red", color="red")
self.sim.add_player(player)
self.assertEqual(len(self.sim.players), 1)
self.assertIn("p1", self.sim.players)
def test_get_player(self):
player = Player(id="p1", name="Red", color="red")
self.sim.add_player(player)
found = self.sim.get_player("p1")
self.assertEqual(found.name, "Red")
self.assertIsNone(self.sim.get_player("nonexistent"))
def test_get_living_players(self):
p1 = Player(id="p1", name="Red", color="red")
p2 = Player(id="p2", name="Blue", color="blue", is_alive=False)
p3 = Player(id="p3", name="Green", color="green")
self.sim.add_player(p1)
self.sim.add_player(p2)
self.sim.add_player(p3)
living = self.sim.get_living_players()
self.assertEqual(len(living), 2)
def test_players_at(self):
p1 = Player(id="p1", name="Red", color="red", position=Position(x=1000, y=400, room_id="cafeteria"))
p2 = Player(id="p2", name="Blue", color="blue", position=Position(x=1000, y=400, room_id="cafeteria"))
p3 = Player(id="p3", name="Green", color="green", position=Position(x=1200, y=700, room_id="admin"))
self.sim.add_player(p1)
self.sim.add_player(p2)
self.sim.add_player(p3)
at_cafe = self.sim.players_at("cafeteria")
self.assertEqual(len(at_cafe), 2)
if __name__ == "__main__":
unittest.main()