返回 DeepSeek-Reasonix
message-pasted-blocks.test.ts
根目录 / desktop / frontend / src / __tests__ / message-pasted-blocks.test.ts
1 // Run: tsx src/__tests__/message-pasted-blocks.test.ts
2
3 import { parsePastedBlocks, parseSelectedTextBlocks } from "../components/Message";
4 import { formatSelectedTextContext, formatSelectionLabel, type SelectedTextReference } from "../lib/selectedTextContext";
5
6 let passed = 0;
7 let failed = 0;
8
9 function eq(a: unknown, b: unknown, label: string) {
10 if (JSON.stringify(a) === JSON.stringify(b)) {
11 process.stdout.write(` PASS ${label}\n`);
12 passed += 1;
13 } else {
14 process.stdout.write(` FAIL ${label}: expected ${JSON.stringify(b)}, got ${JSON.stringify(a)}\n`);
15 failed += 1;
16 }
17 }
18
19 function wrapped(label: string, content: string): string {
20 return `${label}\n\n--- Begin ${label} ---\n${content}\n--- End ${label} ---`;
21 }
22
23 console.log("\nmessage pasted blocks");
24
25 for (const [label, name] of [
26 ["[已粘贴文本 #2 · 31 行]", "Simplified Chinese"],
27 ["[已貼上文字 #2 · 31 行]", "Traditional Chinese"],
28 ["[Pasted text #2 · 31 lines]", "English"],
29 ] as const) {
30 eq(
31 parsePastedBlocks(`before\n${label}\nafter`, wrapped(label, "line 1\nline 2")),
32 [{ label, content: "line 1\nline 2\n" }],
33 `${name} pasted text labels are parsed from submit text`,
34 );
35 }
36
37 eq(parsePastedBlocks("[unknown paste #1]", "--- Begin [unknown paste #1] ---\nnope\n--- End [unknown paste #1] ---"), [], "unknown labels are ignored");
38
39 const repeatedPrefix = "same prefix selected text that is deliberately longer than forty characters";
40 const selections: SelectedTextReference[] = [
41 { id: "chat-1", text: `${repeatedPrefix} first` },
42 { id: "chat-2", text: `${repeatedPrefix} second` },
43 { id: "code-1", path: "src/a]b.ts", text: "if (ready) {\n run_task();\n}" },
44 ];
45 const labels = selections.map(formatSelectionLabel);
46 const authoredLabel = labels[0];
47 const display = `compare ${authoredLabel}\n${labels.join(" ")}`;
48 const selectedBlocks = parseSelectedTextBlocks(display, formatSelectedTextContext(selections));
49
50 eq(labels[2].includes("a]b.ts"), true, "selection labels sanitize closing brackets in file names");
51 eq(
52 selectedBlocks.map(({ label, content, path, kind }) => ({ label, content, path, kind })),
53 [
54 { label: labels[0], content: `${repeatedPrefix} first`, kind: "chat" },
55 { label: labels[1], content: `${repeatedPrefix} second`, kind: "chat" },
56 { label: labels[2], content: "if (ready) {\n run_task();\n}", path: "src/a]b.ts", kind: "code" },
57 ],
58 "selection cards recover duplicate snippets and bracketed file names from the existing JSON context",
59 );
60 eq(selectedBlocks[0]?.start, display.indexOf(labels[0], display.indexOf("\n") + 1), "label-shaped authored prose is not consumed as a selection card");
61 const unterminatedDisplay = `explain literal [Chat: ${labels.join(" ")}`;
62 let expectedLabelStart = unterminatedDisplay.length - labels.join(" ").length;
63 const expectedTrailingLabels = labels.map((label) => {
64 const expected = { label, start: expectedLabelStart };
65 expectedLabelStart += label.length + 1;
66 return expected;
67 });
68 eq(
69 parseSelectedTextBlocks(unterminatedDisplay, formatSelectedTextContext(selections)).map(({ label, start }) => ({ label, start })),
70 expectedTrailingLabels,
71 "unterminated label-shaped prose cannot consume the exact trailing selection labels",
72 );
73 eq(parsePastedBlocks(labels.join(" "), formatSelectedTextContext(selections)), [], "selection labels no longer use pasted-text marker parsing");
74
75 console.log(`\n${passed} passed, ${failed} failed`);
76 if (failed > 0) process.exit(1);
77
77 lines TYPESCRIPT