Files
suaveplan/packages/security-stack/security/license/src/time/time.test.ts
2026-05-27 23:47:53 +01:00

119 lines
4.1 KiB
TypeScript

import { describe, expect, it } from "@suaveplan/testing/runner";
import type { Clock } from "@suaveplan/types";
import { TimeEncodingType } from "../types/license.js";
import { checkExpiration, dayNumberToDate, getDayNumber } from "./time.js";
describe("time helpers", () => {
it("NONE is never expired", { timeout: 5000 }, () => {
const result = checkExpiration(TimeEncodingType.NONE, 0);
expect(result.isExpired).toBe(false);
expect(result.expirationDate).toBeUndefined();
});
it("ABSOLUTE_DAYS expires after its day number", { timeout: 5000 }, () => {
const day = 20000; // 2024-10-04ish
const refAfter = new Date((day + 1) * 86_400_000);
const refBefore = new Date((day - 1) * 86_400_000);
const after = checkExpiration(
TimeEncodingType.ABSOLUTE_DAYS,
day,
refAfter
);
const before = checkExpiration(
TimeEncodingType.ABSOLUTE_DAYS,
day,
refBefore
);
expect(after.isExpired).toBe(true);
expect(after.expirationDate?.getTime()).toBe(day * 86_400_000);
expect(before.isExpired).toBe(false);
});
it("RELATIVE_DAYS uses creationDate baseline", { timeout: 5000 }, () => {
const creation = new Date("2026-01-01T00:00:00Z");
const refAfter = new Date("2026-01-15T00:00:01Z"); // 14 days + 1s
const refBefore = new Date("2026-01-10T00:00:00Z");
const after = checkExpiration(
TimeEncodingType.RELATIVE_DAYS,
14,
refAfter,
creation
);
const before = checkExpiration(
TimeEncodingType.RELATIVE_DAYS,
14,
refBefore,
creation
);
expect(after.isExpired).toBe(true);
expect(before.isExpired).toBe(false);
});
it("RELATIVE_DAYS falls back to referenceDate when no creationDate", {
timeout: 5000,
}, () => {
const ref = new Date("2026-01-01T00:00:00Z");
const r = checkExpiration(TimeEncodingType.RELATIVE_DAYS, 5, ref);
expect(r.isExpired).toBe(false);
expect(r.expirationDate?.getTime()).toBe(
ref.getTime() + 5 * 86_400_000
);
});
it("ABSOLUTE_TIMESTAMP expires after its second", { timeout: 5000 }, () => {
const ts = 1_700_000_000; // a moment in 2023
const before = checkExpiration(
TimeEncodingType.ABSOLUTE_TIMESTAMP,
ts,
new Date((ts - 10) * 1000)
);
const after = checkExpiration(
TimeEncodingType.ABSOLUTE_TIMESTAMP,
ts,
new Date((ts + 10) * 1000)
);
expect(before.isExpired).toBe(false);
expect(after.isExpired).toBe(true);
});
it("uses injected Clock when no referenceDate supplied", {
timeout: 5000,
}, () => {
const fixed = 1_000_000_000_000; // 2001-09-09T01:46:40Z
const clock: Clock = () => fixed;
// ABSOLUTE_DAYS at day 11574 (which equals fixed/MS_PER_DAY=11574)
const day = Math.floor(fixed / 86_400_000);
const exactNow = checkExpiration(
TimeEncodingType.ABSOLUTE_DAYS,
day - 1,
undefined,
undefined,
clock
);
expect(exactNow.isExpired).toBe(true);
});
it("default unknown encoding falls through to non-expired", {
timeout: 5000,
}, () => {
const r = checkExpiration(99 as TimeEncodingType, 0);
expect(r.isExpired).toBe(false);
});
it("getDayNumber uses provided date", { timeout: 5000 }, () => {
expect(getDayNumber(new Date(0))).toBe(0);
expect(getDayNumber(new Date(86_400_000))).toBe(1);
});
it("getDayNumber uses injected clock when no date", {
timeout: 5000,
}, () => {
const clock: Clock = () => 5 * 86_400_000;
expect(getDayNumber(undefined, clock)).toBe(5);
});
it("dayNumberToDate inverts getDayNumber", { timeout: 5000 }, () => {
expect(dayNumberToDate(10).getTime()).toBe(10 * 86_400_000);
});
});