1package claudetool
2
3import (
4 "context"
5 "encoding/json"
6 "os"
7 "os/exec"
8 "path/filepath"
9 "testing"
10
11 "shelley.exe.dev/llm"
12)
13
14// Mock LLM provider for testing
15type mockLLMProvider struct{}
16
17type mockService struct{}
18
19func (m *mockService) Do(ctx context.Context, req *llm.Request) (*llm.Response, error) {
20 return &llm.Response{Content: llm.TextContent("test response")}, nil
21}
22
23func (m *mockService) TokenContextWindow() int {
24 return 4096
25}
26
27func (m *mockService) MaxImageDimension() int {
28 return 0
29}
30
31func (m *mockLLMProvider) GetService(modelID string) (llm.Service, error) {
32 return &mockService{}, nil
33}
34
35func (m *mockLLMProvider) GetAvailableModels() []string {
36 return []string{"test-model"}
37}
38
39func TestNewKeywordTool(t *testing.T) {
40 provider := &mockLLMProvider{}
41 tool := NewKeywordTool(provider)
42
43 if tool == nil {
44 t.Fatal("NewKeywordTool returned nil")
45 }
46}
47
48func TestNewKeywordToolWithWorkingDir(t *testing.T) {
49 provider := &mockLLMProvider{}
50 wd := NewMutableWorkingDir("/test")
51 tool := NewKeywordToolWithWorkingDir(provider, wd)
52
53 if tool == nil {
54 t.Fatal("NewKeywordToolWithWorkingDir returned nil")
55 }
56
57 if tool.workingDir != wd {
58 t.Error("workingDir not set correctly")
59 }
60}
61
62func TestKeywordTool_Tool(t *testing.T) {
63 provider := &mockLLMProvider{}
64 keywordTool := NewKeywordTool(provider)
65 tool := keywordTool.Tool()
66
67 if tool == nil {
68 t.Fatal("Tool() returned nil")
69 }
70
71 if tool.Name != keywordName {
72 t.Errorf("expected name %q, got %q", keywordName, tool.Name)
73 }
74
75 if tool.Description != keywordDescription {
76 t.Errorf("expected description %q, got %q", keywordDescription, tool.Description)
77 }
78
79 if tool.Run == nil {
80 t.Error("Run function not set")
81 }
82}
83
84func TestFindRepoRoot(t *testing.T) {
85 // Create a temp directory structure
86 tmpDir := t.TempDir()
87
88 // Test when not in a git repo (should fail)
89 _, err := FindRepoRoot(tmpDir)
90 if err == nil {
91 t.Error("expected error when not in git repo")
92 }
93
94 // Initialize a git repo properly
95 cmd := exec.Command("git", "init")
96 cmd.Dir = tmpDir
97 if err := cmd.Run(); err != nil {
98 t.Skip("git not available, skipping test")
99 }
100
101 // Test when in a git repo (should succeed)
102 root, err := FindRepoRoot(tmpDir)
103 if err != nil {
104 t.Errorf("unexpected error when in git repo: %v", err)
105 }
106
107 if root != tmpDir {
108 t.Errorf("expected root %q, got %q", tmpDir, root)
109 }
110}
111
112func TestKeywordRun(t *testing.T) {
113 if _, err := exec.LookPath("rg"); err != nil {
114 t.Skip("rg not installed, skipping test")
115 }
116
117 // Create a temp directory with some files
118 tmpDir := t.TempDir()
119 testFile := filepath.Join(tmpDir, "test.txt")
120 content := "This is a test file with some content for keyword search testing."
121 if err := os.WriteFile(testFile, []byte(content), 0o644); err != nil {
122 t.Fatal(err)
123 }
124
125 provider := &mockLLMProvider{}
126 wd := NewMutableWorkingDir(tmpDir)
127 keywordTool := NewKeywordToolWithWorkingDir(provider, wd)
128
129 // Test with valid input
130 input := keywordInput{
131 Query: "what files exist in this project",
132 SearchTerms: []string{"test", "file"},
133 }
134 inputBytes, err := json.Marshal(input)
135 if err != nil {
136 t.Fatal(err)
137 }
138
139 result := keywordTool.keywordRun(context.Background(), inputBytes)
140
141 if result.Error != nil {
142 t.Errorf("unexpected error: %v", result.Error)
143 }
144
145 if len(result.LLMContent) == 0 {
146 t.Error("expected LLM content")
147 }
148}