Sudoku Solver: Add functional tests and fix Unit Tests

This commit is contained in:
CherryKitten 2022-11-12 10:35:00 +01:00
parent 70cee77a95
commit 0d2e39e7ba
Signed by: sammy
GPG key ID: 0B696A86A853E955
4 changed files with 237 additions and 76 deletions

View file

@ -1,22 +1,41 @@
export const puzzlesAndSolutions = [
[
'1.5..2.84..63.12.7.2..5.....9..1....8.2.3674.3.7.2..9.47...8..1..16....926914.37.',
'135762984946381257728459613694517832812936745357824196473298561581673429269145378'
"1.5..2.84..63.12.7.2..5.....9..1....8.2.3674.3.7.2..9.47...8..1..16....926914.37.",
"135762984946381257728459613694517832812936745357824196473298561581673429269145378",
],
[
'5..91372.3...8.5.9.9.25..8.68.47.23...95..46.7.4.....5.2.......4..8916..85.72...3',
'568913724342687519197254386685479231219538467734162895926345178473891652851726943'
"5..91372.3...8.5.9.9.25..8.68.47.23...95..46.7.4.....5.2.......4..8916..85.72...3",
"568913724342687519197254386685479231219538467734162895926345178473891652851726943",
],
[
'..839.7.575.....964..1.......16.29846.9.312.7..754.....62..5.78.8...3.2...492...1',
'218396745753284196496157832531672984649831257827549613962415378185763429374928561'
"..839.7.575.....964..1.......16.29846.9.312.7..754.....62..5.78.8...3.2...492...1",
"218396745753284196496157832531672984649831257827549613962415378185763429374928561",
],
[
'.7.89.....5....3.4.2..4..1.5689..472...6.....1.7.5.63873.1.2.8.6..47.1..2.9.387.6',
'473891265851726394926345817568913472342687951197254638734162589685479123219538746'
".7.89.....5....3.4.2..4..1.5689..472...6.....1.7.5.63873.1.2.8.6..47.1..2.9.387.6",
"473891265851726394926345817568913472342687951197254638734162589685479123219538746",
],
[
'82..4..6...16..89...98315.749.157.............53..4...96.415..81..7632..3...28.51',
'827549163531672894649831527496157382218396475753284916962415738185763249374928651'
]
"82..4..6...16..89...98315.749.157.............53..4...96.415..81..7632..3...28.51",
"827549163531672894649831527496157382218396475753284916962415738185763249374928651",
],
];
export const invalidStrings = [
"135762984946-8125772845961369451783281293674535B82419647329856158167342926:145378",
'56891372434268751"%=7254386685479231219538467734162895926345178473891652851726943',
"/////////////////////////////////////////////////////////////////////////////////",
"NyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyan.",
];
export const unsolvableStrings = [
"115..2.84..63.12.7.2..5.....9..1....8.2.3674.3.7.2..9.420..8..1..16....926969.37.",
"4206942069.......................................................................",
"111111111111111111111111111111111111111111111111111111111111111111111111111111111",
];
export const wrongLengthStrings = [
"123456",
"9999999.9999992",
"1.5..2.84..63.12.7.2..5.....9..1....8.2.3674.3.7.2..9.47...8..1..16....926914.37.5..91372.3...8.5.9.9.25..8.68.47.23...95..46.7.4.....5.2.......4..8916..85.72...3",
];

View file

@ -41,7 +41,7 @@ class SudokuSolver {
checkRegionPlacement(puzzleString, row, column, value) {}
solve(puzzleString) {
return false;
return { error: "test" };
}
}

View file

