Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions tests/funding-deadline-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,52 @@ describe("validateFundingDeadline", () => {
expect(validateFundingDeadline(iso, NOW)).toBeNull();
});

describe("timezone normalization", () => {
const originalTz = process.env.TZ;

beforeEach(() => {
process.env.TZ = "America/New_York";
});

afterEach(() => {
process.env.TZ = originalTz;
});

it("evaluates equivalent instants identically regardless of string format", () => {
const utcString = "2026-03-03T12:00:00.000Z";
const offsetString = "2026-03-03T14:00:00.000+02:00";
expect(validateFundingDeadline(utcString, NOW)).toBeNull();
expect(validateFundingDeadline(offsetString, NOW)).toBeNull();
});

it("rejects equivalent past deadlines across timezones", () => {
const utcString = "2026-03-01T11:00:00.000Z";
const offsetString = "2026-03-01T06:00:00.000-05:00";
expect(validateFundingDeadline(utcString, NOW)).toMatchObject({
code: "DUE_DATE_IN_PAST",
});
expect(validateFundingDeadline(offsetString, NOW)).toMatchObject({
code: "DUE_DATE_IN_PAST",
});
});

it("enforces the exact boundary consistently across timezones", () => {
const utcBoundary = "2026-03-02T12:00:00.000Z";
const offsetBoundary = "2026-03-02T17:30:00.000+05:30";
expect(validateFundingDeadline(utcBoundary, NOW)).toBeNull();
expect(validateFundingDeadline(offsetBoundary, NOW)).toBeNull();

const utcTooSoon = "2026-03-02T11:59:59.999Z";
const offsetTooSoon = "2026-03-02T17:29:59.999+05:30";
expect(validateFundingDeadline(utcTooSoon, NOW)).toMatchObject({
code: "DUE_DATE_TOO_SOON",
});
expect(validateFundingDeadline(offsetTooSoon, NOW)).toMatchObject({
code: "DUE_DATE_TOO_SOON",
});
});
});

describe("clock source", () => {
afterEach(() => {
jest.useRealTimers();
Expand Down
22 changes: 21 additions & 1 deletion tests/investor-return.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,26 @@ describe("computeInvestorReturn", () => {
expect(computeInvestorReturn(2000n, 4000n, 4400n)).toBe(2200n);
});

it("floors the result when division is not exact, without rounding up", () => {
it("floors the result when division is not exact (repeating fractional ratios), without rounding up", () => {
// (1000 * 1000) / 3000 = 333.33... -> floors to 333
expect(computeInvestorReturn(1000n, 3000n, 1000n)).toBe(333n);
});

it("handles repeating fractional ratios correctly in edge cases", () => {
// e.g., 2/3 of 1000 = 666
expect(computeInvestorReturn(2000n, 3000n, 1000n)).toBe(666n);
});

it("returns 0 when yield (settledProceeds) is zero", () => {
expect(computeInvestorReturn(1000n, 5000n, 0n)).toBe(0n);
});

it("handles maximum supported yield without overflow and exact division", () => {
// 64-bit signed integer max
const int64Max = 9223372036854775807n;
expect(computeInvestorReturn(1000n, 2000n, int64Max)).toBe(int64Max / 2n);
});

it("returns the full settled proceeds when investedAmount equals totalFunded", () => {
expect(computeInvestorReturn(5000n, 5000n, 7500n)).toBe(7500n);
});
Expand All @@ -27,4 +42,9 @@ describe("computeInvestorReturn", () => {
expect(() => computeInvestorReturn(-1n, 1000n, 1000n)).toThrow(RangeError);
expect(() => computeInvestorReturn(1n, 1000n, -1000n)).toThrow(RangeError);
});

it("asserts integer output at the service boundary (bigint return type)", () => {
const result = computeInvestorReturn(1000n, 3000n, 1000n);
expect(typeof result).toBe("bigint");
});
});