Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/BaseSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
45 changes: 44 additions & 1 deletion tests/BaseSolver.test.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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)
})
Loading