"""All tests for the Sudoku Solver.""" import unittest import copy from typing import List from main import solve_board from board import Board from square import Square class TestMain(unittest.TestCase): """TestCase for the main file.""" def setUp(self): self.strings: List[str] = [( ".2..785..\n" "4...52...\n" "..1..3.2.\n" ".....1...\n" "7348.526.\n" "2.9.67..5\n" ".687..3.9\n" "342.1.7..\n" "19..86..2\n" ), ( "..1..6435\n" ".....1...\n" ".5.47.98.\n" "..2.8.7.9\n" "..87..612\n" ".64.1..5.\n" "91.3428.7\n" ".27....9.\n" "6.3.9.5..\n" ), ( ".....6...\n" "..2.35.8.\n" "....2..13\n" ".2....19.\n" "93....7..\n" "5....4...\n" "1......7.\n" ".7...142.\n" ".9.4.3...\n" ), ( "...82....\n" "...6.9..1\n" "9.4..1...\n" ".9.7..28.\n" ".......57\n" "7.5......\n" ".78962..5\n" ".2..8.7.3\n" ".6..74.2.\n" ), ( "4......1.\n" ".15.4.6..\n" ".....7...\n" "...21...8\n" "...734..2\n" ".3..8....\n" "8.19...45\n" ".4....7..\n" "2....3...\n" ), ( "3........\n" ".6...791.\n" ".....325.\n" ".19.645..\n" ".......6.\n" ".85......\n" "...8.....\n" "..1..97..\n" "47..5....\n" )] def test_iterate_over_various_board_difficulties(self): """Run the solver on different boards.""" for string in self.strings[:-1]: self.assertIsInstance(string, str) solve_board(string) class TestBoard(unittest.TestCase): """TestCase for Board.""" def setUp(self): self.string = ( ".2..785..\n" "4...52...\n" "..1..3.2.\n" ".....1...\n" "7348.526.\n" "2.9.67..5\n" ".687..3.9\n" "342.1.7..\n" "19..86..2\n" ) self.board = Board(self.string, debug=False) def test_lines_are_correctly_initialized(self): """There should be 9 lines, each a set of its values.""" self.assertIsInstance(self.board.lines, list) self.assertEqual(len(self.board.lines), 9) for line in self.board.lines: self.assertIsInstance(line, set) self.assertNotEqual(len(line), 0) def test_columns_are_correctly_initialized(self): """There should be 9 columns, each a set of its values.""" self.assertIsInstance(self.board.columns, list) self.assertEqual(len(self.board.columns), 9) for column in self.board.columns: self.assertIsInstance(column, set) self.assertNotEqual(len(column), 0) def test_grids_are_correctly_initialized(self): """There should be 9 grids, each a set of its values.""" self.assertIsInstance(self.board.grids, list) self.assertEqual(len(self.board.grids), 9) for grid in self.board.grids: self.assertIsInstance(grid, set) self.assertNotEqual(len(grid), 0) def test_squares_are_correctly_initialized(self): """There should be 81 squares, each a Square object.""" self.assertIsInstance(self.board.squares, list) self.assertEqual(len(self.board.squares), 81) for square in self.board.squares: self.assertIsInstance(square, Square) self.assertIsInstance(square.values, set) self.assertLess(len(square.values), 2) def test_compute_possible_values(self): """For each square, values are added if the square was empty. If the square was not empty, it had only one value. Values should not be added if the square was not empty. """ empty_squares = 0 squares_with_one_value = 0 for square in self.board.squares: if len(square.values) == 0: empty_squares += 1 # We already tested that if len(square.values) != 0 it must be 1 else: squares_with_one_value += 1 old_squares = copy.deepcopy(self.board.squares) self.board.compute_possible_values() new_squares = copy.deepcopy(self.board.squares) self.assertEqual(len(old_squares), 81) self.assertEqual(len(new_squares), 81) for i in range(81): if len(old_squares[i].values) != 1: self.assertLess( len(old_squares[i].values), len(new_squares[i].values) ) else: self.assertEqual( len(old_squares[i].values), len(new_squares[i].values) ) squares_with_more_than_one_value = 0 for square in self.board.squares: self.assertGreater(len(square.values), 0) if len(square.values) > 1: squares_with_more_than_one_value += 1 # Maybe only one value was computed. self.assertLessEqual( squares_with_more_than_one_value, empty_squares ) def test_get_square(self): """Searching for a square returns the correct square.""" valid_square, square_nb = self.board.get_square(3, 4) self.assertEqual(valid_square.coordinates, (3, 4)) self.assertIn(square_nb, range(81)) valid_square, square_nb = self.board.get_square(8, 0) self.assertEqual(valid_square.coordinates, (8, 0)) self.assertIn(square_nb, range(81)) valid_square, square_nb = self.board.get_square(0, 0) self.assertEqual(valid_square.coordinates, (0, 0)) self.assertIn(square_nb, range(81)) invalid_square, square_nb = self.board.get_square(12, 5) self.assertIsNone(invalid_square) self.assertIsNone(square_nb) invalid_square, square_nb = self.board.get_square(0, 34) self.assertIsNone(invalid_square) self.assertIsNone(square_nb) invalid_square, square_nb = self.board.get_square(55, 120) self.assertIsNone(invalid_square) self.assertIsNone(square_nb) invalid_square, square_nb = self.board.get_square(-1, 2) self.assertIsNone(invalid_square) self.assertIsNone(square_nb) def test_update_board(self): """Updated board is consistent with board.string.""" old_string: str = self.board.string self.board.update_board() self.assertEqual(old_string, self.board.string) old_string = old_string.replace('\n', '') self.assertEqual(len(old_string), 81) for square_nb, square in enumerate(self.board.squares): if len(square.values) == 1: self.assertEqual( str(square.values)[2:-2], old_string[square_nb] ) def test_update_string(self): """Updated board.string is consistent with board.""" old_string: str = self.board.string self.board.compute_possible_values() new_string: str = self.board.update_string() self.assertEqual(len(self.string), 90) self.assertEqual(len(old_string), 90) self.assertEqual(len(new_string), 90) self.assertEqual(len(self.board.string), 90) self.assertIs(self.board.string, new_string) empty_squares = 0 for square in self.board.squares: if len(square.values) != 1: empty_squares += 1 self.assertEqual(empty_squares, self.board.string.count('.')) class TestSquare(unittest.TestCase): """TestCase for Square.""" def setUp(self): content = '.' self.board = [ Square(line, column, content) for line in range(9) for column in range(9) ] self.assertEqual(len(self.board), 81) def test_grid_is_correctly_computed(self): """Square.grid is correctly computed for all values.""" correct_grids = ( "000111222" "000111222" "000111222" "333444555" "333444555" "333444555" "666777888" "666777888" "666777888" ) for i, square in enumerate(self.board): self.assertEqual(square.grid, int(correct_grids[i])) if __name__ == '__main__': unittest.main()