import { describe, expect, it } from "vitest"; import { formatDuration, formatTimestamp, parseCsv, parseDuration, parseTimestamp, safeJsonParse, stableStringify, stringifyCsv, } from "../../src/helpers"; describe("bounded structured data", () => { it("parses hardened JSON and serializes deterministic key order", () => { expect(safeJsonParse('{"b":2,"a":[true,null]}')).toEqual({ b: 2, a: [true, null], }); expect(stableStringify({ z: 1, a: { d: 4, c: 3 } }, 2)).toBe( '{\n "a": {\n "c": 3,\n "d": 4\n },\n "z": 1\n}', ); expect(() => safeJsonParse('{"__proto__":{"polluted":true}}')).toThrow( /Dangerous/u, ); expect(() => safeJsonParse("[[[0]]]", { maxDepth: 2 })).toThrow(/depth/u); expect(() => safeJsonParse("[1,2,3]", { maxNodes: 3 })).toThrow(/node/u); const cycle: Record = {}; cycle.self = cycle; expect(() => stableStringify(cycle)).toThrow(/cyclic/u); expect(() => stableStringify({ value: 1n })).toThrow(/BigInt/u); }); it("handles quoted CSV, embedded newlines, and round trips", () => { const rows = [ ["name", "note"], ["Ada", 'comma, quote " and\nnewline'], ["", "last"], ]; const csv = stringifyCsv(rows); expect(csv).toContain('"comma, quote "" and\nnewline"'); expect(parseCsv(csv)).toEqual(rows); expect(parseCsv("a;b\r\n1;2", { delimiter: ";" })).toEqual([ ["a", "b"], ["1", "2"], ]); expect(() => parseCsv('"unterminated')).toThrow(/unterminated/u); expect(() => parseCsv("a,b,c", { maxColumns: 2 })).toThrow(/column/u); }); }); describe("timestamps and durations", () => { it("normalizes ISO and Unix timestamps", () => { expect(parseTimestamp(0, "seconds")).toMatchObject({ epochMilliseconds: 0, epochSeconds: 0, iso: "1970-01-01T00:00:00.000Z", }); expect(parseTimestamp("2000-01-01T00:00:00Z").epochSeconds).toBe(946684800); expect(formatTimestamp(0, "UTC")).toMatch(/1970/u); expect(() => parseTimestamp("not a date")).toThrow(/range/u); }); it("parses ISO, clock, and token durations and formats them", () => { expect(parseDuration("P1DT2H3M4.5S")).toBe(93_784_500); expect(parseDuration("01:02:03.004")).toBe(3_723_004); expect(parseDuration("2h 30m")).toBe(9_000_000); expect(parseDuration("-2h 30m")).toBe(-9_000_000); expect(parseDuration(formatDuration(-9_000_000, "human"))).toBe(-9_000_000); expect(formatDuration(93_784_500, "iso")).toBe("P1DT2H3M4.5S"); expect(formatDuration(3_723_004, "clock")).toBe("01:02:03.004"); expect(formatDuration(9_000_000, "human")).toBe("2h 30m"); expect(formatDuration(86_400_000, "iso")).toBe("P1D"); expect(formatDuration(59_999.6, "clock")).toBe("00:01:00.000"); expect(() => parseDuration("1 month")).toThrow(/Duration/u); }); });