| package tools |
| |
| import ( |
| "context" |
| "testing" |
| |
| "github.com/korap/korap-mcp/service" |
| "github.com/mark3labs/mcp-go/mcp" |
| "github.com/stretchr/testify/assert" |
| ) |
| |
| func TestSearchTool_Name(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| assert.Equal(t, "korap_search", tool.Name()) |
| } |
| |
| func TestSearchTool_Description(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| expected := "Search for words or phrases in KorAP corpora using various query languages" |
| assert.Equal(t, expected, tool.Description()) |
| } |
| |
| func TestSearchTool_InputSchema(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| schema := tool.InputSchema() |
| |
| // Verify it's an object type |
| assert.Equal(t, "object", schema["type"]) |
| |
| // Verify properties exist |
| properties, ok := schema["properties"].(map[string]interface{}) |
| assert.True(t, ok) |
| assert.Contains(t, properties, "query") |
| assert.Contains(t, properties, "query_language") |
| assert.Contains(t, properties, "corpus") |
| assert.Contains(t, properties, "count") |
| // Note: offset and context will be added in future iterations |
| |
| // Verify required fields |
| required, ok := schema["required"].([]string) |
| assert.True(t, ok) |
| assert.Contains(t, required, "query") |
| } |
| |
| func TestNewSearchTool(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| assert.NotNil(t, tool) |
| assert.Equal(t, client, tool.client) |
| } |
| |
| func TestSearchTool_Execute_MissingQuery(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| // Create request without query parameter |
| request := mcp.CallToolRequest{ |
| Params: mcp.CallToolParams{ |
| Arguments: map[string]interface{}{}, |
| }, |
| } |
| |
| _, err := tool.Execute(context.Background(), request) |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "query parameter is required") |
| } |
| |
| func TestSearchTool_Execute_NilClient(t *testing.T) { |
| tool := NewSearchTool(nil) |
| |
| request := mcp.CallToolRequest{ |
| Params: mcp.CallToolParams{ |
| Arguments: map[string]interface{}{ |
| "query": "test", |
| }, |
| }, |
| } |
| |
| _, err := tool.Execute(context.Background(), request) |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "KorAP client not configured") |
| } |
| |
| func TestSearchTool_Execute_ParameterExtraction(t *testing.T) { |
| // This test verifies that parameters are extracted correctly |
| // It should fail with authentication error since we don't have a mock server |
| // but we can verify the parameters were parsed correctly by checking the log messages |
| |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| tests := []struct { |
| name string |
| arguments map[string]interface{} |
| expectErr bool |
| }{ |
| { |
| name: "minimal_query", |
| arguments: map[string]interface{}{ |
| "query": "test", |
| }, |
| expectErr: true, // Will fail at authentication |
| }, |
| { |
| name: "full_parameters", |
| arguments: map[string]interface{}{ |
| "query": "word", |
| "query_language": "cosmas2", |
| "corpus": "test-corpus", |
| "count": 10, |
| }, |
| expectErr: true, // Will fail at authentication |
| }, |
| { |
| name: "invalid_count_type", |
| arguments: map[string]interface{}{ |
| "query": "test", |
| "count": "invalid", // Should use default |
| }, |
| expectErr: true, // Will fail at authentication |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| request := mcp.CallToolRequest{ |
| Params: mcp.CallToolParams{ |
| Arguments: tt.arguments, |
| }, |
| } |
| |
| _, err := tool.Execute(context.Background(), request) |
| if tt.expectErr { |
| assert.Error(t, err) |
| } |
| }) |
| } |
| } |
| |
| func TestSearchTool_formatSearchResults(t *testing.T) { |
| client := &service.Client{} |
| tool := NewSearchTool(client) |
| |
| // Test empty response |
| emptyResponse := &service.SearchResponse{ |
| Query: service.SearchQuery{ |
| Query: "test", |
| QueryLang: "poliqarp", |
| }, |
| Meta: service.SearchMeta{ |
| TotalResults: 0, |
| Count: 0, |
| StartIndex: 0, |
| }, |
| Matches: []service.SearchMatch{}, |
| } |
| |
| result := tool.formatSearchResults(emptyResponse) |
| assert.Contains(t, result, "KorAP Search Results") |
| assert.Contains(t, result, "Query: test") |
| assert.Contains(t, result, "Query Language: poliqarp") |
| assert.Contains(t, result, "Total Results: 0") |
| assert.Contains(t, result, "No matches found") |
| |
| // Test response with matches |
| responseWithMatches := &service.SearchResponse{ |
| Query: service.SearchQuery{ |
| Query: "word", |
| QueryLang: "poliqarp", |
| Collection: "test-corpus", |
| }, |
| Meta: service.SearchMeta{ |
| TotalResults: 5, |
| Count: 2, |
| StartIndex: 0, |
| SearchTime: 0.123, |
| }, |
| Matches: []service.SearchMatch{ |
| { |
| TextSigle: "text1", |
| Snippet: "This is a test snippet", |
| PubPlace: "Berlin", |
| MatchID: "match1", |
| Position: 10, |
| }, |
| { |
| TextSigle: "text2", |
| Snippet: "Another test snippet", |
| Position: 25, |
| }, |
| }, |
| } |
| |
| result = tool.formatSearchResults(responseWithMatches) |
| assert.Contains(t, result, "Query: word") |
| assert.Contains(t, result, "Query Language: poliqarp") |
| assert.Contains(t, result, "Corpus: test-corpus") |
| assert.Contains(t, result, "Total Results: 5") |
| assert.Contains(t, result, "Shown: 1-2") |
| assert.Contains(t, result, "Search Time: 0.123 seconds") |
| assert.Contains(t, result, "1. Text: text1") |
| assert.Contains(t, result, "Snippet: This is a test snippet") |
| assert.Contains(t, result, "Publication: Berlin") |
| assert.Contains(t, result, "2. Text: text2") |
| assert.Contains(t, result, "Position: 25") |
| |
| // Test response with warnings |
| responseWithWarnings := &service.SearchResponse{ |
| Query: service.SearchQuery{ |
| Query: "test", |
| CutOff: true, |
| TimeExceeded: true, |
| }, |
| Meta: service.SearchMeta{}, |
| Matches: []service.SearchMatch{}, |
| } |
| |
| result = tool.formatSearchResults(responseWithWarnings) |
| assert.Contains(t, result, "Results were cut off due to limits") |
| assert.Contains(t, result, "Search time limit was exceeded") |
| } |