package tools import ( "context" "encoding/json" "errors" "testing" "git.warky.dev/wdevs/amcs/internal/mcperrors" "github.com/modelcontextprotocol/go-sdk/jsonrpc" ) func TestResolveProjectRequiredErrorGuidesCaller(t *testing.T) { _, err := resolveProject(context.Background(), nil, nil, nil, "", true) if err == nil { t.Fatal("resolveProject() error = nil, want error") } rpcErr, data := requireRPCError(t, err) if rpcErr.Code != codeProjectRequired { t.Fatalf("resolveProject() code = %d, want %d", rpcErr.Code, codeProjectRequired) } if data.Type != mcperrors.TypeProjectRequired { t.Fatalf("resolveProject() type = %q, want %q", data.Type, mcperrors.TypeProjectRequired) } if data.Field != "project" { t.Fatalf("resolveProject() field = %q, want %q", data.Field, "project") } if data.Hint == "" { t.Fatal("resolveProject() hint = empty, want guidance") } } func TestSessionIDErrorGuidesCaller(t *testing.T) { _, err := sessionID(nil) if err == nil { t.Fatal("sessionID() error = nil, want error") } rpcErr, data := requireRPCError(t, err) if rpcErr.Code != codeSessionRequired { t.Fatalf("sessionID() code = %d, want %d", rpcErr.Code, codeSessionRequired) } if data.Type != mcperrors.TypeSessionRequired { t.Fatalf("sessionID() type = %q, want %q", data.Type, mcperrors.TypeSessionRequired) } if data.Hint == "" { t.Fatal("sessionID() hint = empty, want guidance") } } func TestParseUUIDReturnsTypedError(t *testing.T) { _, err := parseUUID("not-a-uuid") if err == nil { t.Fatal("parseUUID() error = nil, want error") } rpcErr, data := requireRPCError(t, err) if rpcErr.Code != codeInvalidID { t.Fatalf("parseUUID() code = %d, want %d", rpcErr.Code, codeInvalidID) } if data.Type != mcperrors.TypeInvalidID { t.Fatalf("parseUUID() type = %q, want %q", data.Type, mcperrors.TypeInvalidID) } if data.Field != "id" { t.Fatalf("parseUUID() field = %q, want %q", data.Field, "id") } if data.Value != "not-a-uuid" { t.Fatalf("parseUUID() value = %q, want %q", data.Value, "not-a-uuid") } if data.Detail == "" { t.Fatal("parseUUID() detail = empty, want parse failure detail") } } func TestErrInvalidInputReturnsTypedError(t *testing.T) { err := errInvalidInput("name is required") if err == nil { t.Fatal("errInvalidInput() error = nil, want error") } rpcErr, data := requireRPCError(t, err) if rpcErr.Code != jsonrpc.CodeInvalidParams { t.Fatalf("errInvalidInput() code = %d, want %d", rpcErr.Code, jsonrpc.CodeInvalidParams) } if data.Type != mcperrors.TypeInvalidInput { t.Fatalf("errInvalidInput() type = %q, want %q", data.Type, mcperrors.TypeInvalidInput) } } func requireRPCError(t *testing.T, err error) (*jsonrpc.Error, mcpErrorData) { t.Helper() var rpcErr *jsonrpc.Error if !errors.As(err, &rpcErr) { t.Fatalf("error type = %T, want *jsonrpc.Error", err) } var data mcpErrorData if len(rpcErr.Data) > 0 { if unmarshalErr := json.Unmarshal(rpcErr.Data, &data); unmarshalErr != nil { t.Fatalf("unmarshal error data: %v", unmarshalErr) } } return rpcErr, data }