/** * 配置服务单元测试 * 覆盖维度映射路径构建与嵌套键规整两项核心逻辑 * 运行:npm test */ const test = require("node:test"); const assert = require("node:assert"); const { buildConfigPath, normalizeKey, validateEditValue, validateStructure } = require("../src/services/configService"); // 构造测试用项目对象的辅助函数 function makeProject(overrides) { return { enableIdc: true, enableEnvironment: true, enableGroup: true, idcMapping: "path", environmentMapping: "path", groupMapping: "path", ...overrides, }; } test("1-1 全部维度映射为 path 时,路径包含全部维度前缀", () => { const project = makeProject({}); const config = { idc: "华北", environment: "dev", group: "用户模块", key: "db.host" }; assert.strictEqual(buildConfigPath(project, config), "华北/dev/用户模块/db.host"); }); test("1-2 分组映射为 label 时,分组不进入路径", () => { const project = makeProject({ groupMapping: "label" }); const config = { idc: "华北", environment: "dev", group: "用户模块", key: "db/host" }; assert.strictEqual(buildConfigPath(project, config), "华北/dev/db/host"); }); test("1-3 全部维度映射为 label 时,路径仅含嵌套键", () => { const project = makeProject({ idcMapping: "label", environmentMapping: "label", groupMapping: "label" }); const config = { idc: "华北", environment: "dev", group: "用户模块", key: "db/pool/max" }; assert.strictEqual(buildConfigPath(project, config), "db/pool/max"); }); test("1-4 维度未启用时,即便映射为 path 也不进入路径", () => { const project = makeProject({ enableIdc: false }); const config = { idc: "华北", environment: "dev", group: "用户模块", key: "db.host" }; assert.strictEqual(buildConfigPath(project, config), "dev/用户模块/db.host"); }); test("2-1 规整键:去除首尾斜杠与空白", () => { assert.strictEqual(normalizeKey(" /db/host/ "), "db/host"); }); test("2-2 规整键:压缩连续斜杠并去除空段", () => { assert.strictEqual(normalizeKey("db//pool///max"), "db/pool/max"); }); test("2-3 规整键:空输入返回空字符串", () => { assert.strictEqual(normalizeKey(" "), ""); }); test("3-1 必填且存在:空值校验失败", () => { const cfg = { key: "a", value: " ", type: "string", valueRange: "", required: true, exists: true }; assert.throws(() => validateEditValue(cfg), /必填项/); }); test("3-2 必填且存在:非空值通过", () => { const cfg = { key: "a", value: "x", type: "string", valueRange: "", required: true, exists: true }; assert.doesNotThrow(() => validateEditValue(cfg)); }); test("3-3 必填但不存在:允许空值", () => { const cfg = { key: "a", value: "", type: "string", valueRange: "", required: true, exists: false }; assert.doesNotThrow(() => validateEditValue(cfg)); }); test("3-4 不存在:跳过类型与范围校验", () => { const cfg = { key: "a", value: "not-number", type: "number", valueRange: "", required: false, exists: false }; assert.doesNotThrow(() => validateEditValue(cfg)); }); test("3-5 存在且值类型错误:校验失败", () => { const cfg = { key: "a", value: "abc", type: "number", valueRange: "", required: false, exists: true }; assert.throws(() => validateEditValue(cfg), /有效的数字/); }); test("3-6 存在且不符合正则范围:校验失败", () => { const cfg = { key: "phone", value: "123", type: "string", valueRange: "/^1[3-9]\\d{9}$/", required: false, exists: true }; assert.throws(() => validateEditValue(cfg), /格式要求/); }); test("3-7 必填且 json 值为空数组:不算空值", () => { const cfg = { key: "a", value: [], type: "json", valueRange: "", required: true, exists: true }; assert.doesNotThrow(() => validateEditValue(cfg)); }); test("3-8 必填且值为 0 / false:不算空值", () => { assert.doesNotThrow(() => validateEditValue({ key: "a", value: 0, type: "number", valueRange: "", required: true, exists: true })); assert.doesNotThrow(() => validateEditValue({ key: "a", value: false, type: "boolean", valueRange: "", required: true, exists: true })); }); test("4-1 默认值类型校验:number 类型默认值必须为数字", () => { const project = makeProject({}); const base = { key: "a", type: "number", description: "d", idc: "x", environment: "y", group: "z" }; assert.throws(() => validateStructure({ ...base, defaultValue: "abc" }, project), /默认值不符合类型/); assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: "42" }, project)); assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: 0 }, project)); }); test("4-2 默认值类型校验:空默认值不做校验", () => { const project = makeProject({}); const base = { key: "a", type: "number", description: "d", idc: "x", environment: "y", group: "z" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: "" }, project)); assert.doesNotThrow(() => validateStructure({ ...base }, project)); }); test("4-3 默认值类型校验:json 类型默认值需为合法 JSON", () => { const project = makeProject({}); const base = { key: "a", type: "json", description: "d", idc: "x", environment: "y", group: "z" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: "{\"a\":1}" }, project)); assert.throws(() => validateStructure({ ...base, defaultValue: "{bad json}" }, project), /默认值不符合类型/); }); test("4-4 默认值范围校验:默认值需符合值范围约束", () => { const project = makeProject({}); const base = { key: "a", type: "string", description: "d", idc: "x", environment: "y", group: "z", valueRange: "/^1[3-9]\\d{9}$/" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: "13800138000" }, project)); assert.throws(() => validateStructure({ ...base, defaultValue: "12345" }, project), /默认值校验失败/); }); test("4-5 默认值范围校验:number 区间默认值", () => { const project = makeProject({}); const base = { key: "a", type: "number", description: "d", idc: "x", environment: "y", group: "z", valueRange: "1-100" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: "50" }, project)); assert.throws(() => validateStructure({ ...base, defaultValue: "500" }, project), /默认值校验失败/); }); test("4-6 默认值类型校验:boolean false 为合法默认值", () => { const project = makeProject({}); const base = { key: "a", type: "boolean", description: "d", idc: "x", environment: "y", group: "z" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: false }, project)); }); test("4-7 默认值判断:纯空白默认值视为未填写", () => { const project = makeProject({}); const base = { key: "a", type: "number", description: "d", idc: "x", environment: "y", group: "z" }; assert.doesNotThrow(() => validateStructure({ ...base, defaultValue: " " }, project)); });