import { describe, expect, it } from "vitest"; import { MATTER_EPOCH_UNIX_SECONDS, compareDeviceClock, currentMatterUtcMicroseconds, formatDurationMicros, formatMatterMicros, matterMicrosToUnixMillis, unixMillisToMatterMicros, } from "../src/sync.js"; describe("Matter epoch conversion", () => { it("maps 2000-01-01T00:00:00Z to 0 microseconds", () => { const unixMs = BigInt(Date.parse("2000-01-01T00:00:00Z")); expect(unixMillisToMatterMicros(unixMs)).toBe(0n); }); it("maps 2000-01-01T00:00:01Z to 1,000,000 microseconds", () => { const unixMs = BigInt(Date.parse("2000-01-01T00:00:01Z")); expect(unixMillisToMatterMicros(unixMs)).toBe(1_000_000n); }); it("keeps the Unix epoch conversion exact", () => { expect(unixMillisToMatterMicros(0n)).toBe(-MATTER_EPOCH_UNIX_SECONDS * 1_000_000n); expect(unixMillisToMatterMicros(0n)).toBe(-946_684_800_000_000n); }); it("keeps current dates exact through bigint round-trips", () => { const unixMs = BigInt(Date.parse("2026-07-26T20:00:00.123Z")); const micros = unixMillisToMatterMicros(unixMs); expect(micros).toBe((unixMs - 946_684_800_000n) * 1_000n); expect(matterMicrosToUnixMillis(micros)).toBe(unixMs); }); it("stays exact beyond JavaScript number precision", () => { // Microsecond timestamps pass Number.MAX_SAFE_INTEGER around year 2285; // conversion must not degrade there, proving no number arithmetic occurs. const unixMs = BigInt(Date.parse("2300-01-01T00:00:00.001Z")); const micros = unixMillisToMatterMicros(unixMs); expect(micros > BigInt(Number.MAX_SAFE_INTEGER)).toBe(true); expect(matterMicrosToUnixMillis(micros)).toBe(unixMs); }); it("computes the current time via the injected clock", () => { const nowMs = Date.parse("2026-07-26T20:00:00Z"); const micros = currentMatterUtcMicroseconds(() => nowMs); expect(micros).toBe(unixMillisToMatterMicros(BigInt(nowMs))); }); it("formats Matter microseconds as an ISO instant", () => { expect(formatMatterMicros(0n)).toBe("2000-01-01T00:00:00.000Z"); expect(formatMatterMicros(1_000_000n)).toBe("2000-01-01T00:00:01.000Z"); }); }); describe("formatDurationMicros", () => { it("scales units with magnitude", () => { expect(formatDurationMicros(0n)).toBe("0us"); expect(formatDurationMicros(999n)).toBe("999us"); expect(formatDurationMicros(412_000n)).toBe("412ms"); expect(formatDurationMicros(3_200_000n)).toBe("3.2s"); expect(formatDurationMicros(59_000_000n)).toBe("59s"); expect(formatDurationMicros(125_000_000n)).toBe("2m 5s"); expect(formatDurationMicros(3_840_000_000n)).toBe("1h 4m"); // 90,061 seconds = 1d 1h 1m 1s; seconds are dropped once days appear. expect(formatDurationMicros(90_061_000_000n)).toBe("1d 1h 1m"); }); it("rejects negative durations", () => { expect(() => formatDurationMicros(-1n)).toThrow(); }); }); describe("compareDeviceClock", () => { const host = unixMillisToMatterMicros(BigInt(Date.parse("2026-07-26T20:00:00.000Z"))); it("reports an unset device clock", () => { const comparison = compareDeviceClock(null, host); expect(comparison.deviceTime).toBeNull(); expect(comparison.deltaMicroseconds).toBeNull(); expect(comparison.hostTime).toBe("2026-07-26T20:00:00.000Z"); expect(comparison.description).toBe("device clock was unset"); }); it("reports a device clock behind the host", () => { const comparison = compareDeviceClock(host - 83_000_000n, host); expect(comparison.deviceTime).toBe("2026-07-26T19:58:37.000Z"); expect(comparison.deltaMicroseconds).toBe(-83_000_000n); expect(comparison.description).toBe("device clock was 1m 23s behind"); }); it("reports a device clock ahead of the host", () => { const comparison = compareDeviceClock(host + 5_500_000n, host); expect(comparison.deltaMicroseconds).toBe(5_500_000n); expect(comparison.description).toBe("device clock was 5.5s ahead"); }); it("treats sub-second deltas as in sync but still reports them", () => { const comparison = compareDeviceClock(host - 412_000n, host); expect(comparison.description).toBe("device clock was within 1s of host time (412ms behind)"); }); it("handles a device clock wildly in the future (wrong epoch bug)", () => { // A device set with Unix-epoch seconds where Matter-epoch was expected // shows up decades ahead; the delta must stay exact. const wrong = host + 946_684_800n * 1_000_000n; const comparison = compareDeviceClock(wrong, host); expect(comparison.deltaMicroseconds).toBe(946_684_800_000_000n); expect(comparison.description).toContain("ahead"); }); });