144 lines
4.3 KiB
Python
144 lines
4.3 KiB
Python
"""Tests for maze solving algorithms."""
|
|
|
|
import pytest
|
|
from src.solvers import DFSSolver, BFSSolver
|
|
from src.generators import RecursiveBacktrackingGenerator
|
|
|
|
|
|
SOLVERS = [DFSSolver(), BFSSolver()]
|
|
|
|
|
|
class TestSolvers:
|
|
"""Test maze solving algorithms."""
|
|
|
|
@pytest.mark.parametrize("solver", SOLVERS)
|
|
def test_solver_finds_solution(self, solver, small_maze):
|
|
"""Test that solver finds a solution."""
|
|
result = solver.solve(small_maze)
|
|
|
|
assert result['success']
|
|
assert result['path'] is not None
|
|
assert len(result['path']) > 0
|
|
assert result['path_length'] > 0
|
|
assert result['time_ms'] >= 0
|
|
|
|
@pytest.mark.parametrize("solver", SOLVERS)
|
|
def test_solution_path_validity(self, solver, medium_maze):
|
|
"""Test that solution path is valid."""
|
|
result = solver.solve(medium_maze)
|
|
|
|
assert result['success']
|
|
path = result['path']
|
|
|
|
# Path should start at maze start
|
|
assert path[0] == medium_maze.start
|
|
|
|
# Path should end at maze end
|
|
assert path[-1] == medium_maze.end
|
|
|
|
# Each step should be adjacent to previous
|
|
for i in range(len(path) - 1):
|
|
r1, c1 = path[i]
|
|
r2, c2 = path[i + 1]
|
|
|
|
# Manhattan distance should be 1
|
|
assert abs(r2 - r1) + abs(c2 - c1) == 1
|
|
|
|
@pytest.mark.parametrize("solver", SOLVERS)
|
|
def test_solver_visited_cells(self, solver, small_maze):
|
|
"""Test that solver tracks visited cells."""
|
|
result = solver.solve(small_maze)
|
|
|
|
assert 'visited' in result
|
|
assert len(result['visited']) > 0
|
|
|
|
# Solution path should be subset of visited cells
|
|
path_set = set(result['path'])
|
|
visited_set = set(result['visited'])
|
|
assert path_set.issubset(visited_set)
|
|
|
|
def test_bfs_finds_shortest_path(self):
|
|
"""Test that BFS finds shortest path."""
|
|
gen = RecursiveBacktrackingGenerator()
|
|
maze = gen.generate(10, 10, seed=42)
|
|
|
|
bfs = BFSSolver()
|
|
dfs = DFSSolver()
|
|
|
|
bfs_result = bfs.solve(maze)
|
|
dfs_result = dfs.solve(maze)
|
|
|
|
# BFS should find shortest or equal path
|
|
assert bfs_result['path_length'] <= dfs_result['path_length']
|
|
|
|
def test_solver_performance(self):
|
|
"""Test solver performance."""
|
|
gen = RecursiveBacktrackingGenerator()
|
|
maze = gen.generate(25, 25, seed=42)
|
|
|
|
for solver in SOLVERS:
|
|
result = solver.solve(maze)
|
|
# Should solve 25x25 maze quickly
|
|
assert result['time_ms'] < 1000
|
|
|
|
def test_solver_on_different_sizes(self):
|
|
"""Test solvers on different maze sizes."""
|
|
gen = RecursiveBacktrackingGenerator()
|
|
|
|
for size in [5, 10, 15, 20]:
|
|
maze = gen.generate(size, size, seed=42)
|
|
|
|
for solver in SOLVERS:
|
|
result = solver.solve(maze)
|
|
assert result['success']
|
|
assert result['path_length'] > 0
|
|
|
|
|
|
class TestDFSSolver:
|
|
"""Test DFS-specific functionality."""
|
|
|
|
def test_dfs_name(self):
|
|
"""Test DFS solver name."""
|
|
solver = DFSSolver()
|
|
assert "DFS" in solver.name or "Depth-First" in solver.name
|
|
|
|
def test_dfs_solves_maze(self, medium_maze):
|
|
"""Test DFS solves maze correctly."""
|
|
solver = DFSSolver()
|
|
result = solver.solve(medium_maze)
|
|
|
|
assert result['success']
|
|
assert result['algorithm'] == solver.name
|
|
|
|
|
|
class TestBFSSolver:
|
|
"""Test BFS-specific functionality."""
|
|
|
|
def test_bfs_name(self):
|
|
"""Test BFS solver name."""
|
|
solver = BFSSolver()
|
|
assert "BFS" in solver.name or "Breadth-First" in solver.name
|
|
|
|
def test_bfs_solves_maze(self, medium_maze):
|
|
"""Test BFS solves maze correctly."""
|
|
solver = BFSSolver()
|
|
result = solver.solve(medium_maze)
|
|
|
|
assert result['success']
|
|
assert result['algorithm'] == solver.name
|
|
|
|
def test_bfs_optimal_path(self):
|
|
"""Test BFS finds optimal path."""
|
|
gen = RecursiveBacktrackingGenerator()
|
|
|
|
# Test on multiple mazes
|
|
for seed in [42, 100, 200]:
|
|
maze = gen.generate(15, 15, seed=seed)
|
|
|
|
bfs = BFSSolver()
|
|
result = bfs.solve(maze)
|
|
|
|
# Verify path exists and is valid
|
|
assert result['success']
|
|
assert result['path_length'] > 0
|