import { computeAvailableLeftover, computeBatchedPortions } from "@batch-cooking/shared"; import { expect } from "chai"; /** * Pure portion arithmetic from `@batch-cooking/shared` — no DB, so this * suite skips `resetDatabase`. The API (`addPlanningItem`, and later the * leftover-assignment endpoints) and the web app both call these; the * numbers below are the two worked examples from issue #34 plus the * boundary cases. */ describe("planning portion arithmetic", () => { describe("computeBatchedPortions", () => { it("rounds up to one batch when fewer portions are requested than the recipe yields", () => { expect(computeBatchedPortions(4, 3)).to.deep.equal({ portions: 4, leftover: 1 }); }); it("cooks several batches when more portions are requested than one batch yields", () => { expect(computeBatchedPortions(4, 10)).to.deep.equal({ portions: 12, leftover: 2 }); }); it("leaves no leftover on an exact batch boundary", () => { expect(computeBatchedPortions(4, 4)).to.deep.equal({ portions: 4, leftover: 0 }); expect(computeBatchedPortions(4, 8)).to.deep.equal({ portions: 8, leftover: 0 }); }); it("still prepares one batch when a single portion is requested", () => { expect(computeBatchedPortions(6, 1)).to.deep.equal({ portions: 6, leftover: 5 }); }); it("handles a one-portion recipe (every request is an exact number of batches)", () => { expect(computeBatchedPortions(1, 5)).to.deep.equal({ portions: 5, leftover: 0 }); }); }); describe("computeAvailableLeftover", () => { const base = { portions: 12, portionsRequested: 10, discardedPortions: 0, leftoverUses: [] }; it("is the prepared-minus-requested pool when nothing has been discarded or served", () => { expect(computeAvailableLeftover(base)).to.equal(2); }); it("subtracts portions already served to other slots", () => { expect( computeAvailableLeftover({ ...base, leftoverUses: [{ portions: 1 }, { portions: 1 }] }), ).to.equal(0); }); it("subtracts explicitly discarded portions", () => { expect(computeAvailableLeftover({ ...base, discardedPortions: 2 })).to.equal(0); }); it("never goes negative", () => { expect( computeAvailableLeftover({ ...base, discardedPortions: 5, leftoverUses: [{ portions: 3 }], }), ).to.equal(0); }); it("is 0 for an item whose request landed exactly on a batch (no pool at all)", () => { expect( computeAvailableLeftover({ portions: 8, portionsRequested: 8, discardedPortions: 0, leftoverUses: [], }), ).to.equal(0); }); }); });