package errors import ( "fmt" "testing" ) // The constructors and the helpers' non-domain paths. The suite above covers // the common errors; these are the builder methods and the plain-error answers // a caller gets when the error in hand is not a DomainError. func TestBaseStringAndWithMessage(t *testing.T) { e := ErrInvalidJSON if e.String() == "" || e.String() != e.Error() { t.Fatal("String must mirror Error") } m := e.WithMessage([]byte("custom")) if string(m.message) != "custom" { t.Fatal("WithMessage") } if string(m.Code()) != "INVALID_JSON" || string(m.Category()) != "validation" { t.Fatal("WithMessage must keep the code and category") } if m.IsRetryable() { t.Fatal("WithMessage must keep the retryable flag") } if string(e.message) != "malformed JSON" { t.Fatal("WithMessage must not mutate the original") } // No cause: the message stands alone. if e.Error() != "malformed JSON" { t.Fatalf("Error without a cause = %s", e.Error()) } } func TestWithFieldAndConstructors(t *testing.T) { v := ErrInvalidEventID.WithField([]byte("other")) if string(v.Field) != "other" || string(v.Code()) != "INVALID_ID" { t.Fatal("WithField") } if string(v.Category()) != "validation" { t.Fatal("WithField must keep the category") } a := NewAccessDenied([]byte("write"), []byte("nope")) if string(a.Code()) != "ACCESS_DENIED" || string(a.AccessLevel) != "write" || a.NeedsAuth() { t.Fatal("NewAccessDenied") } if a.Category()[0] != 'a' { t.Fatal("NewAccessDenied category") } p := NewProcessingError([]byte("X"), []byte("x"), true).WithEventID([]byte("abc")) if string(p.EventID) != "abc" || !p.IsRetryable() { t.Fatal("WithEventID") } p2 := p.WithKind(7) if p2.Kind != 7 || string(p2.EventID) != "abc" { t.Fatal("WithKind") } pb := NewPolicyBlocked([]byte("rule"), []byte("no")) if string(pb.RuleName) != "rule" || string(pb.Action) != "block" { t.Fatal("NewPolicyBlocked") } pr := NewPolicyRejected([]byte("rule"), []byte("no")) if string(pr.Action) != "reject" || string(pr.Code()) != "POLICY_REJECTED" { t.Fatal("NewPolicyRejected") } if !NeedsAuth(NewAuthRequired([]byte("because"))) { t.Fatal("NewAuthRequired") } ap := ErrBanned.WithPubkey([]byte("pk")) if string(ap.Pubkey) != "pk" || string(ap.Code()) != "BANNED" { t.Fatal("WithPubkey") } } func TestCodeCategoryAndIsOnPlainErrors(t *testing.T) { plain := fmt.Errorf("plain") if Code(plain) != nil { t.Fatal("a plain error has no code") } if string(Category(plain)) != "unknown" { t.Fatal("a plain error's category is unknown") } if Is(plain, ErrDuplicate) { t.Fatal("Is on a plain error is false") } if IsRetryable(plain) { t.Fatal("a plain error is not retryable") } if NeedsAuth(plain) { t.Fatal("a plain error does not need auth") } if string(Code(ErrAuthRequired)) != "AUTH_REQUIRED" { t.Fatal("code") } if string(Category(ErrRateLimited)) != "processing" { t.Fatal("rate limit category") } if string(Category(ErrKindBlocked)) != "policy" { t.Fatal("policy category") } if string(Category(ErrServiceUnavailable)) != "service" || !IsRetryable(ErrServiceUnavailable) { t.Fatal("service error") } if string(Category(ErrStorageFull)) != "storage" { t.Fatal("storage category") } if !Is(ErrAuthRequired, ErrAuthRequired) { t.Fatal("Is matches on the code, not the pointer") } }