# file: tests/test_models_rect.py """Unit tests for Wrdler rectangular grid support in models.py""" import pytest from wrdler.models import Coord, Word, Puzzle, GameState class TestCoordRectangular: """Tests for Coord.in_bounds_rect() method""" def test_in_bounds_rect_valid_coords(self): """Test that valid coordinates pass boundary check""" # 6 rows x 8 cols (Wrdler grid) assert Coord(0, 0).in_bounds_rect(6, 8) is True assert Coord(5, 7).in_bounds_rect(6, 8) is True # Bottom-right corner assert Coord(3, 4).in_bounds_rect(6, 8) is True # Middle def test_in_bounds_rect_invalid_coords(self): """Test that out-of-bounds coordinates fail boundary check""" # 6 rows x 8 cols assert Coord(6, 0).in_bounds_rect(6, 8) is False # Row too large assert Coord(0, 8).in_bounds_rect(6, 8) is False # Col too large assert Coord(-1, 0).in_bounds_rect(6, 8) is False # Negative row assert Coord(0, -1).in_bounds_rect(6, 8) is False # Negative col def test_in_bounds_backward_compatibility(self): """Test that legacy in_bounds() still works for square grids""" assert Coord(0, 0).in_bounds(12) is True assert Coord(11, 11).in_bounds(12) is True assert Coord(12, 0).in_bounds(12) is False class TestPuzzleRectangular: """Tests for Puzzle with rectangular grid dimensions""" def test_puzzle_default_dimensions(self): """Test that Puzzle defaults to Wrdler dimensions (6x8)""" puzzle = Puzzle(words=[]) assert puzzle.grid_rows == 6 assert puzzle.grid_cols == 8 def test_puzzle_custom_dimensions(self): """Test that Puzzle can use custom dimensions""" puzzle = Puzzle(words=[], grid_rows=10, grid_cols=12) assert puzzle.grid_rows == 10 assert puzzle.grid_cols == 12 def test_puzzle_no_radar_field(self): """Test that radar field is removed from Puzzle""" puzzle = Puzzle(words=[]) assert not hasattr(puzzle, 'radar') class TestGameStateRectangular: """Tests for GameState with rectangular grid support""" def test_gamestate_default_dimensions(self): """Test that GameState defaults to Wrdler dimensions (6x8)""" state = GameState() assert state.grid_rows == 6 assert state.grid_cols == 8 def test_gamestate_free_letters_field(self): """Test that free_letters field exists and is initialized""" state = GameState() assert hasattr(state, 'free_letters') assert isinstance(state.free_letters, set) assert len(state.free_letters) == 0 def test_gamestate_free_letters_used_field(self): """Test that free_letters_used field exists and is initialized to 0""" state = GameState() assert hasattr(state, 'free_letters_used') assert state.free_letters_used == 0 def test_gamestate_grid_size_property_square(self): """Test grid_size property works for square grids""" state = GameState(grid_rows=12, grid_cols=12) assert state.grid_size == 12 def test_gamestate_grid_size_property_rectangular_raises(self): """Test grid_size property raises ValueError for rectangular grids""" state = GameState(grid_rows=6, grid_cols=8) with pytest.raises(ValueError, match="grid_size not applicable"): _ = state.grid_size class TestWordHorizontalOnly: """Tests for Word with horizontal-only placement (Wrdler requirement)""" def test_word_horizontal_valid(self): """Test that horizontal words are created correctly""" word = Word(text="WORD", start=Coord(0, 0), direction="H") assert word.direction == "H" assert len(word.cells) == 4 assert word.cells[0] == Coord(0, 0) assert word.cells[3] == Coord(0, 3) def test_word_horizontal_fits_in_8_cols(self): """Test that words fit within 8-column grid""" # Max length word (8 letters) starting at column 0 word = Word(text="TESTWORD", start=Coord(0, 0), direction="H") assert all(c.in_bounds_rect(6, 8) for c in word.cells) # 4-letter word starting at column 4 (last cell at column 7) word = Word(text="TEST", start=Coord(0, 4), direction="H") assert all(c.in_bounds_rect(6, 8) for c in word.cells) if __name__ == "__main__": pytest.main([__file__, "-v"])