Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

138 lines
4.8 KiB
Go

package mcp
import (
"strings"
"testing"
"github.com/zzet/gortex/internal/daemon"
)
// TestToolDescriptors_CoversEveryToolOnce asserts the catalog enumerates
// every registered tool — live and deferred — exactly once, with no
// duplicates, and that the total matches the raw live+deferred surface.
func TestToolDescriptors_CoversEveryToolOnce(t *testing.T) {
srv := newFullTestServer(t)
descs := srv.ToolDescriptors()
// Expected universe: the raw live MCP surface plus any deferred names.
expected := make(map[string]bool)
for name := range srv.mcpServer.ListTools() {
expected[name] = true
}
if srv.lazy != nil {
for _, name := range srv.lazy.DeferredNames() {
expected[name] = true
}
}
if len(descs) != len(expected) {
t.Errorf("ToolDescriptors returned %d descriptors, want %d (live+deferred)", len(descs), len(expected))
}
seen := make(map[string]int, len(descs))
for _, d := range descs {
seen[d.Name]++
}
for name, n := range seen {
if n != 1 {
t.Errorf("tool %q appears %d times in descriptors (want exactly 1)", name, n)
}
}
for name := range expected {
if _, ok := seen[name]; !ok {
t.Errorf("registered tool %q is missing from descriptors", name)
}
}
}
// TestToolDescriptors_NonEmptyCategory asserts every descriptor carries a
// category — toolCategory always classifies (falling back to "other"),
// so a blank category means the join broke.
func TestToolDescriptors_NonEmptyCategory(t *testing.T) {
srv := newFullTestServer(t)
for _, d := range srv.ToolDescriptors() {
if d.Category == "" {
t.Errorf("tool %q has an empty category", d.Name)
}
}
}
// TestToolDescriptors_MutatingMatchesDaemon asserts each descriptor's
// Mutating flag agrees with the authoritative daemon.MutatingTools set.
func TestToolDescriptors_MutatingMatchesDaemon(t *testing.T) {
srv := newFullTestServer(t)
for _, d := range srv.ToolDescriptors() {
if want := daemon.MutatingTools[d.Name]; d.Mutating != want {
t.Errorf("tool %q Mutating = %v, want %v (daemon.MutatingTools)", d.Name, d.Mutating, want)
}
}
}
// TestToolDescriptors_DescriptionNonEmptyAndTrimmed asserts every descriptor
// with a non-blank raw MCP description carries a matching, whitespace-trimmed
// Description, and that Summary is never longer than Description (Summary is
// derived from Description via firstSentence, so it can only truncate it).
func TestToolDescriptors_DescriptionNonEmptyAndTrimmed(t *testing.T) {
srv := newFullTestServer(t)
for _, d := range srv.ToolDescriptors() {
if d.Description != strings.TrimSpace(d.Description) {
t.Errorf("tool %q Description is not trimmed: %q", d.Name, d.Description)
}
if d.Summary != "" && len(d.Summary) > len(d.Description) {
t.Errorf("tool %q Summary (%q) is longer than Description (%q)", d.Name, d.Summary, d.Description)
}
if d.Description == "" && d.Summary != "" {
t.Errorf("tool %q has a Summary but an empty Description", d.Name)
}
}
}
// TestFirstSentence_DivergesFromDescriptionOnMultiSentenceInput asserts the
// Summary/Description split ToolDescriptors relies on: firstSentence
// truncates at the first ". " boundary, but a period immediately followed by
// a newline (no space) does not count as a boundary, so the whole
// (multi-line) description passes through unchanged.
func TestFirstSentence_DivergesFromDescriptionOnMultiSentenceInput(t *testing.T) {
tests := []struct {
name string
desc string
want string
}{
{"empty", "", ""},
{"whitespace only", " \n\t ", ""},
{"single sentence", "Show who calls a function", "Show who calls a function"},
{"multi-sentence period-space", "Show who calls a function. Returns the caller subgraph.", "Show who calls a function."},
{"period-newline is not a boundary", "Show who calls a function.\nReturns the caller subgraph.", "Show who calls a function.\nReturns the caller subgraph."},
{"leading/trailing whitespace trimmed", " Show who calls a function. ", "Show who calls a function."},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := firstSentence(tt.desc); got != tt.want {
t.Errorf("firstSentence(%q) = %q, want %q", tt.desc, got, tt.want)
}
})
}
}
// TestToolDescriptors_CorePresetMembership asserts every tool in the core
// preset roster carries "core" in its Presets — guarding the
// presetsContaining join against drift in the preset rosters.
func TestToolDescriptors_CorePresetMembership(t *testing.T) {
srv := newFullTestServer(t)
presets := make(map[string][]string)
for _, d := range srv.ToolDescriptors() {
presets[d.Name] = d.Presets
}
for _, name := range corePresetTools {
got, ok := presets[name]
if !ok {
t.Errorf("core preset tool %q not present in descriptors", name)
continue
}
if !containsString(got, "core") {
t.Errorf("core preset tool %q does not list \"core\" in its presets: %v", name, got)
}
}
}