MapForgejoError previously classified HTTP results by substring
matching. Two failure modes: URIs/error bodies legitimately
containing "404"/"Forbidden" mis-classified, and parser errors of
shape "invalid URI: expected forgejo://..." fell through to -32603
because the existing "kind must be"/"index must be numeric"
substrings did not cover them.
Introduce resource.ErrInvalidParams sentinel; wrap every parser
return path with it (Parse{Owner,Repo,Commit,Issue,PR,Comment,Status},
parseForgejoURI, validateSHA). MapForgejoError now classifies via
errors.Is(err, ErrInvalidParams) before falling back to HTTP
substring matching for 403/404. Substring matching for 403/404
stays as a transition fallback because the SDK still surfaces
HTTP status only via formatted error strings.
Update handler tests that asserted Code == -32603 on parse errors
(set by forgejo-mcp-vzz) to assert -32602.
Closes forgejo-mcp-wgs.
Ref PR #172 review https://codeberg.org/goern/forgejo-mcp/pulls/172#issuecomment-16022165
71 lines
2.4 KiB
Go
71 lines
2.4 KiB
Go
package resource
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestMapForgejoError_403(t *testing.T) {
|
|
err := MapForgejoError("forgejo://repo/a/b", errors.New("403 Forbidden"))
|
|
if err == nil {
|
|
t.Fatal("expected non-nil ResourceError")
|
|
}
|
|
if err.Code != -32002 {
|
|
t.Errorf("expected code -32002 for 403, got %d", err.Code)
|
|
}
|
|
}
|
|
|
|
func TestMapForgejoError_404(t *testing.T) {
|
|
err := MapForgejoError("forgejo://repo/a/b", errors.New("404 Not Found"))
|
|
if err == nil {
|
|
t.Fatal("expected non-nil ResourceError")
|
|
}
|
|
if err.Code != -32003 {
|
|
t.Errorf("expected code -32003 for 404, got %d", err.Code)
|
|
}
|
|
}
|
|
|
|
func TestMapForgejoError_Nil(t *testing.T) {
|
|
err := MapForgejoError("forgejo://repo/a/b", nil)
|
|
if err != nil {
|
|
t.Errorf("expected nil for nil input, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMapForgejoError_InvalidKind(t *testing.T) {
|
|
// The real parser now wraps with ErrInvalidParams; simulate that here.
|
|
wrapped := fmt.Errorf("%w: invalid URI \"forgejo://repo/a/b/wiki/1/comment/5\": kind must be 'issue' or 'pr', got \"wiki\"", ErrInvalidParams)
|
|
err := MapForgejoError("forgejo://repo/a/b/wiki/1/comment/5", wrapped)
|
|
if err == nil {
|
|
t.Fatal("expected non-nil ResourceError")
|
|
}
|
|
if err.Code != -32602 {
|
|
t.Errorf("expected code -32602 for invalid kind, got %d", err.Code)
|
|
}
|
|
}
|
|
|
|
func TestMapForgejoError_ErrInvalidParams_Sentinel(t *testing.T) {
|
|
// Errors wrapping ErrInvalidParams must map to -32602 regardless of message content.
|
|
wrapped := fmt.Errorf("%w: invalid URI \"forgejo://repo/x/y/commit/short\": sha must be exactly 40 hex characters, got 5", ErrInvalidParams)
|
|
err := MapForgejoError("forgejo://repo/x/y/commit/short", wrapped)
|
|
if err == nil {
|
|
t.Fatal("expected non-nil ResourceError")
|
|
}
|
|
if err.Code != -32602 {
|
|
t.Errorf("expected code -32602 for ErrInvalidParams sentinel, got %d", err.Code)
|
|
}
|
|
}
|
|
|
|
func TestMapForgejoError_ErrInvalidParams_404InMessage(t *testing.T) {
|
|
// A URI containing "404" in its body must still map to -32602 when wrapped with ErrInvalidParams,
|
|
// not to -32003 (the substring-match path must not fire before the sentinel check).
|
|
wrapped := fmt.Errorf("%w: invalid URI containing 404 in path", ErrInvalidParams)
|
|
err := MapForgejoError("forgejo://repo/a/b/issue/404abc", wrapped)
|
|
if err == nil {
|
|
t.Fatal("expected non-nil ResourceError")
|
|
}
|
|
if err.Code != -32602 {
|
|
t.Errorf("expected code -32602 (sentinel beats 404 substring), got %d", err.Code)
|
|
}
|
|
}
|