package antigravity import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/require" ) func TestNormalizeClaudeCodeToolName(t *testing.T) { t.Parallel() tests := []struct { name string input string expected string }{ {name: "read alias", input: "read_file", expected: "Read"}, {name: "grep alias", input: "search_files", expected: "Grep"}, {name: "webfetch alias", input: "fetch", expected: "WebFetch"}, {name: "plan alias", input: "enter_plan_mode", expected: "EnterPlanMode"}, {name: "native passthrough", input: "TaskUpdate", expected: "TaskUpdate"}, {name: "mcp passthrough", input: "mcp__github__list_prs", expected: "mcp__github__list_prs"}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal(t, tt.expected, normalizeClaudeCodeToolName(tt.input)) }) } } func TestBuildPartsNormalizesClaudeCodeToolNames(t *testing.T) { t.Parallel() toolIDToName := make(map[string]string) assistantParts, stripped, err := buildParts(json.RawMessage(`[ {"type":"tool_use","id":"tool-1","name":"read_file","input":{"file_path":"/tmp/demo.txt"}} ]`), toolIDToName, false, false) require.NoError(t, err) require.False(t, stripped) require.Len(t, assistantParts, 1) require.NotNil(t, assistantParts[0].FunctionCall) require.Equal(t, "Read", assistantParts[0].FunctionCall.Name) require.Equal(t, "Read", toolIDToName["tool-1"]) userParts, stripped, err := buildParts(json.RawMessage(`[ {"type":"tool_result","tool_use_id":"tool-1","content":[{"type":"text","text":"ok"}]} ]`), toolIDToName, false, true) require.NoError(t, err) require.False(t, stripped) require.Len(t, userParts, 1) require.NotNil(t, userParts[0].FunctionResponse) require.Equal(t, "Read", userParts[0].FunctionResponse.Name) } func TestBuildToolsNormalizesClaudeCodeBuiltinNamesOnly(t *testing.T) { t.Parallel() result := buildTools([]ClaudeTool{ { Name: "search_files", Description: "Search the workspace", InputSchema: map[string]any{ "type": "object", }, }, { Name: "mcp__github__list_prs", Description: "List pull requests", InputSchema: map[string]any{ "type": "object", }, }, }) require.Len(t, result, 1) require.Len(t, result[0].FunctionDeclarations, 2) require.Equal(t, "Grep", result[0].FunctionDeclarations[0].Name) require.Equal(t, "mcp__github__list_prs", result[0].FunctionDeclarations[1].Name) } func TestNonStreamingProcessorNormalizesClaudeCodeToolName(t *testing.T) { t.Parallel() processor := NewNonStreamingProcessor() response := processor.Process(&GeminiResponse{ Candidates: []GeminiCandidate{ { Content: &GeminiContent{ Parts: []GeminiPart{ { FunctionCall: &GeminiFunctionCall{ Name: "web_fetch", Args: map[string]any{"url": "https://example.com"}, }, }, }, }, FinishReason: "STOP", }, }, }, "resp-1", "claude-sonnet-4-5") require.Len(t, response.Content, 1) require.Equal(t, "tool_use", response.Content[0].Type) require.Equal(t, "WebFetch", response.Content[0].Name) require.True(t, strings.HasPrefix(response.Content[0].ID, "WebFetch-")) require.NotNil(t, response.Content[0].Caller) require.Equal(t, "direct", response.Content[0].Caller.Type) require.Equal(t, "tool_use", response.StopReason) } func TestStreamingProcessorNormalizesClaudeCodeToolName(t *testing.T) { t.Parallel() processor := NewStreamingProcessor("claude-sonnet-4-5") output := processor.processFunctionCall(&GeminiFunctionCall{ Name: "search_files", Args: map[string]any{"pattern": "TODO"}, }, "") events := parseSSEDataEvents(t, output) require.Len(t, events, 3) contentBlock, ok := events[0]["content_block"].(map[string]any) require.True(t, ok) require.Equal(t, "tool_use", contentBlock["type"]) require.Equal(t, "Grep", contentBlock["name"]) toolID, ok := contentBlock["id"].(string) require.True(t, ok) require.True(t, strings.HasPrefix(toolID, "Grep-")) caller, ok := contentBlock["caller"].(map[string]any) require.True(t, ok) require.Equal(t, "direct", caller["type"]) } func parseSSEDataEvents(t *testing.T, payload []byte) []map[string]any { t.Helper() lines := strings.Split(string(payload), "\n") events := make([]map[string]any, 0) for _, line := range lines { if !strings.HasPrefix(line, "data: ") { continue } var event map[string]any require.NoError(t, json.Unmarshal([]byte(strings.TrimPrefix(line, "data: ")), &event)) events = append(events, event) } return events }