单元测试(新增,node:test 零依赖): - tests/unit/: ulid / hmac / ed25519 / acl / validate 共 26 项用例 - 覆盖最关键的安全函数:签名验签、ACL 授权、参数校验 - 新增 pnpm test:unit;CI 增加单元测试步骤 细节修复: 1. screen.info 的 scale 硬编码为 1 → 改读注册表 HKCU AppliedDPI, 真实反映 Windows DPI 缩放(100% -> 1.0, 150% -> 1.5) 2. verify.mjs 升级:支持多设备配置(resolveTarget)+ ed25519 模式 + Hub 中转 (此前直接用旧的扁平配置 + 仅 psk,配了多设备会取不到 host) 验证:构建 + 类型检查全绿;单元 26/26;E2E 21/21;verify.mjs 13/0/3
83 lines
3.3 KiB
JavaScript
83 lines
3.3 KiB
JavaScript
import { test } from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import { validate, applyDefaults } from '../../packages/protocol/dist/index.js';
|
||
|
||
test('validate:基本类型', () => {
|
||
assert.deepEqual(validate('x', { type: 'string' }), []);
|
||
assert.deepEqual(validate(1, { type: 'integer' }), []);
|
||
assert.deepEqual(validate(1.5, { type: 'number' }), []);
|
||
assert.deepEqual(validate(true, { type: 'boolean' }), []);
|
||
assert.deepEqual(validate([], { type: 'array' }), []);
|
||
assert.deepEqual(validate({}, { type: 'object' }), []);
|
||
|
||
assert.ok(validate(1, { type: 'string' }).length > 0);
|
||
assert.ok(validate('x', { type: 'integer' }).length > 0);
|
||
assert.ok(validate(1.5, { type: 'integer' }).length > 0, '非整数应报错');
|
||
});
|
||
|
||
test('validate:enum', () => {
|
||
const schema = { type: 'string', enum: ['a', 'b'] };
|
||
assert.deepEqual(validate('a', schema), []);
|
||
assert.ok(validate('c', schema).length > 0, '不在枚举内应报错');
|
||
});
|
||
|
||
test('validate:数值范围', () => {
|
||
const schema = { type: 'number', minimum: 0, maximum: 10 };
|
||
assert.deepEqual(validate(5, schema), []);
|
||
assert.deepEqual(validate(0, schema), []);
|
||
assert.ok(validate(-1, schema).length > 0);
|
||
assert.ok(validate(11, schema).length > 0);
|
||
});
|
||
|
||
test('validate:字符串长度与 pattern', () => {
|
||
const schema = { type: 'string', minLength: 2, maxLength: 5, pattern: '^[a-z]+$' };
|
||
assert.deepEqual(validate('abc', schema), []);
|
||
assert.ok(validate('a', schema).length > 0, '过短');
|
||
assert.ok(validate('abcdef', schema).length > 0, '过长');
|
||
assert.ok(validate('ab1', schema).length > 0, '不匹配 pattern');
|
||
});
|
||
|
||
test('validate:数组长度与 items 类型', () => {
|
||
const schema = { type: 'array', minItems: 1, maxItems: 3, items: { type: 'integer' } };
|
||
assert.deepEqual(validate([1, 2], schema), []);
|
||
assert.ok(validate([], schema).length > 0, '空数组');
|
||
assert.ok(validate([1, 2, 3, 4], schema).length > 0, '超长');
|
||
assert.ok(validate([1, 'x'], schema).length > 0, 'item 类型错');
|
||
});
|
||
|
||
test('validate:required 与 additionalProperties', () => {
|
||
const schema = {
|
||
type: 'object',
|
||
properties: { name: { type: 'string' }, age: { type: 'integer' } },
|
||
required: ['name'],
|
||
additionalProperties: false,
|
||
};
|
||
assert.deepEqual(validate({ name: 'x', age: 1 }, schema), []);
|
||
assert.ok(validate({ age: 1 }, schema).length > 0, '缺 required');
|
||
assert.ok(validate({ name: 'x', extra: 1 }, schema).length > 0, '多余字段');
|
||
});
|
||
|
||
test('validate:嵌套路径正确', () => {
|
||
const schema = {
|
||
type: 'object',
|
||
properties: { filter: { type: 'object', properties: { pattern: { type: 'string' } } } },
|
||
};
|
||
assert.deepEqual(validate({ filter: { pattern: 'x' } }, schema), []);
|
||
const errs = validate({ filter: { pattern: 1 } }, schema);
|
||
assert.equal(errs.length, 1);
|
||
assert.ok(errs[0].includes('$.filter.pattern'), '错误应带嵌套路径');
|
||
});
|
||
|
||
test('applyDefaults:填补缺失字段,不覆盖已有值', () => {
|
||
const schema = {
|
||
type: 'object',
|
||
properties: {
|
||
limit: { type: 'integer', default: 20 },
|
||
recursive: { type: 'boolean', default: false },
|
||
},
|
||
};
|
||
const out = applyDefaults({ limit: 5 }, schema);
|
||
assert.equal(out.limit, 5, '已有值不被覆盖');
|
||
assert.equal(out.recursive, false, '缺失字段填默认值');
|
||
});
|