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);
});
});
|