diff --git a/src/engine/engine.test.ts b/src/engine/engine.test.ts index 29f15e1..febef3a 100644 --- a/src/engine/engine.test.ts +++ b/src/engine/engine.test.ts @@ -335,6 +335,13 @@ describe("extension API", () => { eng.addUnit({ id: "horse", phrases: "horse, horses, hrs", baseUnitId: "meter", format: "hrs", ratio: 2.4 }); expect(calc("2 horses in meters")).toBe("4.8 m"); }); + it("addUnit throws on id collision instead of silently corrupting unitsById", () => { + expect(() => + eng.addUnit({ id: "horse", phrases: "nag", baseUnitId: "meter", format: "nag", ratio: 99 }) + ).toThrow(/horse/); + // the original registration must survive the failed collision + expect(calc("2 horses in meters")).toBe("4.8 m"); + }); it("addFunction (zum from Sample.js)", () => { eng.addFunction({ id: "zum", phrases: "zum" }, (values) => ({ double: values[0].double + values[1].double })); expect(calc("zum(2;3)")).toBe("5"); diff --git a/src/engine/index.ts b/src/engine/index.ts index e507dd9..5d6e82e 100644 --- a/src/engine/index.ts +++ b/src/engine/index.ts @@ -218,6 +218,7 @@ export class SumEngine { addUnit(spec: ExtensionUnitSpec): void { const base = this.reg.unitsById.get(spec.baseUnitId) ?? this.currencyBase(spec.baseUnitId); if (!base) throw new Error(`numi.addUnit: unknown baseUnitId ${spec.baseUnitId}`); + if (this.reg.unitsById.has(spec.id)) throw new Error(`numi.addUnit: id "${spec.id}" is already registered`); const unit: Unit = { id: spec.id, dimension: base.dimension,