amogus/tests/test_path_utils.py

249 lines
7.7 KiB
Python

"""
Tests for path utilities — walk interpolation.
"""
import unittest
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.engine.types import Position
from src.engine.path_utils import WalkPath, WalkState, WalkManager, PathSegment
class TestPathSegment(unittest.TestCase):
"""Tests for PathSegment."""
def test_interpolate_start(self):
segment = PathSegment(
start=Position(x=0, y=0),
end=Position(x=100, y=0),
distance=100,
cumulative_distance=100
)
pos = segment.interpolate(0.0)
self.assertEqual(pos.x, 0)
self.assertEqual(pos.y, 0)
def test_interpolate_end(self):
segment = PathSegment(
start=Position(x=0, y=0),
end=Position(x=100, y=0),
distance=100,
cumulative_distance=100
)
pos = segment.interpolate(1.0)
self.assertEqual(pos.x, 100)
self.assertEqual(pos.y, 0)
def test_interpolate_middle(self):
segment = PathSegment(
start=Position(x=0, y=0),
end=Position(x=100, y=0),
distance=100,
cumulative_distance=100
)
pos = segment.interpolate(0.5)
self.assertAlmostEqual(pos.x, 50)
self.assertAlmostEqual(pos.y, 0)
class TestWalkPath(unittest.TestCase):
"""Tests for WalkPath."""
def test_straight_line_distance(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
self.assertAlmostEqual(path.total_distance, 100.0)
def test_multi_segment_distance(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0),
Position(x=100, y=100)
])
self.assertAlmostEqual(path.total_distance, 200.0)
def test_position_at_distance_start(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
pos = path.position_at_distance(0)
self.assertEqual(pos.x, 0)
def test_position_at_distance_end(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
pos = path.position_at_distance(100)
self.assertEqual(pos.x, 100)
def test_position_at_distance_middle(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
pos = path.position_at_distance(50)
self.assertAlmostEqual(pos.x, 50)
def test_position_at_distance_multi_segment(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0),
Position(x=100, y=100)
])
# At 150 pixels: first 100 to (100,0), then 50 down
pos = path.position_at_distance(150)
self.assertAlmostEqual(pos.x, 100)
self.assertAlmostEqual(pos.y, 50)
def test_position_at_time(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
# Speed 50 px/sec, after 1 sec = 50 px traveled
pos = path.position_at_time(elapsed=1.0, speed=50.0)
self.assertAlmostEqual(pos.x, 50)
def test_time_to_complete(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
# 100 pixels at 50 px/sec = 2 seconds
self.assertAlmostEqual(path.time_to_complete(50.0), 2.0)
def test_is_complete(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
self.assertFalse(path.is_complete(elapsed=1.0, speed=50.0))
self.assertTrue(path.is_complete(elapsed=3.0, speed=50.0))
def test_progress(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
self.assertAlmostEqual(path.progress(elapsed=1.0, speed=50.0), 0.5)
self.assertAlmostEqual(path.progress(elapsed=2.0, speed=50.0), 1.0)
def test_direct_path(self):
path = WalkPath.direct(Position(x=0, y=0), Position(x=100, y=100))
self.assertAlmostEqual(path.total_distance, 141.42, places=1)
class TestWalkState(unittest.TestCase):
"""Tests for WalkState."""
def test_current_position(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
state = WalkState(
player_id="p1",
path=path,
start_time=10.0,
speed=50.0
)
# At time 11.0 (1 sec elapsed), should be at x=50
pos = state.current_position(11.0)
self.assertAlmostEqual(pos.x, 50)
def test_is_complete(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
state = WalkState(
player_id="p1",
path=path,
start_time=10.0,
speed=50.0
)
self.assertFalse(state.is_complete(11.0))
self.assertTrue(state.is_complete(13.0))
def test_arrival_time(self):
path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
state = WalkState(
player_id="p1",
path=path,
start_time=10.0,
speed=50.0
)
self.assertAlmostEqual(state.arrival_time(), 12.0)
class TestWalkManager(unittest.TestCase):
"""Tests for WalkManager."""
def setUp(self):
self.manager = WalkManager()
self.path = WalkPath(waypoints=[
Position(x=0, y=0),
Position(x=100, y=0)
])
def test_start_walk(self):
state = self.manager.start_walk("p1", self.path, 0.0, 50.0)
self.assertEqual(state.player_id, "p1")
self.assertIsNotNone(self.manager.get_walk_state("p1"))
def test_get_position(self):
self.manager.start_walk("p1", self.path, 0.0, 50.0)
pos = self.manager.get_position("p1", 1.0)
self.assertIsNotNone(pos)
self.assertAlmostEqual(pos.x, 50)
def test_get_position_no_walk(self):
pos = self.manager.get_position("nonexistent", 1.0)
self.assertIsNone(pos)
def test_is_walking(self):
self.manager.start_walk("p1", self.path, 0.0, 50.0)
self.assertTrue(self.manager.is_walking("p1", 1.0))
self.assertFalse(self.manager.is_walking("p1", 3.0))
def test_cancel_walk(self):
self.manager.start_walk("p1", self.path, 0.0, 50.0)
self.manager.cancel_walk("p1")
self.assertIsNone(self.manager.get_walk_state("p1"))
def test_cleanup_completed(self):
self.manager.start_walk("p1", self.path, 0.0, 50.0)
self.manager.start_walk("p2", self.path, 0.0, 100.0)
# p2 finishes at t=1, p1 at t=2
completed = self.manager.cleanup_completed(1.5)
self.assertEqual(len(completed), 1)
self.assertEqual(completed[0].player_id, "p2")
self.assertIsNone(self.manager.get_walk_state("p2"))
self.assertIsNotNone(self.manager.get_walk_state("p1"))
def test_get_all_positions(self):
self.manager.start_walk("p1", self.path, 0.0, 50.0)
self.manager.start_walk("p2", self.path, 0.0, 100.0)
positions = self.manager.get_all_positions(1.0)
self.assertEqual(len(positions), 2)
self.assertAlmostEqual(positions["p1"].x, 50)
self.assertAlmostEqual(positions["p2"].x, 100)
if __name__ == "__main__":
unittest.main()