diff --git a/src/game/formulas/formulas.ts b/src/game/formulas/formulas.ts index 6628293..d9a6bed 100644 --- a/src/game/formulas/formulas.ts +++ b/src/game/formulas/formulas.ts @@ -1344,6 +1344,7 @@ export default class Formula< // "Inner" part of the formula if (this.applySubstitution == null) { console.error("Cannot have two complex operations in an integrable formula"); + return Formula.constant(0); } stack.push((variable: GenericFormula) => // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/tests/game/formulas.test.ts b/tests/game/formulas.test.ts index 3acc944..a36d099 100644 --- a/tests/game/formulas.test.ts +++ b/tests/game/formulas.test.ts @@ -227,14 +227,15 @@ describe("Creating Formulas", () => { expect(formula.evaluate()).compare_tolerance(expectedValue)); // eslint-disable-next-line @typescript-eslint/ban-ts-comment /* @ts-ignore */ - test("Invert throws", () => expect(() => formula.invert(25)).toThrow()); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - /* @ts-ignore */ - test("Integrate throws", () => expect(() => formula.evaluateIntegral()).toThrow()); - test("Invert integral throws", () => + test("Invert errors", () => expect(() => formula.invert(25)).toLogError()); + test("Integrate errors", () => // eslint-disable-next-line @typescript-eslint/ban-ts-comment /* @ts-ignore */ - expect(() => formula.invertIntegral(25)).toThrow()); + expect(() => formula.evaluateIntegral()).toLogError()); + test("Invert integral errors", () => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + /* @ts-ignore */ + expect(() => formula.invertIntegral(25)).toLogError()); }); } testConstant("number", () => Formula.constant(10)); @@ -256,10 +257,10 @@ describe("Creating Formulas", () => { // None of these formulas have variables, so they should all behave the same test("Is not marked as having a variable", () => expect(formula.hasVariable()).toBe(false)); test("Is not invertible", () => expect(formula.isInvertible()).toBe(false)); - test(`Formula throws if trying to invert`, () => + test(`Formula errors if trying to invert`, () => // eslint-disable-next-line @typescript-eslint/ban-ts-comment /* @ts-ignore */ - expect(() => formula.invert(10)).toThrow()); + expect(() => formula.invert(10)).toLogError()); test("Is not integrable", () => expect(formula.isIntegrable()).toBe(false)); test("Has a non-invertible integral", () => expect(formula.isIntegralInvertible()).toBe(false)); @@ -495,12 +496,12 @@ describe("Inverting", () => { test("Non-invertible constant", () => { const formula = Formula.add(variable, constant.ceil()); expect(formula.isInvertible()).toBe(true); - expect(() => formula.invert(10)).not.toThrow(); + expect(() => formula.invert(10)).not.toLogError(); }); test("Non-invertible variable", () => { const formula = Formula.add(variable.ceil(), constant); expect(formula.isInvertible()).toBe(false); - expect(() => formula.invert(10)).toThrow(); + expect(() => formula.invert(10)).toLogError(); }); }); }); @@ -624,19 +625,19 @@ describe("Integrating", () => { test("Integrating nested complex formulas", () => { const formula = Formula.pow(1.05, variable).times(100).pow(0.5); - expect(() => formula.evaluateIntegral()).toThrow(); + expect(() => formula.evaluateIntegral()).toLogError(); }); describe("Integrating with non-integrable sections", () => { test("Non-integrable constant", () => { const formula = Formula.add(variable, constant.ceil()); expect(formula.isIntegrable()).toBe(true); - expect(() => formula.evaluateIntegral()).not.toThrow(); + expect(() => formula.evaluateIntegral()).not.toLogError(); }); test("Non-integrable variable", () => { const formula = Formula.add(variable.ceil(), constant); expect(formula.isIntegrable()).toBe(false); - expect(() => formula.evaluateIntegral()).toThrow(); + expect(() => formula.evaluateIntegral()).toLogError(); }); }); }); @@ -657,7 +658,7 @@ describe("Inverting integrals", () => { describe("Invertible Integral functions marked as such", () => { function checkFormula(formula: InvertibleIntegralFormula) { expect(formula.isIntegralInvertible()).toBe(true); - expect(() => formula.invertIntegral(10)).to.not.throw(); + expect(() => formula.invertIntegral(10)).not.toLogError(); } invertibleIntegralZeroPramFunctionNames.forEach(name => { describe(name, () => { @@ -676,7 +677,7 @@ describe("Inverting integrals", () => { test(`${name}(var, var) is marked as not having an invertible integral`, () => { const formula = Formula[name](variable, variable); expect(formula.isIntegralInvertible()).toBe(false); - expect(() => formula.invertIntegral(10)).to.throw(); + expect(() => formula.invertIntegral(10)).toLogError(); }); }); }); @@ -732,7 +733,7 @@ describe("Inverting integrals", () => { test("Inverting integral of nested complex formulas", () => { const formula = Formula.pow(1.05, variable).times(100).pow(0.5); - expect(() => formula.invertIntegral(100)).toThrow(); + expect(() => formula.invertIntegral(100)).toLogError(); }); }); @@ -765,7 +766,7 @@ describe("Step-wise", () => { ); expect(() => Formula.step(constant, 10, value => Formula.add(value, 10)).evaluateIntegral() - ).toThrow(); + ).toLogError(); }); test("Formula never marked as having an invertible integral", () => { @@ -774,7 +775,7 @@ describe("Step-wise", () => { ).toBe(false); expect(() => Formula.step(constant, 10, value => Formula.add(value, 10)).invertIntegral(10) - ).toThrow(); + ).toLogError(); }); test("Formula modifiers with variables mark formula as non-invertible", () => { @@ -866,7 +867,7 @@ describe("Conditionals", () => { ); expect(() => Formula.if(constant, true, value => Formula.add(value, 10)).evaluateIntegral() - ).toThrow(); + ).toLogError(); }); test("Formula never marked as having an invertible integral", () => { @@ -875,7 +876,7 @@ describe("Conditionals", () => { ).toBe(false); expect(() => Formula.if(constant, true, value => Formula.add(value, 10)).invertIntegral(10) - ).toThrow(); + ).toLogError(); }); test("Formula modifiers with variables mark formula as non-invertible", () => { @@ -976,7 +977,7 @@ describe("Custom Formulas", () => { evaluate: () => 6, invert: value => value }).invert(10) - ).toThrow()); + ).toLogError()); test("One input inverts correctly", () => expect( new Formula({ @@ -1003,7 +1004,7 @@ describe("Custom Formulas", () => { evaluate: () => 0, integrate: stack => variable }).evaluateIntegral() - ).toThrow()); + ).toLogError()); test("One input integrates correctly", () => expect( new Formula({ @@ -1030,7 +1031,7 @@ describe("Custom Formulas", () => { evaluate: () => 0, integrate: stack => variable }).invertIntegral(20) - ).toThrow()); + ).toLogError()); test("One input inverts integral correctly", () => expect( new Formula({ @@ -1074,18 +1075,18 @@ describe("Buy Max", () => { resource = createResource(ref(100000)); }); describe("Without cumulative cost", () => { - test("Throws on calculating max affordable of non-invertible formula", () => { + test("Errors on calculating max affordable of non-invertible formula", () => { const purchases = ref(1); const variable = Formula.variable(purchases); const formula = Formula.abs(variable); const maxAffordable = calculateMaxAffordable(formula, resource, false); - expect(() => maxAffordable.value).toThrow(); + expect(() => maxAffordable.value).toLogError(); }); - test("Throws on calculating cost of non-invertible formula", () => { + test("Errors on calculating cost of non-invertible formula", () => { const purchases = ref(1); const variable = Formula.variable(purchases); const formula = Formula.abs(variable); - expect(() => calculateCost(formula, 5, false, 0)).toThrow(); + expect(() => calculateCost(formula, 5, false, 0)).toLogError(); }); test("Calculates max affordable and cost correctly", () => { const variable = Formula.variable(0); @@ -1110,18 +1111,18 @@ describe("Buy Max", () => { }); }); describe("With cumulative cost", () => { - test("Throws on calculating max affordable of non-invertible formula", () => { + test("Errors on calculating max affordable of non-invertible formula", () => { const purchases = ref(1); const variable = Formula.variable(purchases); const formula = Formula.abs(variable); const maxAffordable = calculateMaxAffordable(formula, resource, true); - expect(() => maxAffordable.value).toThrow(); + expect(() => maxAffordable.value).toLogError(); }); - test("Throws on calculating cost of non-invertible formula", () => { + test("Errors on calculating cost of non-invertible formula", () => { const purchases = ref(1); const variable = Formula.variable(purchases); const formula = Formula.abs(variable); - expect(() => calculateCost(formula, 5, true, 0)).toThrow(); + expect(() => calculateCost(formula, 5, true, 0)).toLogError(); }); test("Estimates max affordable and cost correctly with 0 purchases", () => { const purchases = ref(0); @@ -1266,7 +1267,7 @@ describe("Buy Max", () => { test("Handles direct sum of non-integrable formula", () => { const purchases = ref(0); const formula = Formula.variable(purchases).abs(); - expect(() => calculateCost(formula, 10)).not.toThrow(); + expect(() => calculateCost(formula, 10)).not.toLogError(); }); }); }); diff --git a/tests/utils.ts b/tests/utils.ts index a1e6084..4252eac 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,8 +1,9 @@ import Decimal, { DecimalSource, format } from "util/bignum"; -import { expect } from "vitest"; +import { Mock, expect, vi } from "vitest"; interface CustomMatchers { compare_tolerance(expected: DecimalSource, tolerance?: number): R; + toLogError(): R; } declare global { @@ -36,5 +37,25 @@ expect.extend({ expected: format(expected), actual: format(received) }; + }, + toLogError(received: () => unknown) { + const { isNot } = this; + console.error = vi.fn(); + received(); + const calls = ( + console.error as unknown as Mock< + Parameters, + ReturnType + > + ).mock.calls.length; + const pass = calls >= 1; + vi.restoreAllMocks(); + return { + pass, + message: () => + `Expected ${received} to ${(isNot as boolean) ? " not" : ""} log an error`, + expected: "1+", + actual: calls + }; } });