package tools_test import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "gitea.d-ma.be/mathias/gitea-mcp/internal/allowlist" "gitea.d-ma.be/mathias/gitea-mcp/internal/gitea" "gitea.d-ma.be/mathias/gitea-mcp/internal/tools" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // #36: every caller (claude.ai connector, gitea's own convention) sends the // repo identifier as `repo` and issue/PR index as `index`, but the tools // declare them as `name` and `number`. Unmatched fields zero-valued the path // segment and produced gitea's misleading /api/swagger 404. parseArgs now // aliases repo->name and index->number so the idiomatic call works. func TestRepoAndIndexAliasesResolve(t *testing.T) { tests := []struct { name string args string wantPath string }{ {"repo+index aliases", `{"owner":"mathias","repo":"infra","index":7}`, "/api/v1/repos/mathias/infra/issues/7"}, {"canonical name+number", `{"owner":"mathias","name":"infra","number":7}`, "/api/v1/repos/mathias/infra/issues/7"}, {"explicit name wins over repo", `{"owner":"mathias","name":"infra","repo":"ignored","number":7}`, "/api/v1/repos/mathias/infra/issues/7"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { var gotPath string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotPath = r.URL.Path w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"number":7,"title":"t"}`)) })) defer srv.Close() tool := tools.NewIssueGet(gitea.NewClient(srv.URL, "tok"), allowlist.New([]string{"mathias"})) out, err := tool.Call(context.Background(), json.RawMessage(tc.args)) require.NoError(t, err) assert.Equal(t, tc.wantPath, gotPath) assert.Contains(t, string(out), `"number":7`) }) } }