package tools import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) // TestWebTool_WebFetch_Success verifies successful URL fetching func TestWebTool_WebFetch_Success(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) w.Write([]byte("

Test Page

Content here

")) })) defer server.Close() tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{ "url": server.URL, } result := tool.Execute(ctx, args) // Success should not be an error if result.IsError { t.Errorf("Expected success, got IsError=true: %s", result.ForLLM) } // ForUser should contain the fetched content if !strings.Contains(result.ForUser, "Test Page") { t.Errorf("Expected ForUser to contain 'Test Page', got: %s", result.ForUser) } // ForLLM should contain summary if !strings.Contains(result.ForLLM, "bytes") && !strings.Contains(result.ForLLM, "extractor") { t.Errorf("Expected ForLLM to contain summary, got: %s", result.ForLLM) } } // TestWebTool_WebFetch_JSON verifies JSON content handling func TestWebTool_WebFetch_JSON(t *testing.T) { testData := map[string]string{"key": "value", "number": "123"} expectedJSON, _ := json.MarshalIndent(testData, "", " ") server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write(expectedJSON) })) defer server.Close() tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{ "url": server.URL, } result := tool.Execute(ctx, args) // Success should not be an error if result.IsError { t.Errorf("Expected success, got IsError=true: %s", result.ForLLM) } // ForUser should contain formatted JSON if !strings.Contains(result.ForUser, "key") && !strings.Contains(result.ForUser, "value") { t.Errorf("Expected ForUser to contain JSON data, got: %s", result.ForUser) } } // TestWebTool_WebFetch_InvalidURL verifies error handling for invalid URL func TestWebTool_WebFetch_InvalidURL(t *testing.T) { tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{ "url": "not-a-valid-url", } result := tool.Execute(ctx, args) // Should return error result if !result.IsError { t.Errorf("Expected error for invalid URL") } // Should contain error message (either "invalid URL" or scheme error) if !strings.Contains(result.ForLLM, "URL") && !strings.Contains(result.ForUser, "URL") { t.Errorf("Expected error message for invalid URL, got ForLLM: %s", result.ForLLM) } } // TestWebTool_WebFetch_UnsupportedScheme verifies error handling for non-http URLs func TestWebTool_WebFetch_UnsupportedScheme(t *testing.T) { tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{ "url": "ftp://example.com/file.txt", } result := tool.Execute(ctx, args) // Should return error result if !result.IsError { t.Errorf("Expected error for unsupported URL scheme") } // Should mention only http/https allowed if !strings.Contains(result.ForLLM, "http/https") && !strings.Contains(result.ForUser, "http/https") { t.Errorf("Expected scheme error message, got ForLLM: %s", result.ForLLM) } } // TestWebTool_WebFetch_MissingURL verifies error handling for missing URL func TestWebTool_WebFetch_MissingURL(t *testing.T) { tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{} result := tool.Execute(ctx, args) // Should return error result if !result.IsError { t.Errorf("Expected error when URL is missing") } // Should mention URL is required if !strings.Contains(result.ForLLM, "url is required") && !strings.Contains(result.ForUser, "url is required") { t.Errorf("Expected 'url is required' message, got ForLLM: %s", result.ForLLM) } } // TestWebTool_WebFetch_Truncation verifies content truncation func TestWebTool_WebFetch_Truncation(t *testing.T) { longContent := strings.Repeat("x", 20000) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) w.Write([]byte(longContent)) })) defer server.Close() tool := NewWebFetchTool(1000) // Limit to 1000 chars ctx := context.Background() args := map[string]interface{}{ "url": server.URL, } result := tool.Execute(ctx, args) // Success should not be an error if result.IsError { t.Errorf("Expected success, got IsError=true: %s", result.ForLLM) } // ForUser should contain truncated content (not the full 20000 chars) resultMap := make(map[string]interface{}) json.Unmarshal([]byte(result.ForUser), &resultMap) if text, ok := resultMap["text"].(string); ok { if len(text) > 1100 { // Allow some margin t.Errorf("Expected content to be truncated to ~1000 chars, got: %d", len(text)) } } // Should be marked as truncated if truncated, ok := resultMap["truncated"].(bool); !ok || !truncated { t.Errorf("Expected 'truncated' to be true in result") } } // TestWebTool_WebSearch_NoApiKey verifies that no tool is created when API key is missing func TestWebTool_WebSearch_NoApiKey(t *testing.T) { tool := NewWebSearchTool(WebSearchToolOptions{BraveEnabled: true, BraveAPIKey: ""}) if tool != nil { t.Errorf("Expected nil tool when Brave API key is empty") } // Also nil when nothing is enabled tool = NewWebSearchTool(WebSearchToolOptions{}) if tool != nil { t.Errorf("Expected nil tool when no provider is enabled") } } // TestWebTool_WebSearch_MissingQuery verifies error handling for missing query func TestWebTool_WebSearch_MissingQuery(t *testing.T) { tool := NewWebSearchTool(WebSearchToolOptions{BraveEnabled: true, BraveAPIKey: "test-key", BraveMaxResults: 5}) ctx := context.Background() args := map[string]interface{}{} result := tool.Execute(ctx, args) // Should return error result if !result.IsError { t.Errorf("Expected error when query is missing") } } // TestWebTool_WebFetch_HTMLExtraction verifies HTML text extraction func TestWebTool_WebFetch_HTMLExtraction(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) w.Write([]byte(`

Title

Content

`)) })) defer server.Close() tool := NewWebFetchTool(50000) ctx := context.Background() args := map[string]interface{}{ "url": server.URL, } result := tool.Execute(ctx, args) // Success should not be an error if result.IsError { t.Errorf("Expected success, got IsError=true: %s", result.ForLLM) } // ForUser should contain extracted text (without script/style tags) if !strings.Contains(result.ForUser, "Title") && !strings.Contains(result.ForUser, "Content") { t.Errorf("Expected ForUser to contain extracted text, got: %s", result.ForUser) } // Should NOT contain script or style tags if strings.Contains(result.ForUser, "