diff --git a/lib/BaseSolver.ts b/lib/BaseSolver.ts index e071bf8..37455e4 100644 --- a/lib/BaseSolver.ts +++ b/lib/BaseSolver.ts @@ -53,14 +53,20 @@ export class BaseSolver { throw e } if (!this.solved && this.iterations >= this.MAX_ITERATIONS) { - this.tryFinalAcceptance() + try { + this.tryFinalAcceptance() + } catch (e) { + this.error = `${this.getSolverName()} error: ${e}` + this.failed = true + throw e + } } if (!this.solved && this.iterations >= this.MAX_ITERATIONS) { this.error = `${this.getSolverName()} ran out of iterations` this.failed = true } if ("computeProgress" in this) { - // @ts-ignore + // @ts-expect-error this.progress = this.computeProgress() as number } } diff --git a/tests/BaseSolver.test.ts b/tests/BaseSolver.test.ts index 76ee9e3..5d2afd3 100644 --- a/tests/BaseSolver.test.ts +++ b/tests/BaseSolver.test.ts @@ -1,4 +1,4 @@ -import { test, expect } from "bun:test" +import { expect, test } from "bun:test" import { BaseSolver } from "../lib/BaseSolver" class TestSolver extends BaseSolver { @@ -121,3 +121,46 @@ test("BaseSolver error handling", () => { expect(solver.failed).toBe(true) expect(solver.error).toContain("ErrorSolver error: Error: Test error") }) + +test("tryFinalAcceptance exceptions fail the solver and are not retried", () => { + class AcceptanceErrorSolver extends BaseSolver { + override MAX_ITERATIONS = 1 + calls = 0 + failure = new Error("final acceptance failed") + + override tryFinalAcceptance() { + this.calls++ + throw this.failure + } + } + + const solver = new AcceptanceErrorSolver() + expect(() => solver.step()).toThrow(solver.failure) + expect(solver.failed).toBe(true) + expect(solver.error).toContain( + "AcceptanceErrorSolver error: Error: final acceptance failed", + ) + expect(solver.iterations).toBe(1) + expect(solver.calls).toBe(1) + + expect(() => solver.step()).not.toThrow() + expect(solver.calls).toBe(1) + expect(solver.iterations).toBe(1) +}) + +test("tryFinalAcceptance can still accept a passable solution", () => { + class AcceptingSolver extends BaseSolver { + override MAX_ITERATIONS = 1 + + override tryFinalAcceptance() { + this.solved = true + } + } + + const solver = new AcceptingSolver() + solver.solve() + expect(solver.solved).toBe(true) + expect(solver.failed).toBe(false) + expect(solver.error).toBeNull() + expect(solver.iterations).toBe(1) +})