def test_get_next_with_last_child_returns_none(): """ Verifies that `get_next` on a point with its last possible child returns None. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) grid[1][1].child = grid[1][0] assert get_next(grid[1][1]) is None
def test_observability_with_point_mutations_notifies_observers(): """Verifies that grids forward point mutation notifications to their observers""" grid = Grid(((-1, -1), (-1, -1))) point = grid[0][0] # Instantiate and register an incrementor as an example observer of the grid incrementor = Incrementor() grid.register(incrementor.increment) # Mutate a point on the grid an arbitrary number of times # Verify that the incrementor indeed increments in response to each point mutation assert incrementor.count == 0 for i in range(1, 4): # Solely accessing the point's child field should not notify observers assert point.child is None # Mutating the point's child field should indeed notify observers point.child = None assert incrementor.count == i
def test_get_next_with_one_remaining_segment_skips_point_on_new_segment(): """ Verifies that `get_next`, on last allowed segment, skips points on new segments. """ grid = Grid(((-1, -1, -1, -1), (1, -1, -1, 0))) grid[1][0].child = grid[1][1] assert get_next(grid[1][1]).location == (1, 2)
def test_is_option_with_new_segment_and_one_remaining_segment_returns_false(): """Verifies that a point not on the last allowed segment is not an option.""" grid = Grid(((1, -1, -1, 0), (-1, -1, -1, -1))) current = grid[0][1] # Set partial path to current grid[0][0].child = current assert not is_option(current, grid[1][1])
def test_remaining_segments_with_source_returns_type(): """ Verifies that the number of remaining segments of a source point is what was set. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) assert grid[0][0].remaining_segments == 3 assert grid[1][1].remaining_segments == 2
def test_is_on_different_segment_with_same_segment_returns_false(): """ Verifies that `is_on_different_segment` is false for a point on the same segment. """ grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0))) grid[0][0].child = grid[0][1] assert not grid[0][2].is_on_different_segment(grid[0][1])
def test_is_on_different_segment_with_different_segment_returns_true(): """ Verifies that `is_on_different_segment` is true for a point on a new segment. """ grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0))) grid[0][0].child = grid[0][1] assert grid[1][1].is_on_different_segment(grid[0][1])
def test_parent_with_parent_returns_correct_point(): """Verifies that parent property methods function for a point with a parent.""" grid = Grid(((2, -1), (1, 0))) parent, child = grid[0][0], grid[0][1] parent.child = child assert child.has_parent() assert child.parent is parent
def test_get_next_with_first_of_multiple_children_returns_next_child(): """ Verifies that `get_next` on a point with a child returns the correct next point. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) grid[1][1].child = grid[0][1] assert get_next(grid[1][1]).location == (1, 2)
def test_algorithm_with_unsolvable_example_returns_false(strategy): """Verifies that each algorithm returns false for an unsolvable puzzle.""" grid = Grid(((2, -1, -1), (-1, -1, -1), (-1, -1, -1))) assert not strategy(grid) # Test that grid is clear for row in grid: for point in row: assert point.is_source() or point.is_open()
def test_str_with_complete_board_returns_correct_string(): """Verifies that the string representation of a solved grid is correct.""" grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0))) # Set path from "2" draw_path(grid, ((1, 1), (1, 0), (2, 0))) assert str(grid) == GRID_STRING_2
def test_is_on_different_segment_with_source_returns_false(): """ Verifies that `is_on_different_segment` always reports false against sources. """ grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0))) source = grid[0][0] assert not grid[0][1].is_on_different_segment(source) assert not grid[1][0].is_on_different_segment(source)
def test_parent_with_sink_returns_none(): """Verifies that a sink point never reports that it has a parent.""" grid = Grid(((2, -1), (1, 0))) source, pipe, sink = grid[0][0], grid[0][1], grid[1][1] source.child = pipe pipe.child = sink assert not sink.has_parent() assert sink.parent is None
def test_is_option_with_new_segment_sink_and_two_remaining_segments_returns_true( ): """Verifies that a sink not on the second to last allowed segment is an option.""" grid = Grid(((2, -1, 0), (-1, 0, -1))) current = grid[0][1] # Set partial path to current grid[0][0].child = current assert is_option(current, grid[1][1])
def test_get_next_with_no_child_and_all_open_neighbors_returns_first_available( ): """ Verifies that `get_next` returns the first available neighbor if all are open. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) assert get_next(grid[0][0]).location == (0, 1) assert get_next(grid[1][1]).location == (0, 1)
def test_is_option_with_same_segment_sink_and_one_remaining_segment_returns_true( ): """Verifies that a sink on the last allowed segment is an option.""" grid = Grid(((1, -1, 0), (-1, 0, -1))) current = grid[0][1] # Set partial path to current grid[0][0].child = current assert is_option(current, grid[0][2])
def test_is_option_with_open_neighbor_returns_true(): """Verifies that `is_option` correctly identifies when a point is an option.""" grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) current = grid[1][1] assert is_option(current, grid[0][1]) assert is_option(current, grid[1][2]) assert is_option(current, grid[2][1]) assert is_option(current, grid[1][0])
def test_get_next_with_no_child_and_some_open_neighbors_returns_first_available( ): """ Verifies that `get_next` returns the first available neighbor if some are open. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set partial path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2))) assert get_next(grid[1][1]).location == (2, 1)
def test_is_head_complete_puzzle_returns_no_heads(): """Verifies that a completely solved puzzle has no remaining heads.""" grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0))) # Set path from "2" draw_path(grid, ((1, 1), (1, 0), (2, 0))) # Test that there are no heads anymore assert not [point for row in grid for point in row if point.is_head()]
def test_is_open_with_pipe_conditional_on_parent(): """Verifies that a pipe reports being open if and only if it's parentless.""" grid = Grid(((2, -1), (1, 0))) pipe = grid[0][1] # Test pipe without parent is open assert pipe.is_open() # Test pipe with parent is not open grid[0][0].child = pipe assert not pipe.is_open()
def test_get_head_with_complete_puzzle_returns_none(): """Verifies that a completely solved puzzle reports having no heads.""" grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0))) # Set path from "2" draw_path(grid, ((1, 1), (1, 0), (2, 0))) assert not has_head(grid) assert get_head(grid) is None
def test_get_next_with_greater_than_two_remaining_segments_skips_sinks(): """ Verifies that `get_next` skips a sink not on the last allowed segment. """ grid = Grid(((-1, 0, -1), (4, -1, 0), (-1, -1, -1))) current = grid[1][1] # Set partial path to current grid[1][0].child = current assert get_next(current).location == (2, 1)
def test_solve_with_real_strategies_solves_grid(strategy): """Verifies that `solve` using real strategies solves a real grid.""" grid = Grid(((2, -1), (0, 0))) assert solve(grid, strategy=strategy) # Test all points in component-wise order assert grid[0][0].child.location == (0, 1) assert grid[0][1].child.location == (1, 1) assert grid[1][0].is_open() assert grid[1][1].is_open()
def test_get_neighbors_with_some_neighbors_returns_correct_points(): """Verifies that the neighbor method functions for points with some neighbors.""" grid = Grid(((-1, -1), (-1, -1))) point = grid[0][0] expected_neighbors = (grid[0][1], grid[1][0]) actual_neighbors = point.get_neighbors() assert len(expected_neighbors) == len(actual_neighbors) == 2 for expected_neighbor, actual_neighbor in zip(expected_neighbors, actual_neighbors): assert expected_neighbor is actual_neighbor
def test_reveal_with_complete_puzzle_prints_but_does_not_backtrack(capsys): """Verifies that `reveal` on a complete puzzle prints as expected.""" grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0))) # Set path from "2" draw_path(grid, ((1, 1), (1, 0), (2, 0))) # Test reveal with no delay reveal(grid, delay=0) assert capsys.readouterr().out == f"\x1b[J{SOLVED_GRID_STRING}\n"
def test_get_neighbor_with_neighbor_present_returns_correct_point(): """Verifies that the neighbor method functions for a point with neighbors.""" grid = Grid(((-1, -1, -1), (-1, -1, -1), (-1, -1, -1))) point = grid[1][1] neighbors = (grid[0][1], grid[1][2], grid[2][1], grid[1][0]) # Test that the correct neighbor exists in each direction for i, direction in enumerate(Direction): assert point.has_neighbor(direction) neighbor = point.get_neighbor(direction) assert neighbor is neighbors[i]
def test_is_option_with_unavailable_neighbor_returns_false(): """ Verifies that `is_option` correctly identifies when a point is not an option. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Set partial path from "3" draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2))) # Test neighbors on partial path from "3" current = grid[1][1] assert not is_option(current, grid[0][1]) assert not is_option(current, grid[1][2])
def test_remaining_segments_with_first_segment_returns_no_change(): """ Verifies that a source's child has an unchanged number of remaining segments. """ grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1))) # Test first point on first segment grid[0][0].child = grid[0][1] assert grid[0][1].remaining_segments == 3 # Test second point on first segment grid[0][1].child = grid[0][2] assert grid[0][2].remaining_segments == 3
def test_solve_with_default_arguments_solves_grid_silently(capsys): """Verifies that `solve` using default arguments solves a real grid silently.""" grid = Grid(((2, -1), (0, 0))) assert solve(grid) # Test all points in component-wise order assert grid[0][0].child.location == (0, 1) assert grid[0][1].child.location == (1, 1) assert grid[1][0].is_open() assert grid[1][1].is_open() # Verify that nothing was printed to the console assert capsys.readouterr().out == ""
def august_9_grid(): """Test fixture that creates the August 9 Gas Lines puzzle.""" # Real NYT Magazine Gas Lines puzzle from the August 9, 2020 issue return Grid(( (2, -1, 0, -1, 2, -1, -1), (-1, 4, -1, -1, -1, -1, 4), (-1, -1, -1, -1, 2, -1, -1), (-1, 0, 1, -1, -1, 0, -1), (-1, -1, -1, -1, -1, -1, -1), (-1, 3, 0, -1, -1, 4, -1), (4, -1, -1, -1, -1, -1, -1), ), )