255 lines
7.1 KiB
JavaScript
255 lines
7.1 KiB
JavaScript
"use strict";
|
|
|
|
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const run = async () => {
|
|
const source = fs.readFileSync(
|
|
path.join(__dirname, "../utils/generation-poem.js"),
|
|
"utf8",
|
|
);
|
|
const moduleUrl = `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`;
|
|
const {
|
|
MAX_GENERATION_NO,
|
|
MAX_GENERATION_COUNT,
|
|
MAX_GENERATION_TEXT_LENGTH,
|
|
MAX_GENERATION_POEM_INPUT_LENGTH,
|
|
GENERATION_POEM_STATUS,
|
|
normalizeGenerationNumber,
|
|
validateGenerationPoemText,
|
|
findFirstGenerationGap,
|
|
mergeGenerationPoemRows,
|
|
} = await import(moduleUrl);
|
|
|
|
assert.strictEqual(MAX_GENERATION_COUNT, 500);
|
|
assert.strictEqual(MAX_GENERATION_TEXT_LENGTH, 50);
|
|
assert.strictEqual(MAX_GENERATION_POEM_INPUT_LENGTH, 26000);
|
|
assert.deepStrictEqual(GENERATION_POEM_STATUS, {
|
|
ACTIVE: "0",
|
|
DISABLED: "1",
|
|
});
|
|
assert.strictEqual(normalizeGenerationNumber(undefined, 12), 12);
|
|
assert.strictEqual(normalizeGenerationNumber("300", 12), 300);
|
|
for (const invalid of [
|
|
"0",
|
|
"1.5",
|
|
"1e2",
|
|
"Infinity",
|
|
Infinity,
|
|
NaN,
|
|
MAX_GENERATION_NO + 1,
|
|
]) {
|
|
assert.strictEqual(
|
|
normalizeGenerationNumber(invalid, 12),
|
|
null,
|
|
`非法代次未拒绝:${invalid}`,
|
|
);
|
|
}
|
|
|
|
assert.deepStrictEqual(validateGenerationPoemText("启宗敦本").generations, [
|
|
"启",
|
|
"宗",
|
|
"敦",
|
|
"本",
|
|
]);
|
|
assert.deepStrictEqual(
|
|
validateGenerationPoemText("克勤 克俭,承先;启后、敦本/睦族|传芳").generations,
|
|
["克勤", "克俭", "承先", "启后", "敦本", "睦族", "传芳"],
|
|
"OpenAPI 声明的分隔符必须统一解析多字字辈",
|
|
);
|
|
assert.deepStrictEqual(
|
|
validateGenerationPoemText("德承家亦\n忠厚传芳").generations,
|
|
["德承家亦", "忠厚传芳"],
|
|
);
|
|
assert.strictEqual(
|
|
validateGenerationPoemText("𠀀").valid,
|
|
true,
|
|
"扩展区字符必须按一个 code point 计数",
|
|
);
|
|
assert.strictEqual(validateGenerationPoemText("").valid, false);
|
|
assert.strictEqual(validateGenerationPoemText("启".repeat(501)).valid, false);
|
|
assert.strictEqual(
|
|
validateGenerationPoemText(`${"启".repeat(51)} 宗`).valid,
|
|
false,
|
|
);
|
|
assert.strictEqual(
|
|
validateGenerationPoemText("启".repeat(MAX_GENERATION_POEM_INPUT_LENGTH + 1)).valid,
|
|
false,
|
|
);
|
|
|
|
assert.throws(
|
|
() =>
|
|
mergeGenerationPoemRows({
|
|
existingRows: [],
|
|
generationTexts: ["启", "宗"],
|
|
startGeneration: MAX_GENERATION_NO,
|
|
currentGeneration: MAX_GENERATION_NO,
|
|
disableMissing: false,
|
|
}),
|
|
/超出支持范围/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
mergeGenerationPoemRows({
|
|
existingRows: [],
|
|
generationTexts: Array.from({ length: 501 }, () => "启"),
|
|
startGeneration: 1,
|
|
currentGeneration: 1,
|
|
disableMissing: false,
|
|
}),
|
|
/最多 500 个世代/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
mergeGenerationPoemRows({
|
|
existingRows: [],
|
|
generationTexts: ["启"],
|
|
startGeneration: 1,
|
|
currentGeneration: 1,
|
|
disableMissing: "false",
|
|
}),
|
|
/disableMissing/,
|
|
);
|
|
|
|
const contiguous = [
|
|
{ generationNo: 12, generationText: "启", status: "0" },
|
|
{ generationNo: 13, generationText: "宗", status: "0" },
|
|
{ generationNo: 14, generationText: "敦", status: "0" },
|
|
];
|
|
assert.strictEqual(findFirstGenerationGap(contiguous, 15), null);
|
|
assert.strictEqual(
|
|
findFirstGenerationGap([contiguous[0], contiguous[2]], 15),
|
|
13,
|
|
"历史缺口必须定位到首个缺失世代",
|
|
);
|
|
assert.strictEqual(
|
|
findFirstGenerationGap([{ generationNo: 5, status: "0" }], 6, 1),
|
|
1,
|
|
"完整序列必须从第一世检查前缀缺口",
|
|
);
|
|
assert.strictEqual(
|
|
findFirstGenerationGap(
|
|
[
|
|
{ generationNo: 1, status: "0" },
|
|
{ generationNo: 2, status: "0" },
|
|
{ generationNo: 5, status: "0" },
|
|
],
|
|
6,
|
|
1,
|
|
),
|
|
3,
|
|
"保留后续 ACTIVE 记录时不能留下中间缺口",
|
|
);
|
|
assert.strictEqual(
|
|
findFirstGenerationGap(
|
|
[
|
|
{ generationNo: 1, status: "0" },
|
|
{ generationNo: 2, status: "1" },
|
|
{ generationNo: 3, status: "0" },
|
|
],
|
|
4,
|
|
1,
|
|
),
|
|
2,
|
|
"DISABLED 记录不能填补 ACTIVE 序列缺口",
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
mergeGenerationPoemRows({
|
|
existingRows: [
|
|
{ generationNo: 1, generationText: "启", status: "UNKNOWN" },
|
|
],
|
|
generationTexts: ["宗"],
|
|
startGeneration: 2,
|
|
currentGeneration: 2,
|
|
disableMissing: false,
|
|
}),
|
|
/GenerationPoemView/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
mergeGenerationPoemRows({
|
|
existingRows: [
|
|
{ generationNo: 1, generationText: "启", status: "0" },
|
|
{ generationNo: 1, generationText: "宗", status: "1" },
|
|
],
|
|
generationTexts: ["敦"],
|
|
startGeneration: 2,
|
|
currentGeneration: 2,
|
|
disableMissing: false,
|
|
}),
|
|
/重复的世代记录/,
|
|
"同一世代存在多条记录时必须失败关闭,不能静默 last-wins",
|
|
);
|
|
|
|
const preserved = mergeGenerationPoemRows({
|
|
existingRows: [
|
|
...contiguous,
|
|
{ poemId: "9007199254740993", generationNo: 15, generationText: "本", status: "0" },
|
|
{ generationNo: 16, generationText: "继", status: "0" },
|
|
],
|
|
generationTexts: ["克勤"],
|
|
startGeneration: 15,
|
|
currentGeneration: 15,
|
|
disableMissing: false,
|
|
});
|
|
assert.deepStrictEqual(
|
|
preserved.map(({ generationNo, generationText, status }) => ({
|
|
generationNo,
|
|
generationText,
|
|
status,
|
|
})),
|
|
[
|
|
{ generationNo: 12, generationText: "启", status: "0" },
|
|
{ generationNo: 13, generationText: "宗", status: "0" },
|
|
{ generationNo: 14, generationText: "敦", status: "0" },
|
|
{ generationNo: 15, generationText: "克勤", status: "0" },
|
|
{ generationNo: 16, generationText: "继", status: "0" },
|
|
],
|
|
);
|
|
assert.strictEqual(
|
|
preserved.find((row) => row.generationNo === 15)?.poemId,
|
|
"9007199254740993",
|
|
"覆盖文字时必须保留词法 int64 记录身份",
|
|
);
|
|
|
|
const disabled = mergeGenerationPoemRows({
|
|
existingRows: preserved,
|
|
generationTexts: ["昭穆"],
|
|
startGeneration: 15,
|
|
currentGeneration: 15,
|
|
disableMissing: true,
|
|
});
|
|
assert.strictEqual(
|
|
disabled.find((row) => row.generationNo === 12)?.generationText,
|
|
"启",
|
|
);
|
|
assert.strictEqual(
|
|
disabled.find((row) => row.generationNo === 16)?.status,
|
|
"1",
|
|
);
|
|
assert.strictEqual(
|
|
disabled.find((row) => row.generationNo === 16)?.generationText,
|
|
"继",
|
|
);
|
|
|
|
const maximumBatch = mergeGenerationPoemRows({
|
|
existingRows: [],
|
|
generationTexts: Array.from({ length: MAX_GENERATION_COUNT }, () => "启"),
|
|
startGeneration: 1,
|
|
currentGeneration: 500,
|
|
disableMissing: false,
|
|
});
|
|
assert.strictEqual(maximumBatch.length, 500);
|
|
assert.strictEqual(maximumBatch[499].generationNo, 500);
|
|
assert.strictEqual(maximumBatch[499].current, true);
|
|
|
|
process.stdout.write("GENERATION-POEM-RUNTIME-SMOKE PASS\n");
|
|
};
|
|
|
|
run().catch((error) => {
|
|
process.stderr.write(`${error.stack || error.message}\n`);
|
|
process.exit(1);
|
|
});
|