@ -1,19 +1,11 @@
const chai = require("chai");
const assert = chai.assert;
import { puzzlesAndSolutions } from "../controllers/puzzle-strings";
const invalidStrings = [
"135762984946-8125772845961369451783281293674535B82419647329856158167342926:145378",
'56891372434268751"%=7254386685479231219538467734162895926345178473891652851726943',
"/////////////////////////////////////////////////////////////////////////////////",
"NyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyanNyan.",
];
const unsolvableStrings = [
"115..2.84..63.12.7.2..5.....9..1....8.2.3674.3.7.2..9.420..8..1..16....926969.37.",
"4206942069.......................................................................",
"111111111111111111111111111111111111111111111111111111111111111111111111111111111",
];
import {
puzzlesAndSolutions,
invalidStrings,
unsolvableStrings,
wrongLengthStrings,
} from "../controllers/puzzle-strings";
const Solver = require("../controllers/sudoku-solver.js");
let solver = new Solver();
@ -35,10 +27,12 @@ suite("Unit Tests", () => {
}
});
test("Logic handles a puzzle string that is not 81 characters in length", () => {
assert.equal(
solver.validate("135762984946145378").error,
"Expected puzzle to be 81 characters long"
);
for (let i in wrongLengthStrings) {
assert.equal(
solver.validate(wrongLengthStrings[i]).error,
"Expected puzzle to be 81 characters long"
);
}
});
});
suite("Placement Checks", () => {
@ -106,7 +100,6 @@ suite("Unit Tests", () => {
suite("Solver", () => {
test("Valid puzzle strings pass the solver", () => {
for (let i in puzzlesAndSolutions) {
console.log(i);
assert.equal(
solver.solve(puzzlesAndSolutions[i][1]),
puzzlesAndSolutions[i][1]
@ -116,21 +109,9 @@ suite("Unit Tests", () => {
test("Invalid puzzle strings fail the solver", () => {
for (let i in invalidStrings) {
assert.equal(
solver.solve(invalidStrings[i].error),
"Invalid characters in puzzle",
"invalid characters" + invalidStrings[i]
);
}
assert.equal(
solver.solve("135762984946145378").error,
"Expected puzzle to be 81 characters long",
"wrong length"
);
for (let i in unsolvableStrings) {
assert.equal(
solver.solve().error,
"Puzzle cannot be solved",
"not solvable" + unsolvableStrings[i]
solver.solve(invalidStrings[i]),
{ error: "Invalid characters in puzzle" },
"invalid characters"
);
}
});
@ -145,12 +126,3 @@ suite("Unit Tests", () => {
});
});
});
/*
TODO:
Valid puzzle strings pass the solver
*/

View file

@ -2,27 +2,197 @@ const chai = require("chai");
const chaiHttp = require("chai-http");
const assert = chai.assert;
const server = require("../server");
import {
puzzlesAndSolutions,
invalidStrings,
unsolvableStrings,
wrongLengthStrings,
} from "../controllers/puzzle-strings";
chai.use(chaiHttp);
suite("Functional Tests", () => {});
/*
TODO:
Solve a puzzle with valid puzzle string: POST request to /api/solve
Solve a puzzle with missing puzzle string: POST request to /api/solve
Solve a puzzle with invalid characters: POST request to /api/solve
Solve a puzzle with incorrect length: POST request to /api/solve
Solve a puzzle that cannot be solved: POST request to /api/solve
Check a puzzle placement with all fields: POST request to /api/check
Check a puzzle placement with single placement conflict: POST request to /api/check
Check a puzzle placement with multiple placement conflicts: POST request to /api/check
Check a puzzle placement with all placement conflicts: POST request to /api/check
Check a puzzle placement with missing required fields: POST request to /api/check
Check a puzzle placement with invalid characters: POST request to /api/check
Check a puzzle placement with incorrect length: POST request to /api/check
Check a puzzle placement with invalid placement coordinate: POST request to /api/check
Check a puzzle placement with invalid placement value: POST request to /api/check
*/
suite("Functional Tests", () => {
suite("Solving puzzles", () => {
test("Solve a puzzle with valid puzzle string: POST request to /api/solve", (done) => {
for (let i in puzzlesAndSolutions) {
chai
.request(server)
.post("/api/solve")
.send({ puzzle: puzzlesAndSolutions[i][0] })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.solution, puzzlesAndSolutions[i][1]);
done();
});
}
});
test("Solve a puzzle with missing puzzle string: POST request to /api/solve", (done) => {
for (let i in puzzlesAndSolutions) {
chai
.request(server)
.post("/api/solve")
.send({})
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Required field missing");
done();
});
}
});
test("Solve a puzzle with invalid characters: POST request to /api/solve", (done) => {
for (let i in invalidStrings) {
chai
.request(server)
.post("/api/solve")
.send({ puzzle: invalidStrings[i] })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Invalid characters in puzzle");
done();
});
}
});
test("Solve a puzzle with incorrect length: POST request to /api/solve", (done) => {
for (let i in wrongLengthStrings) {
chai
.request(server)
.post("/api/solve")
.send({ puzzle: wrongLengthStrings[i] })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(
res.body.error,
"Expected puzzle to be 81 charcters long"
);
done();
});
}
});
test("Solve a puzzle that cannot be solved: POST request to /api/solve", (done) => {
for (let i in unsolvableStrings) {
chai
.request(server)
.post("/api/solve")
.send({ puzzle: unsolvableStrings[i] })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Puzzle cannot be solved");
done();
});
}
});
});
suite("Placement Checks", () => {
test("Check a puzzle placement with all fields: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0][0], coordinate: "A2", value: 3 })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.valid, true);
done();
});
});
test("Check a puzzle placement with single placement conflict: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0][0], coordinate: "A2", value: 4 })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.valid, false);
assert.include(res.body.conflict, "row");
assert.notInclude(res.body.conflict, "region");
assert.notInclude(res.body.conflict, "column");
done();
});
});
test("Check a puzzle placement with multiple placement conflicts: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0][0], coordinate: "A2", value: 1 })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.valid, false);
assert.include(res.body.conflict, "row");
assert.include(res.body.conflict, "region");
assert.notInclude(res.body.conflict, "column");
done();
});
});
test("Check a puzzle placement with all placement conflicts: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0][0], coordinate: "A2", value: 2 })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.valid, false);
assert.include(res.body.conflict, "row");
assert.include(res.body.conflict, "region");
assert.include(res.body.conflict, "column");
done();
});
});
test("Check a puzzle placement with missing required fields: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0][0], coordinate: "A2" })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Required field(s) missing");
done();
});
});
test("Check a puzzle placement with invalid characters: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: invalidStrings[0], coordinate: "A2", value: "3" })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Invalid characters in puzzle");
done();
});
});
test("Check a puzzle placement with incorrect length: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: wrongLengthStrings[0], coordinate: "A2", value: "3" })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(
res.body.error,
"Expected puzzle to be 81 characters long"
);
done();
});
});
test("Check a puzzle placement with invalid placement coordinate: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0], coordinate: "Z11", value: "3" })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Invalid coordinate");
done();
});
});
test("Check a puzzle placement with invalid placement value: POST request to /api/check", (done) => {
chai
.request(server)
.post("/api/check")
.send({ puzzle: puzzlesAndSolutions[0], coordinate: "A2", value: "22" })
.end((err, res) => {
assert.equal(res.status, 200);
assert.equal(res.body.error, "Invalid value");
done();
});
});
});
});