mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
test: 添加一大堆测试文件
This commit is contained in:
121
src/services/compact/__tests__/grouping.test.ts
Normal file
121
src/services/compact/__tests__/grouping.test.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { groupMessagesByApiRound } from "../grouping";
|
||||
|
||||
function makeMsg(type: "user" | "assistant" | "system", id: string): any {
|
||||
return {
|
||||
type,
|
||||
message: { id, content: `${type}-${id}` },
|
||||
};
|
||||
}
|
||||
|
||||
describe("groupMessagesByApiRound", () => {
|
||||
// Boundary fires when: assistant msg with NEW id AND current group has items
|
||||
test("splits before first assistant if user messages precede it", () => {
|
||||
const messages = [makeMsg("user", "u1"), makeMsg("assistant", "a1")];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
// user msgs form group 1, assistant starts group 2
|
||||
expect(groups).toHaveLength(2);
|
||||
expect(groups[0]).toHaveLength(1);
|
||||
expect(groups[1]).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("single assistant message forms one group", () => {
|
||||
const messages = [makeMsg("assistant", "a1")];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("splits at new assistant message ID", () => {
|
||||
const messages = [
|
||||
makeMsg("user", "u1"),
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("assistant", "a2"),
|
||||
];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(3);
|
||||
});
|
||||
|
||||
test("keeps same-ID assistant messages in same group (streaming chunks)", () => {
|
||||
const messages = [
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("assistant", "a1"),
|
||||
];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0]).toHaveLength(3);
|
||||
});
|
||||
|
||||
test("returns empty array for empty input", () => {
|
||||
expect(groupMessagesByApiRound([])).toEqual([]);
|
||||
});
|
||||
|
||||
test("handles all user messages (no assistant)", () => {
|
||||
const messages = [makeMsg("user", "u1"), makeMsg("user", "u2")];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("three API rounds produce correct groups", () => {
|
||||
const messages = [
|
||||
makeMsg("user", "u1"),
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("user", "u2"),
|
||||
makeMsg("assistant", "a2"),
|
||||
makeMsg("user", "u3"),
|
||||
makeMsg("assistant", "a3"),
|
||||
];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
// [u1], [a1, u2], [a2, u3], [a3] = 4 groups
|
||||
expect(groups).toHaveLength(4);
|
||||
});
|
||||
|
||||
test("consecutive user messages stay in same group", () => {
|
||||
const messages = [makeMsg("user", "u1"), makeMsg("user", "u2")];
|
||||
expect(groupMessagesByApiRound(messages)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("does not produce empty groups", () => {
|
||||
const messages = [
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("assistant", "a2"),
|
||||
];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
for (const group of groups) {
|
||||
expect(group.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
test("handles single message", () => {
|
||||
expect(groupMessagesByApiRound([makeMsg("user", "u1")])).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("preserves message order within groups", () => {
|
||||
const messages = [makeMsg("assistant", "a1"), makeMsg("user", "u2")];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups[0][0].message.id).toBe("a1");
|
||||
expect(groups[0][1].message.id).toBe("u2");
|
||||
});
|
||||
|
||||
test("handles system messages", () => {
|
||||
const messages = [
|
||||
makeMsg("system", "s1"),
|
||||
makeMsg("assistant", "a1"),
|
||||
];
|
||||
// system msg is non-assistant, goes to current. Then assistant a1 is new ID
|
||||
// and current has items, so split.
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("tool_result after assistant stays in same round", () => {
|
||||
const messages = [
|
||||
makeMsg("assistant", "a1"),
|
||||
makeMsg("user", "tool_result_1"),
|
||||
makeMsg("assistant", "a1"), // same ID = no new boundary
|
||||
];
|
||||
const groups = groupMessagesByApiRound(messages);
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0]).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
77
src/services/compact/__tests__/prompt.test.ts
Normal file
77
src/services/compact/__tests__/prompt.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { mock, describe, expect, test } from "bun:test";
|
||||
|
||||
mock.module("bun:bundle", () => ({ feature: () => false }));
|
||||
|
||||
const { formatCompactSummary } = await import("../prompt");
|
||||
|
||||
describe("formatCompactSummary", () => {
|
||||
test("strips <analysis>...</analysis> block", () => {
|
||||
const input = "<analysis>my thought process</analysis>\n<summary>the summary</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).not.toContain("<analysis>");
|
||||
expect(result).not.toContain("my thought process");
|
||||
});
|
||||
|
||||
test("replaces <summary>...</summary> with 'Summary:\\n' prefix", () => {
|
||||
const input = "<summary>key points here</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).toContain("Summary:");
|
||||
expect(result).toContain("key points here");
|
||||
expect(result).not.toContain("<summary>");
|
||||
});
|
||||
|
||||
test("handles analysis + summary together", () => {
|
||||
const input = "<analysis>thinking</analysis><summary>result</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).not.toContain("thinking");
|
||||
expect(result).toContain("result");
|
||||
});
|
||||
|
||||
test("handles summary without analysis", () => {
|
||||
const input = "<summary>just the summary</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).toContain("just the summary");
|
||||
});
|
||||
|
||||
test("handles analysis without summary", () => {
|
||||
const input = "<analysis>just analysis</analysis>and some text";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).not.toContain("just analysis");
|
||||
expect(result).toContain("and some text");
|
||||
});
|
||||
|
||||
test("collapses multiple newlines to double", () => {
|
||||
const input = "hello\n\n\n\nworld";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).not.toMatch(/\n{3,}/);
|
||||
});
|
||||
|
||||
test("trims leading/trailing whitespace", () => {
|
||||
const input = " \n hello \n ";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).toBe("hello");
|
||||
});
|
||||
|
||||
test("handles empty string", () => {
|
||||
expect(formatCompactSummary("")).toBe("");
|
||||
});
|
||||
|
||||
test("handles plain text without tags", () => {
|
||||
const input = "just plain text";
|
||||
expect(formatCompactSummary(input)).toBe("just plain text");
|
||||
});
|
||||
|
||||
test("handles multiline analysis content", () => {
|
||||
const input = "<analysis>\nline1\nline2\nline3\n</analysis><summary>ok</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).not.toContain("line1");
|
||||
expect(result).toContain("ok");
|
||||
});
|
||||
|
||||
test("preserves content between analysis and summary", () => {
|
||||
const input = "<analysis>thoughts</analysis>middle text<summary>final</summary>";
|
||||
const result = formatCompactSummary(input);
|
||||
expect(result).toContain("middle text");
|
||||
expect(result).toContain("final");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user