def test_solver(self): """Use PuzzleTester class to test SudokuSolver""" for method in su.SOLVERS: with self.subTest(f"method: {method}"): solver = su.SudokuSolver(method=method) self.assertEqual(5, self.pt.num_test_cases()) self.assertEqual(5, self.pt.run_tests(solver))
def test_results(self): """Check test results""" solver = su.SudokuSolver() self.assertEqual(3, len(self.pt.get_test_results())) self.pt.run_tests(solver) self.assertEqual(4, len(self.pt.get_test_results())) self.assertEqual(1, len(self.pt.get_solver_labels())) results = self.pt.get_test_results() newpt = pt.PuzzleTester(puzzle_class=su.SudokuPuzzle) newpt.set_test_results(results) self.assertEqual(self.pt.get_test_results(), newpt.get_test_results())
def test_all_solvers_all_puzzles(self): """Test that all available solvers can solve all test puzzles in sudoku.py""" for x in su.SOLVERS: if x == 'backtracking': continue solver = su.SudokuSolver(method=x) for p in su.SAMPLE_PUZZLES: with self.subTest(f"Method {x} on puzzle {p['label']}"): puz = su.SudokuPuzzle( starting_grid=ls.from_string(p['puzzle'])) self.assertTrue(solver.solve(puz)) self.assertTrue(puz.is_solved()) return
def test_all_solvers(self): """Test that all available solvers are supported""" for x in su.SOLVERS: with self.subTest(f"Method {x}"): solver = su.SudokuSolver(method=x) self.p.init_puzzle(EASY_PUZZLE) self.assertTrue(solver.solve(self.p)) self.assertTrue(self.p.is_solved()) self.p.init_puzzle(HARD_PUZZLE) self.assertTrue(solver.solve(self.p)) self.assertTrue(self.p.is_solved()) return
def test_solver(self): """SudokuSolver can be vaguely useful""" with self.subTest("Default solver works"): solver = su.SudokuSolver() self.p.init_puzzle(EASY_PUZZLE) self.assertTrue(solver.solve(self.p)) self.p.init_puzzle(HARD_PUZZLE) self.assertTrue(solver.solve(self.p)) with self.subTest("Bad solver raises exception"): self.assertRaises(ValueError, su.SudokuSolver, method="banana") return
def test_all_solvers_multisolution_puzzles(self): """Test all solvers on how they handle puzzles with multiple solutions""" for m in su.SOLVERS: solver = su.SudokuSolver(method=m) for i, puz in enumerate(MULTI_SOLUTION_STRINGS): with self.subTest(f"Method {m}; Multi-solution puzzle {i}"): # Failure here would be test data error self.p.init_puzzle(ls.from_string(puz)) self.assertTrue(self.p.is_valid()) self.assertFalse(self.p.is_solved()) # Requirement is to return *a* solution self.assertTrue(solver.solve(self.p)) self.assertTrue(self.p.is_solved()) # TODO: Mechanism to report multiple solutions? SAT could # do it. Others might take too long. return
def test_all_solvers_unsolvable_puzzles(self): """Test all solvers on how they handle unsolvable puzzles""" for m in su.SOLVERS: solver = su.SudokuSolver(method=m) for i, puz in enumerate(UNSOLVABLE_STRINGS): with self.subTest(f"Method {m}; Unsolvable puzzle {i}"): # These "unsolvable" puzzles are still valid initially self.p.init_puzzle(ls.from_string(puz)) self.assertTrue(self.p.is_valid()) self.assertFalse(self.p.is_solved()) # Check method correctly reports it cannot be solved self.assertFalse(solver.solve(self.p)) # Solver should leave puzzle in valid, but unsolved state self.assertTrue(self.p.is_valid()) self.assertFalse(self.p.is_solved()) return
def test_all_solvers_all_sizes(self): """Solvers can solve different sizes of puzzles""" for m in su.SOLVERS: solver = su.SudokuSolver(method=m) for i, puz in enumerate(TEST_PUZZLE_STRINGS): # Skip backtracking on larger puzzles if m == 'backtracking' and len(puz) > 81: continue with self.subTest(f"Method {m}; Puzzle {i} (len={len(puz)})"): p = su.SudokuPuzzle(starting_grid=ls.from_string(puz)) s = su.SudokuPuzzle( starting_grid=ls.from_string(TEST_SOLUTION_STRINGS[i])) self.assertTrue(p.is_valid()) self.assertFalse(p.is_solved()) self.assertTrue(solver.solve(p)) self.assertTrue(p.is_solved()) self.assertEqual(str(s), str(p)) return
def test_callback(self): """Test that callback is called...back""" self._callback_called = False solver = su.SudokuSolver() self.pt.run_tests(solver, callback=self.callback) self.assertTrue(self._callback_called)