Skip to content

Commit ce29527

Browse files
test: 添加一大堆测试文件
1 parent 6f5623b commit ce29527

33 files changed

Lines changed: 3553 additions & 380 deletions

src/__tests__/Tool.test.ts

Lines changed: 178 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,207 @@
1-
import { describe, expect, test } from "bun:test";
1+
import { describe, expect, test } from 'bun:test'
22
import {
33
buildTool,
44
toolMatchesName,
55
findToolByName,
66
getEmptyToolPermissionContext,
77
filterToolProgressMessages,
8-
} from "../Tool";
8+
} from '../Tool'
99

1010
// Minimal tool definition for testing buildTool
1111
function makeMinimalToolDef(overrides: Record<string, unknown> = {}) {
1212
return {
13-
name: "TestTool",
14-
inputSchema: { type: "object" as const } as any,
13+
name: 'TestTool',
14+
inputSchema: { type: 'object' as const } as any,
1515
maxResultSizeChars: 10000,
16-
call: async () => ({ data: "ok" }),
17-
description: async () => "A test tool",
18-
prompt: async () => "test prompt",
19-
mapToolResultToToolResultBlockParam: (content: unknown, toolUseID: string) => ({
20-
type: "tool_result" as const,
16+
call: async () => ({ data: 'ok' }),
17+
description: async () => 'A test tool',
18+
prompt: async () => 'test prompt',
19+
mapToolResultToToolResultBlockParam: (
20+
content: unknown,
21+
toolUseID: string,
22+
) => ({
23+
type: 'tool_result' as const,
2124
tool_use_id: toolUseID,
2225
content: String(content),
2326
}),
2427
renderToolUseMessage: () => null,
2528
...overrides,
26-
};
29+
}
2730
}
2831

29-
describe("buildTool", () => {
30-
test("fills in default isEnabled as true", () => {
31-
const tool = buildTool(makeMinimalToolDef());
32-
expect(tool.isEnabled()).toBe(true);
33-
});
34-
35-
test("fills in default isConcurrencySafe as false", () => {
36-
const tool = buildTool(makeMinimalToolDef());
37-
expect(tool.isConcurrencySafe({})).toBe(false);
38-
});
39-
40-
test("fills in default isReadOnly as false", () => {
41-
const tool = buildTool(makeMinimalToolDef());
42-
expect(tool.isReadOnly({})).toBe(false);
43-
});
44-
45-
test("fills in default isDestructive as false", () => {
46-
const tool = buildTool(makeMinimalToolDef());
47-
expect(tool.isDestructive!({})).toBe(false);
48-
});
49-
50-
test("fills in default checkPermissions as allow", async () => {
51-
const tool = buildTool(makeMinimalToolDef());
52-
const input = { foo: "bar" };
53-
const result = await tool.checkPermissions(input, {} as any);
54-
expect(result).toEqual({ behavior: "allow", updatedInput: input });
55-
});
56-
57-
test("fills in default userFacingName from tool name", () => {
58-
const tool = buildTool(makeMinimalToolDef());
59-
expect(tool.userFacingName(undefined)).toBe("TestTool");
60-
});
61-
62-
test("fills in default toAutoClassifierInput as empty string", () => {
63-
const tool = buildTool(makeMinimalToolDef());
64-
expect(tool.toAutoClassifierInput({})).toBe("");
65-
});
66-
67-
test("preserves explicitly provided methods", () => {
32+
describe('buildTool', () => {
33+
test('fills in default isEnabled as true', () => {
34+
const tool = buildTool(makeMinimalToolDef())
35+
expect(tool.isEnabled()).toBe(true)
36+
})
37+
38+
test('fills in default isConcurrencySafe as false', () => {
39+
const tool = buildTool(makeMinimalToolDef())
40+
expect(tool.isConcurrencySafe({})).toBe(false)
41+
})
42+
43+
test('fills in default isReadOnly as false', () => {
44+
const tool = buildTool(makeMinimalToolDef())
45+
expect(tool.isReadOnly({})).toBe(false)
46+
})
47+
48+
test('fills in default isDestructive as false', () => {
49+
const tool = buildTool(makeMinimalToolDef())
50+
expect(tool.isDestructive!({})).toBe(false)
51+
})
52+
53+
test('fills in default checkPermissions as allow', async () => {
54+
const tool = buildTool(makeMinimalToolDef())
55+
const input = { foo: 'bar' }
56+
const result = await tool.checkPermissions(input, {} as any)
57+
expect(result).toEqual({ behavior: 'allow', updatedInput: input })
58+
})
59+
60+
test('fills in default userFacingName from tool name', () => {
61+
const tool = buildTool(makeMinimalToolDef())
62+
expect(tool.userFacingName(undefined)).toBe('TestTool')
63+
})
64+
65+
test('fills in default toAutoClassifierInput as empty string', () => {
66+
const tool = buildTool(makeMinimalToolDef())
67+
expect(tool.toAutoClassifierInput({})).toBe('')
68+
})
69+
70+
test('preserves explicitly provided methods', () => {
6871
const tool = buildTool(
6972
makeMinimalToolDef({
7073
isEnabled: () => false,
7174
isConcurrencySafe: () => true,
7275
isReadOnly: () => true,
73-
})
74-
);
75-
expect(tool.isEnabled()).toBe(false);
76-
expect(tool.isConcurrencySafe({})).toBe(true);
77-
expect(tool.isReadOnly({})).toBe(true);
78-
});
79-
80-
test("preserves all non-defaultable properties", () => {
81-
const tool = buildTool(makeMinimalToolDef());
82-
expect(tool.name).toBe("TestTool");
83-
expect(tool.maxResultSizeChars).toBe(10000);
84-
expect(typeof tool.call).toBe("function");
85-
expect(typeof tool.description).toBe("function");
86-
expect(typeof tool.prompt).toBe("function");
87-
});
88-
});
89-
90-
describe("toolMatchesName", () => {
91-
test("returns true for exact name match", () => {
92-
expect(toolMatchesName({ name: "Bash" }, "Bash")).toBe(true);
93-
});
94-
95-
test("returns false for non-matching name", () => {
96-
expect(toolMatchesName({ name: "Bash" }, "Read")).toBe(false);
97-
});
98-
99-
test("returns true when name matches an alias", () => {
76+
}),
77+
)
78+
expect(tool.isEnabled()).toBe(false)
79+
expect(tool.isConcurrencySafe({})).toBe(true)
80+
expect(tool.isReadOnly({})).toBe(true)
81+
})
82+
83+
test('preserves all non-defaultable properties', () => {
84+
const tool = buildTool(makeMinimalToolDef())
85+
expect(tool.name).toBe('TestTool')
86+
expect(tool.maxResultSizeChars).toBe(10000)
87+
expect(typeof tool.call).toBe('function')
88+
expect(typeof tool.description).toBe('function')
89+
expect(typeof tool.prompt).toBe('function')
90+
})
91+
})
92+
93+
describe('toolMatchesName', () => {
94+
test('returns true for exact name match', () => {
95+
expect(toolMatchesName({ name: 'Bash' }, 'Bash')).toBe(true)
96+
})
97+
98+
test('returns false for non-matching name', () => {
99+
expect(toolMatchesName({ name: 'Bash' }, 'Read')).toBe(false)
100+
})
101+
102+
test('returns true when name matches an alias', () => {
100103
expect(
101-
toolMatchesName({ name: "Bash", aliases: ["BashTool", "Shell"] }, "BashTool")
102-
).toBe(true);
103-
});
104-
105-
test("returns false when aliases is undefined", () => {
106-
expect(toolMatchesName({ name: "Bash" }, "BashTool")).toBe(false);
107-
});
108-
109-
test("returns false when aliases is empty", () => {
110-
expect(
111-
toolMatchesName({ name: "Bash", aliases: [] }, "BashTool")
112-
).toBe(false);
113-
});
114-
});
115-
116-
describe("findToolByName", () => {
104+
toolMatchesName(
105+
{ name: 'Bash', aliases: ['BashTool', 'Shell'] },
106+
'BashTool',
107+
),
108+
).toBe(true)
109+
})
110+
111+
test('returns false when aliases is undefined', () => {
112+
expect(toolMatchesName({ name: 'Bash' }, 'BashTool')).toBe(false)
113+
})
114+
115+
test('returns false when aliases is empty', () => {
116+
expect(toolMatchesName({ name: 'Bash', aliases: [] }, 'BashTool')).toBe(
117+
false,
118+
)
119+
})
120+
})
121+
122+
describe('findToolByName', () => {
117123
const mockTools = [
118-
buildTool(makeMinimalToolDef({ name: "Bash" })),
119-
buildTool(makeMinimalToolDef({ name: "Read", aliases: ["FileRead"] })),
120-
buildTool(makeMinimalToolDef({ name: "Edit" })),
121-
];
122-
123-
test("finds tool by primary name", () => {
124-
const tool = findToolByName(mockTools, "Bash");
125-
expect(tool).toBeDefined();
126-
expect(tool!.name).toBe("Bash");
127-
});
128-
129-
test("finds tool by alias", () => {
130-
const tool = findToolByName(mockTools, "FileRead");
131-
expect(tool).toBeDefined();
132-
expect(tool!.name).toBe("Read");
133-
});
134-
135-
test("returns undefined when no match", () => {
136-
expect(findToolByName(mockTools, "NonExistent")).toBeUndefined();
137-
});
138-
139-
test("returns first match when duplicates exist", () => {
124+
buildTool(makeMinimalToolDef({ name: 'Bash' })),
125+
buildTool(makeMinimalToolDef({ name: 'Read', aliases: ['FileRead'] })),
126+
buildTool(makeMinimalToolDef({ name: 'Edit' })),
127+
]
128+
129+
test('finds tool by primary name', () => {
130+
const tool = findToolByName(mockTools, 'Bash')
131+
expect(tool).toBeDefined()
132+
expect(tool!.name).toBe('Bash')
133+
})
134+
135+
test('finds tool by alias', () => {
136+
const tool = findToolByName(mockTools, 'FileRead')
137+
expect(tool).toBeDefined()
138+
expect(tool!.name).toBe('Read')
139+
})
140+
141+
test('returns undefined when no match', () => {
142+
expect(findToolByName(mockTools, 'NonExistent')).toBeUndefined()
143+
})
144+
145+
test('returns first match when duplicates exist', () => {
140146
const dupeTools = [
141-
buildTool(makeMinimalToolDef({ name: "Bash", maxResultSizeChars: 100 })),
142-
buildTool(makeMinimalToolDef({ name: "Bash", maxResultSizeChars: 200 })),
143-
];
144-
const tool = findToolByName(dupeTools, "Bash");
145-
expect(tool!.maxResultSizeChars).toBe(100);
146-
});
147-
});
148-
149-
describe("getEmptyToolPermissionContext", () => {
150-
test("returns default permission mode", () => {
151-
const ctx = getEmptyToolPermissionContext();
152-
expect(ctx.mode).toBe("default");
153-
});
154-
155-
test("returns empty maps and arrays", () => {
156-
const ctx = getEmptyToolPermissionContext();
157-
expect(ctx.additionalWorkingDirectories.size).toBe(0);
158-
expect(ctx.alwaysAllowRules).toEqual({});
159-
expect(ctx.alwaysDenyRules).toEqual({});
160-
expect(ctx.alwaysAskRules).toEqual({});
161-
});
162-
163-
test("returns isBypassPermissionsModeAvailable as false", () => {
164-
const ctx = getEmptyToolPermissionContext();
165-
expect(ctx.isBypassPermissionsModeAvailable).toBe(false);
166-
});
167-
});
168-
169-
describe("filterToolProgressMessages", () => {
170-
test("filters out hook_progress messages", () => {
147+
buildTool(makeMinimalToolDef({ name: 'Bash', maxResultSizeChars: 100 })),
148+
buildTool(makeMinimalToolDef({ name: 'Bash', maxResultSizeChars: 200 })),
149+
]
150+
const tool = findToolByName(dupeTools, 'Bash')
151+
expect(tool!.maxResultSizeChars).toBe(100)
152+
})
153+
})
154+
155+
describe('getEmptyToolPermissionContext', () => {
156+
test('returns default permission mode', () => {
157+
const ctx = getEmptyToolPermissionContext()
158+
expect(ctx.mode).toBe('default')
159+
})
160+
161+
test('returns empty maps and arrays', () => {
162+
const ctx = getEmptyToolPermissionContext()
163+
expect(ctx.additionalWorkingDirectories.size).toBe(0)
164+
expect(ctx.alwaysAllowRules).toEqual({})
165+
expect(ctx.alwaysDenyRules).toEqual({})
166+
expect(ctx.alwaysAskRules).toEqual({})
167+
})
168+
169+
test('returns isBypassPermissionsModeAvailable as false', () => {
170+
const ctx = getEmptyToolPermissionContext()
171+
expect(ctx.isBypassPermissionsModeAvailable).toBe(false)
172+
})
173+
})
174+
175+
describe('filterToolProgressMessages', () => {
176+
test('filters out hook_progress messages', () => {
171177
const messages = [
172-
{ data: { type: "hook_progress", hookName: "pre" } },
173-
{ data: { type: "tool_progress", toolName: "Bash" } },
174-
] as any[];
175-
const result = filterToolProgressMessages(messages);
176-
expect(result).toHaveLength(1);
177-
expect((result[0]!.data as any).type).toBe("tool_progress");
178-
});
179-
180-
test("keeps tool progress messages", () => {
178+
{ data: { type: 'hook_progress', hookName: 'pre' } },
179+
{ data: { type: 'tool_progress', toolName: 'Bash' } },
180+
] as any[]
181+
const result = filterToolProgressMessages(messages)
182+
expect(result).toHaveLength(1)
183+
expect((result[0]!.data as any).type).toBe('tool_progress')
184+
})
185+
186+
test('keeps tool progress messages', () => {
181187
const messages = [
182-
{ data: { type: "tool_progress", toolName: "Bash" } },
183-
{ data: { type: "tool_progress", toolName: "Read" } },
184-
] as any[];
185-
const result = filterToolProgressMessages(messages);
186-
expect(result).toHaveLength(2);
187-
});
188-
189-
test("returns empty array for empty input", () => {
190-
expect(filterToolProgressMessages([])).toEqual([]);
191-
});
192-
193-
test("handles messages without type field", () => {
188+
{ data: { type: 'tool_progress', toolName: 'Bash' } },
189+
{ data: { type: 'tool_progress', toolName: 'Read' } },
190+
] as any[]
191+
const result = filterToolProgressMessages(messages)
192+
expect(result).toHaveLength(2)
193+
})
194+
195+
test('returns empty array for empty input', () => {
196+
expect(filterToolProgressMessages([])).toEqual([])
197+
})
198+
199+
test('handles messages without type field', () => {
194200
const messages = [
195-
{ data: { toolName: "Bash" } },
196-
{ data: { type: "hook_progress" } },
197-
] as any[];
198-
const result = filterToolProgressMessages(messages);
199-
expect(result).toHaveLength(1);
200-
});
201-
});
201+
{ data: { toolName: 'Bash' } },
202+
{ data: { type: 'hook_progress' } },
203+
] as any[]
204+
const result = filterToolProgressMessages(messages)
205+
expect(result).toHaveLength(1)
206+
})
207+
})

0 commit comments

Comments
 (0)