keyword_test.go

  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}