@@ -5,7 +5,7 @@
|
||||
*/
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert");
|
||||
const { buildConfigPath, normalizeKey } = require("../src/services/configService");
|
||||
const { buildConfigPath, normalizeKey, validateEditValue, validateStructure } = require("../src/services/configService");
|
||||
|
||||
// 构造测试用项目对象的辅助函数
|
||||
function makeProject(overrides) {
|
||||
@@ -55,3 +55,91 @@ test("2-2 规整键:压缩连续斜杠并去除空段", () => {
|
||||
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));
|
||||
});
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 配置值校验器单元测试
|
||||
* 覆盖正则范围约束(/正则/ 格式)、既有区间/枚举约束
|
||||
* 运行:npm test
|
||||
*/
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert");
|
||||
const { validateByType, validateRange } = require("../src/utils/validator");
|
||||
|
||||
test("1-1 正则范围:手机号格式通过", () => {
|
||||
const range = "/^1[3-9]\\d{9}$/";
|
||||
assert.strictEqual(validateRange("13800138000", range).valid, true);
|
||||
});
|
||||
|
||||
test("1-2 正则范围:手机号格式不通过", () => {
|
||||
const range = "/^1[3-9]\\d{9}$/";
|
||||
assert.strictEqual(validateRange("2380013800", range).valid, false);
|
||||
});
|
||||
|
||||
test("1-3 正则范围:邮箱格式", () => {
|
||||
const range = "/^[\\w.%+-]+@[\\w.-]+\\.[A-Za-z]{2,}$/";
|
||||
assert.strictEqual(validateRange("user@example.com", range).valid, true);
|
||||
assert.strictEqual(validateRange("not-an-email", range).valid, false);
|
||||
});
|
||||
|
||||
test("1-4 正则范围:身份证(18 位)", () => {
|
||||
const range = "/^\\d{17}[\\dXx]$/";
|
||||
assert.strictEqual(validateRange("110101199003071234", range).valid, true);
|
||||
assert.strictEqual(validateRange("11010119900307", range).valid, false);
|
||||
});
|
||||
|
||||
test("1-5 正则范围:支持修饰符(i 忽略大小写)", () => {
|
||||
const range = "/^[A-Z]+$/i";
|
||||
assert.strictEqual(validateRange("abc", range).valid, true);
|
||||
assert.strictEqual(validateRange("abc1", range).valid, false);
|
||||
});
|
||||
|
||||
test("1-6 正则范围:无效正则返回错误提示", () => {
|
||||
const res = validateRange("abc", "/[/");
|
||||
assert.strictEqual(res.valid, false);
|
||||
assert.ok(res.message.includes("正则表达式无效"));
|
||||
});
|
||||
|
||||
test("1-7 正则格式:缺少结尾斜杠明确报格式错误(不静默放行)", () => {
|
||||
const res = validateRange("abc", "/abc");
|
||||
assert.strictEqual(res.valid, false);
|
||||
assert.ok(res.message.includes("正则格式无效"));
|
||||
});
|
||||
|
||||
test("1-8 正则格式:pattern 中未转义的斜杠报格式错误", () => {
|
||||
const res = validateRange("a/b", "/a/b/i");
|
||||
assert.strictEqual(res.valid, false);
|
||||
assert.ok(res.message.includes("正则格式无效"));
|
||||
});
|
||||
|
||||
test("1-9 正则格式:转义斜杠可用", () => {
|
||||
const res = validateRange("a/b", "/a\\/b/");
|
||||
assert.strictEqual(res.valid, true);
|
||||
});
|
||||
|
||||
test("1-10 正则范围:g 标志 test 多次结果稳定", () => {
|
||||
const range = "/^abc$/g";
|
||||
assert.strictEqual(validateRange("abc", range).valid, true);
|
||||
assert.strictEqual(validateRange("abc", range).valid, true);
|
||||
});
|
||||
|
||||
test("1-11 空值范围不做校验", () => {
|
||||
assert.strictEqual(validateRange("anything", "").valid, true);
|
||||
assert.strictEqual(validateRange("anything", " ").valid, true);
|
||||
});
|
||||
|
||||
test("1-12 正则格式:URL 预设(含转义斜杠)可正常校验", () => {
|
||||
const range = "/^https?:\\/\\/[\\w.-]+(?:\\.[a-zA-Z]{2,})?(?:\\/[^\\s]*)?$/";
|
||||
assert.strictEqual(validateRange("https://example.com/path", range).valid, true);
|
||||
assert.strictEqual(validateRange("not a url", range).valid, false);
|
||||
});
|
||||
|
||||
test("1-13 正则格式:非法 flags 报错", () => {
|
||||
const res = validateRange("abc", "/^abc$/q");
|
||||
assert.strictEqual(res.valid, false);
|
||||
assert.ok(res.message.includes("正则表达式无效") || res.message.includes("正则格式无效"));
|
||||
});
|
||||
|
||||
test("3-3 类型校验:number 拒绝 null", () => {
|
||||
assert.strictEqual(validateByType(null, "number").valid, false);
|
||||
});
|
||||
|
||||
test("2-1 区间范围仍生效", () => {
|
||||
assert.strictEqual(validateRange("50", "1-100").valid, true);
|
||||
assert.strictEqual(validateRange("150", "1-100").valid, false);
|
||||
});
|
||||
|
||||
test("2-2 区间下限大于上限时报错", () => {
|
||||
const res = validateRange("5", "10-1");
|
||||
assert.strictEqual(res.valid, false);
|
||||
assert.ok(res.message.includes("大于上限"));
|
||||
});
|
||||
|
||||
test("2-3 枚举范围仍生效", () => {
|
||||
assert.strictEqual(validateRange("A", "枚举: A,B,C").valid, true);
|
||||
assert.strictEqual(validateRange("D", "枚举: A,B,C").valid, false);
|
||||
});
|
||||
|
||||
test("3-1 类型校验:number 拒绝非数字", () => {
|
||||
assert.strictEqual(validateByType("abc", "number").valid, false);
|
||||
});
|
||||
|
||||
test("3-2 类型校验:number 拒绝空串(不再当作 0 放行)", () => {
|
||||
assert.strictEqual(validateByType("", "number").valid, false);
|
||||
});
|
||||
Reference in New Issue
Block a user