Made calculateMaxAffordable, calculateCost, and cost requirements interface a bit cleaner #17

Merged
thepaperpilot merged 6 commits from feature/requirements-refactor into main 2023-05-17 23:52:28 +00:00
3 changed files with 56 additions and 33 deletions
Showing only changes of commit 7deacb41e1 - Show all commits

View file

@ -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

View file

@ -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();
});
});
});

View file

@ -1,8 +1,9 @@
import Decimal, { DecimalSource, format } from "util/bignum";
import { expect } from "vitest";
import { Mock, expect, vi } from "vitest";
interface CustomMatchers<R = unknown> {
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<typeof console.error>,
ReturnType<typeof console.error>
>
).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
};
}
});