xdebug-mcp/internal/tools/tools_test.go
thibaud-leclere 8fafc4a69e feat: add analyze_profile tool
Implements the analyze_profile MCP tool with TDD: exports Analyze() for
direct testing, wraps it in AnalyzeHandler() for MCP, and adds AnalyzeTool()
for the schema definition. Adds mark3labs/mcp-go v0.52.0 dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 09:50:35 +02:00

61 lines
1.9 KiB
Go

package tools_test
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"forge.lclr.dev/AI/xdebug-mcp/internal/cachegrind"
"forge.lclr.dev/AI/xdebug-mcp/internal/tools"
)
func makeTestProfile() *cachegrind.Profile {
main := &cachegrind.Function{Name: "main", File: "index.php", Costs: []int64{3500, 1700}}
query := &cachegrind.Function{Name: "query", File: "index.php", Costs: []int64{2000, 900}}
connect := &cachegrind.Function{Name: "connect", File: "index.php", Costs: []int64{250, 100}}
call1 := &cachegrind.Call{Caller: main, Callee: query, Count: 1, Costs: []int64{1500, 700}}
call2 := &cachegrind.Call{Caller: query, Callee: connect, Count: 2, Costs: []int64{500, 200}}
main.Calls = []*cachegrind.Call{call1}
query.CalledBy = []*cachegrind.Call{call1}
query.Calls = []*cachegrind.Call{call2}
connect.CalledBy = []*cachegrind.Call{call2}
return &cachegrind.Profile{
Cmd: "index.php",
Events: []string{"Time_(10ns)", "Memory_(bytes)"},
Functions: []*cachegrind.Function{main, query, connect},
ByName: map[string][]*cachegrind.Function{
"main": {main},
"query": {query},
"connect": {connect},
},
}
}
func TestAnalyze_TopN(t *testing.T) {
p := makeTestProfile()
result := tools.Analyze(p, 3)
assert.Contains(t, result, "index.php")
assert.Contains(t, result, "Functions: 3 total")
assert.Contains(t, result, "main")
assert.Contains(t, result, "query")
assert.Contains(t, result, "connect")
// main must appear before query (higher cost)
assert.Less(t, strings.Index(result, "main"), strings.Index(result, "query"))
}
func TestAnalyze_TopNLimited(t *testing.T) {
p := makeTestProfile()
result := tools.Analyze(p, 1)
assert.Contains(t, result, "main")
assert.NotContains(t, result, "query") // only top 1
}
// require is used to avoid unused import error if tests change
var _ = require.New