deadhead-space-freight-tycoon/packages/sim/test/loan.test.ts

98 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { content } from "@deadhead/content";
import { describe, expect, it } from "vitest";
import {
createDispatchRecord,
resolveDispatch,
splitLoanRepayment,
type Contract,
} from "../src/index";
describe("loan repayment split", () => {
it("takes min(balance, credits × share), rounded down to whole credits", () => {
expect(splitLoanRepayment(1000, 5000, 0.3)).toEqual({ repayment: 300, net: 700 });
expect(splitLoanRepayment(1001, 5000, 0.3)).toEqual({ repayment: 300, net: 701 });
expect(splitLoanRepayment(1000, 120, 0.3)).toEqual({ repayment: 120, net: 880 });
});
it("takes nothing when there is no balance, or no positive payout", () => {
expect(splitLoanRepayment(1000, 0, 0.3)).toEqual({ repayment: 0, net: 1000 });
expect(splitLoanRepayment(0, 5000, 0.3)).toEqual({ repayment: 0, net: 0 });
expect(splitLoanRepayment(-60, 5000, 0.3)).toEqual({ repayment: 0, net: -60 });
});
it("always splits the whole amount and never repays more than the balance", () => {
for (const credits of [-500, -1, 0, 1, 7, 99, 1000, 123_457]) {
for (const balance of [0, 1, 50, 299, 5000, 1_000_000]) {
for (const share of [0, 0.1, 0.3, 1]) {
const { repayment, net } = splitLoanRepayment(credits, balance, share);
expect(net + repayment).toBe(credits);
expect(repayment).toBeLessThanOrEqual(balance);
expect(repayment).toBeGreaterThanOrEqual(0);
expect(repayment).toBe(
credits > 0 && balance > 0 ? Math.min(balance, Math.floor(credits * share)) : 0,
);
}
}
}
});
});
describe("resolution with a loan", () => {
const now = Date.parse("2100-01-01T00:30:00Z");
const contract: Contract = {
id: "c1",
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
tier: 0,
massTonnes: 10,
payout: 2000,
requiredSkill: null,
requiredLongHaulLevel: 0,
offeredAt: now,
expiresAt: now + 3_600_000,
firstContact: false,
};
const record = createDispatchRecord(
{
id: "d1",
ship: { id: "s1", modelId: "courier", locationId: "earth", inFlight: false },
pilot: {
id: "p1",
isAvatar: false,
assignedShipId: "s1",
inFlight: false,
skills: {},
restEndsAt: null,
},
contract,
tutorial: false,
now,
worldSeed: 7,
},
content,
);
it("returns the repayment alongside the credits to add, after pilot pay", () => {
const result = resolveDispatch(
{
record,
pilotIsAvatar: false,
discoveredIds: new Set(["earth", "moon"]),
loanBalance: 5000,
pilotDutyHours: 0,
pilotSkills: {},
now: record.arrivalAt,
},
content,
);
if (result.status !== "resolved") throw new Error("expected a resolution");
const afterPay = 2000 - content.config.pilotPayPerDelivery;
const repayment = Math.floor(afterPay * content.config.loanRepaymentShare);
expect(result.resolution).toMatchObject({
loanRepayment: repayment,
credits: afterPay - repayment,
});
});
});