first commit
This commit is contained in:
132
apps/miniprogram/pages/terminal/vtParser.test.ts
Normal file
132
apps/miniprogram/pages/terminal/vtParser.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const {
|
||||
consumeTerminalSyncUpdateFrames,
|
||||
createTerminalSyncUpdateState,
|
||||
extractLooseAnsiSgr,
|
||||
takeTerminalReplaySlice
|
||||
} = require("./vtParser.js");
|
||||
|
||||
describe("vtParser", () => {
|
||||
it("不会把 CSI 控制序列从中间切开", () => {
|
||||
const result = takeTerminalReplaySlice("ab\u001b[31mcd", 4);
|
||||
|
||||
expect(result).toEqual({
|
||||
slice: "ab",
|
||||
rest: "\u001b[31mcd"
|
||||
});
|
||||
});
|
||||
|
||||
it("不会把 CRLF 从中间拆开", () => {
|
||||
expect(takeTerminalReplaySlice("ab\r\ncd", 3)).toEqual({
|
||||
slice: "ab",
|
||||
rest: "\r\ncd"
|
||||
});
|
||||
expect(takeTerminalReplaySlice("ab\r\ncd", 4)).toEqual({
|
||||
slice: "ab\r\n",
|
||||
rest: "cd"
|
||||
});
|
||||
});
|
||||
|
||||
it("文本开头是完整长控制序列时会整段前进,避免卡死在零进度", () => {
|
||||
const result = takeTerminalReplaySlice("\u001b]10;?\u001b\\X", 3);
|
||||
|
||||
expect(result).toEqual({
|
||||
slice: "\u001b]10;?\u001b\\",
|
||||
rest: "X"
|
||||
});
|
||||
});
|
||||
|
||||
it("文本前缀是不完整控制序列时会返回空 slice,交由上层缓存尾巴", () => {
|
||||
const result = takeTerminalReplaySlice("\u001b[31", 16);
|
||||
|
||||
expect(result).toEqual({
|
||||
slice: "",
|
||||
rest: "\u001b[31"
|
||||
});
|
||||
});
|
||||
|
||||
it("会识别不带 ESC 的松散 SGR 复位片段", () => {
|
||||
expect(extractLooseAnsiSgr("39mtext", 0)).toEqual({
|
||||
end: 2,
|
||||
codes: [39]
|
||||
});
|
||||
expect(extractLooseAnsiSgr("[1;31mtext", 0)).toEqual({
|
||||
end: 5,
|
||||
codes: [1, 31]
|
||||
});
|
||||
});
|
||||
|
||||
it("非可信 SGR 数字串不会被误识别成样式序列", () => {
|
||||
expect(extractLooseAnsiSgr("123mtext", 0)).toBeNull();
|
||||
});
|
||||
|
||||
it("会把 `CSI ? 2026 h/l` 包裹的同步刷新窗口延后到结束时一次性吐出", () => {
|
||||
const first = consumeTerminalSyncUpdateFrames(
|
||||
"ab\u001b[?2026hcd",
|
||||
createTerminalSyncUpdateState()
|
||||
);
|
||||
|
||||
expect(first.text).toBe("ab");
|
||||
expect(first.state).toEqual({
|
||||
depth: 1,
|
||||
carryText: "",
|
||||
bufferedText: "cd"
|
||||
});
|
||||
|
||||
const second = consumeTerminalSyncUpdateFrames("ef\u001b[?2026lg", first.state);
|
||||
|
||||
expect(second.text).toBe("cdefg");
|
||||
expect(second.state).toEqual({
|
||||
depth: 0,
|
||||
carryText: "",
|
||||
bufferedText: ""
|
||||
});
|
||||
});
|
||||
|
||||
it("同步刷新起始序列若被 chunk 边界截断,会保留到下一帧继续拼", () => {
|
||||
const first = consumeTerminalSyncUpdateFrames(
|
||||
"ab\u001b[?2026",
|
||||
createTerminalSyncUpdateState()
|
||||
);
|
||||
|
||||
expect(first.text).toBe("ab");
|
||||
expect(first.state).toEqual({
|
||||
depth: 0,
|
||||
carryText: "\u001b[?2026",
|
||||
bufferedText: ""
|
||||
});
|
||||
|
||||
const second = consumeTerminalSyncUpdateFrames("hcd\u001b[?2026l", first.state);
|
||||
|
||||
expect(second.text).toBe("cd");
|
||||
expect(second.state).toEqual({
|
||||
depth: 0,
|
||||
carryText: "",
|
||||
bufferedText: ""
|
||||
});
|
||||
});
|
||||
|
||||
it("会按和 web 端一致的口径收口 `DCS = 1 s / = 2 s` 同步刷新窗口", () => {
|
||||
const first = consumeTerminalSyncUpdateFrames(
|
||||
"ab\u001bP=1s\u001b\\cd",
|
||||
createTerminalSyncUpdateState()
|
||||
);
|
||||
|
||||
expect(first.text).toBe("ab");
|
||||
expect(first.state).toEqual({
|
||||
depth: 1,
|
||||
carryText: "",
|
||||
bufferedText: "cd"
|
||||
});
|
||||
|
||||
const second = consumeTerminalSyncUpdateFrames("ef\u001bP=2s\u001b\\g", first.state);
|
||||
|
||||
expect(second.text).toBe("cdefg");
|
||||
expect(second.state).toEqual({
|
||||
depth: 0,
|
||||
carryText: "",
|
||||
bufferedText: ""
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user