src.nth.io/

summaryrefslogtreecommitdiff
path: root/test/config.test.ts
blob: 1caecd8b898e7587809573b3d5823905d423ee7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { describe, expect, it } from "vitest";
import { ConfigError, parseNodeId, validateConfig } from "../src/config.js";

const minimal = { storagePath: "/var/lib/mattertimesync" };

describe("validateConfig", () => {
  it("accepts a minimal configuration and applies defaults", () => {
    const config = validateConfig(minimal);
    expect(config.storagePath).toBe(minimal.storagePath);
    expect(config.timezone).toBe("America/Chicago");
    expect(config.logLevel).toBe("info");
  });

  it("accepts a full configuration", () => {
    const config = validateConfig({
      ...minimal,
      timezone: "Europe/Berlin",
      logLevel: "debug",
    });
    expect(config.timezone).toBe("Europe/Berlin");
    expect(config.logLevel).toBe("debug");
  });

  it("rejects non-object documents", () => {
    expect(() => validateConfig([])).toThrow(ConfigError);
    expect(() => validateConfig("x")).toThrow(ConfigError);
    expect(() => validateConfig(null)).toThrow(ConfigError);
  });

  it("requires storagePath", () => {
    expect(() => validateConfig({})).toThrow(/storagePath/);
    expect(() => validateConfig({ storagePath: "" })).toThrow(/storagePath/);
  });

  it("rejects unknown fields", () => {
    expect(() => validateConfig({ ...minimal, unexpected: 1 })).toThrow(/unknown field "unexpected"/);
    // Fields from abandoned designs are rejected, not ignored.
    expect(() => validateConfig({ ...minimal, syncIntervalHours: 24 })).toThrow(/unknown field/);
    expect(() => validateConfig({ ...minimal, syncOnReconnect: true })).toThrow(/unknown field/);
    expect(() => validateConfig({ ...minimal, nodeId: "1" })).toThrow(/unknown field/);
  });

  it("rejects invalid time zones", () => {
    expect(() => validateConfig({ ...minimal, timezone: "Central Time" })).toThrow(/timezone/);
    expect(() => validateConfig({ ...minimal, timezone: "" })).toThrow(/timezone/);
    expect(() => validateConfig({ ...minimal, timezone: 5 })).toThrow(/timezone/);
  });

  it("rejects invalid log levels", () => {
    expect(() => validateConfig({ ...minimal, logLevel: "verbose" })).toThrow(/logLevel/);
  });
});

describe("parseNodeId", () => {
  it("parses decimal strings without precision loss", () => {
    expect(parseNodeId("1")).toBe(1n);
    expect(parseNodeId("9007199254740993")).toBe(9007199254740993n);
    expect(parseNodeId("18446744073709551615")).toBe(18446744073709551615n);
  });

  it("accepts small safe integers", () => {
    expect(parseNodeId(42)).toBe(42n);
  });

  it("rejects unsafe or invalid values", () => {
    expect(() => parseNodeId("18446744073709551616")).toThrow(ConfigError); // 2^64
    expect(() => parseNodeId("-1")).toThrow(ConfigError);
    expect(() => parseNodeId(1.5)).toThrow(ConfigError);
    expect(() => parseNodeId("0x10")).toThrow(ConfigError);
    expect(() => parseNodeId(Number.MAX_SAFE_INTEGER + 2)).toThrow(ConfigError);
    expect(() => parseNodeId(null)).toThrow(ConfigError);
  });
});