Home Manual Reference Source Test

tests/solving.test.js

  1. import { describe, it, expect, vi, afterEach } from "vitest";
  2. import { MOCKS, STUBS } from "./api.js";
  3. const { init, solvers, Model } = await MOCKS.minizinc;
  4. const { initSolvers, solveModel } =
  5. await import("../src/controller/solving.js");
  6. /** @test {initSolvers} */
  7. describe("initSolvers", () => {
  8. afterEach(() => {
  9. vi.clearAllMocks();
  10. vi.restoreAllMocks();
  11. });
  12. /** @test {initSolvers} */
  13. it("calls init then returns the available solvers", async () => {
  14. init.mockResolvedValue(undefined);
  15. solvers.mockResolvedValue([{ id: "gecode" }]);
  16. expect(await initSolvers()).toEqual([{ id: "gecode" }]);
  17. expect(init).toHaveBeenCalledOnce();
  18. });
  19. });
  20. /** @test {solveModel} */
  21. describe("solveModel", () => {
  22. afterEach(() => {
  23. vi.clearAllMocks();
  24. vi.restoreAllMocks();
  25. });
  26. /** @test {solveModel} */
  27. it("returns the solution, statistics and status; logs info for non-OK status", async () => {
  28. const okResult = {
  29. solution: { x: 1 },
  30. statistics: { time: 10 },
  31. status: "OPTIMAL_SOLUTION",
  32. };
  33. const mockModel = STUBS.minizincModel(Model, Promise.resolve(okResult));
  34. const [infoSpy] = STUBS.silenceConsole("info");
  35. expect(await solveModel("t.mzn", "var 1..3: x;", "gecode")).toEqual(
  36. okResult,
  37. );
  38. expect(mockModel.addFile).toHaveBeenCalledWith("t.mzn", "var 1..3: x;");
  39. expect(mockModel.solve).toHaveBeenCalledWith({
  40. options: { solver: "gecode", statistics: true },
  41. });
  42. expect(infoSpy).not.toHaveBeenCalled();
  43. STUBS.minizincModel(
  44. Model,
  45. Promise.resolve({
  46. solution: null,
  47. statistics: {},
  48. status: "UNSATISFIABLE",
  49. }),
  50. );
  51. expect((await solveModel("t.mzn", "...", "gecode")).status).toBe(
  52. "UNSATISFIABLE",
  53. );
  54. expect(infoSpy).toHaveBeenCalledOnce();
  55. });
  56. /** @test {solveModel} */
  57. it("wraps solver errors for falsy solve and rejections with or without detail", async () => {
  58. STUBS.silenceConsole("error");
  59. STUBS.minizincModel(Model, null);
  60. await expect(solveModel("t.mzn", "...", "gecode")).rejects.toThrow(
  61. "Solver 'gecode' failed to initialize.",
  62. );
  63. STUBS.minizincModel(
  64. Model,
  65. Promise.reject({ message: "bad model", code: 1, type: "ERR" }),
  66. );
  67. await expect(solveModel("t.mzn", "...", "gecode")).rejects.toThrow(
  68. "Solver failed (code 1, type ERR): bad model",
  69. );
  70. STUBS.minizincModel(Model, Promise.reject({ code: 2, type: "ERR" }));
  71. await expect(solveModel("t.mzn", "...", "gecode")).rejects.toThrow(
  72. "Solver failed (code 2, type ERR):",
  73. );
  74. });
  75. });