blob: 59668778d35a71f6a33b6ff8cddd3efcb50d11b0 [file] [log] [blame]
Akronb1c71e62025-06-12 16:08:54 +02001package tools
2
3import (
Akron8138c352025-06-12 16:34:42 +02004 "context"
Akronb1c71e62025-06-12 16:08:54 +02005 "testing"
6
7 "github.com/korap/korap-mcp/service"
Akron8138c352025-06-12 16:34:42 +02008 "github.com/mark3labs/mcp-go/mcp"
Akronb1c71e62025-06-12 16:08:54 +02009 "github.com/stretchr/testify/assert"
10)
11
12func TestSearchTool_Name(t *testing.T) {
13 client := &service.Client{}
14 tool := NewSearchTool(client)
15
16 assert.Equal(t, "korap_search", tool.Name())
17}
18
19func TestSearchTool_Description(t *testing.T) {
20 client := &service.Client{}
21 tool := NewSearchTool(client)
22
23 expected := "Search for words or phrases in KorAP corpora using various query languages"
24 assert.Equal(t, expected, tool.Description())
25}
26
27func TestSearchTool_InputSchema(t *testing.T) {
28 client := &service.Client{}
29 tool := NewSearchTool(client)
30
31 schema := tool.InputSchema()
32
33 // Verify it's an object type
34 assert.Equal(t, "object", schema["type"])
35
36 // Verify properties exist
37 properties, ok := schema["properties"].(map[string]interface{})
38 assert.True(t, ok)
39 assert.Contains(t, properties, "query")
40 assert.Contains(t, properties, "query_language")
41 assert.Contains(t, properties, "corpus")
42 assert.Contains(t, properties, "count")
43 // Note: offset and context will be added in future iterations
44
45 // Verify required fields
46 required, ok := schema["required"].([]string)
47 assert.True(t, ok)
48 assert.Contains(t, required, "query")
49}
50
51func TestNewSearchTool(t *testing.T) {
52 client := &service.Client{}
53 tool := NewSearchTool(client)
54
55 assert.NotNil(t, tool)
56 assert.Equal(t, client, tool.client)
57}
58
Akron8138c352025-06-12 16:34:42 +020059func TestSearchTool_Execute_MissingQuery(t *testing.T) {
60 client := &service.Client{}
61 tool := NewSearchTool(client)
Akronb1c71e62025-06-12 16:08:54 +020062
Akron8138c352025-06-12 16:34:42 +020063 // Create request without query parameter
64 request := mcp.CallToolRequest{
65 Params: mcp.CallToolParams{
66 Arguments: map[string]interface{}{},
67 },
68 }
69
70 _, err := tool.Execute(context.Background(), request)
71 assert.Error(t, err)
72 assert.Contains(t, err.Error(), "query parameter is required")
73}
74
75func TestSearchTool_Execute_NilClient(t *testing.T) {
76 tool := NewSearchTool(nil)
77
78 request := mcp.CallToolRequest{
79 Params: mcp.CallToolParams{
80 Arguments: map[string]interface{}{
81 "query": "test",
82 },
83 },
84 }
85
86 _, err := tool.Execute(context.Background(), request)
87 assert.Error(t, err)
88 assert.Contains(t, err.Error(), "KorAP client not configured")
89}
90
91func TestSearchTool_Execute_ParameterExtraction(t *testing.T) {
92 // This test verifies that parameters are extracted correctly
93 // It should fail with authentication error since we don't have a mock server
94 // but we can verify the parameters were parsed correctly by checking the log messages
95
96 client := &service.Client{}
97 tool := NewSearchTool(client)
98
99 tests := []struct {
100 name string
101 arguments map[string]interface{}
102 expectErr bool
103 }{
104 {
105 name: "minimal_query",
106 arguments: map[string]interface{}{
107 "query": "test",
108 },
109 expectErr: true, // Will fail at authentication
110 },
111 {
112 name: "full_parameters",
113 arguments: map[string]interface{}{
114 "query": "word",
115 "query_language": "cosmas2",
116 "corpus": "test-corpus",
117 "count": 10,
118 },
119 expectErr: true, // Will fail at authentication
120 },
121 {
122 name: "invalid_count_type",
123 arguments: map[string]interface{}{
124 "query": "test",
125 "count": "invalid", // Should use default
126 },
127 expectErr: true, // Will fail at authentication
128 },
129 }
130
131 for _, tt := range tests {
132 t.Run(tt.name, func(t *testing.T) {
133 request := mcp.CallToolRequest{
134 Params: mcp.CallToolParams{
135 Arguments: tt.arguments,
136 },
137 }
138
139 _, err := tool.Execute(context.Background(), request)
140 if tt.expectErr {
141 assert.Error(t, err)
142 }
143 })
144 }
145}
146
147func TestSearchTool_formatSearchResults(t *testing.T) {
148 client := &service.Client{}
149 tool := NewSearchTool(client)
150
151 // Test empty response
152 emptyResponse := &service.SearchResponse{
153 Query: service.SearchQuery{
154 Query: "test",
155 QueryLang: "poliqarp",
156 },
157 Meta: service.SearchMeta{
158 TotalResults: 0,
159 Count: 0,
160 StartIndex: 0,
161 },
162 Matches: []service.SearchMatch{},
163 }
164
165 result := tool.formatSearchResults(emptyResponse)
166 assert.Contains(t, result, "KorAP Search Results")
167 assert.Contains(t, result, "Query: test")
168 assert.Contains(t, result, "Query Language: poliqarp")
169 assert.Contains(t, result, "Total Results: 0")
170 assert.Contains(t, result, "No matches found")
171
172 // Test response with matches
173 responseWithMatches := &service.SearchResponse{
174 Query: service.SearchQuery{
175 Query: "word",
176 QueryLang: "poliqarp",
177 Collection: "test-corpus",
178 },
179 Meta: service.SearchMeta{
180 TotalResults: 5,
181 Count: 2,
182 StartIndex: 0,
183 SearchTime: 0.123,
184 },
185 Matches: []service.SearchMatch{
186 {
187 TextSigle: "text1",
188 Snippet: "This is a test snippet",
189 PubPlace: "Berlin",
190 MatchID: "match1",
191 Position: 10,
192 },
193 {
194 TextSigle: "text2",
195 Snippet: "Another test snippet",
196 Position: 25,
197 },
198 },
199 }
200
201 result = tool.formatSearchResults(responseWithMatches)
202 assert.Contains(t, result, "Query: word")
203 assert.Contains(t, result, "Query Language: poliqarp")
204 assert.Contains(t, result, "Corpus: test-corpus")
205 assert.Contains(t, result, "Total Results: 5")
206 assert.Contains(t, result, "Shown: 1-2")
207 assert.Contains(t, result, "Search Time: 0.123 seconds")
208 assert.Contains(t, result, "1. Text: text1")
209 assert.Contains(t, result, "Snippet: This is a test snippet")
210 assert.Contains(t, result, "Publication: Berlin")
211 assert.Contains(t, result, "2. Text: text2")
212 assert.Contains(t, result, "Position: 25")
213
214 // Test response with warnings
215 responseWithWarnings := &service.SearchResponse{
216 Query: service.SearchQuery{
217 Query: "test",
218 CutOff: true,
219 TimeExceeded: true,
220 },
221 Meta: service.SearchMeta{},
222 Matches: []service.SearchMatch{},
223 }
224
225 result = tool.formatSearchResults(responseWithWarnings)
226 assert.Contains(t, result, "Results were cut off due to limits")
227 assert.Contains(t, result, "Search time limit was exceeded")
Akronb1c71e62025-06-12 16:08:54 +0200228}