Files

126 lines
4.1 KiB
Go

package merrors
import (
"errors"
"strings"
"testing"
)
type testReasonedError struct {
error
reason string
}
func (e testReasonedError) Reason() string {
return e.reason
}
func TestReasonUsesReasonedError(t *testing.T) {
err := testReasonedError{
error: InvalidArgument("value is invalid"),
reason: "amount_below_minimum",
}
reason, ok := Reason(err)
if !ok {
t.Fatalf("expected reason")
}
if reason != "amount_below_minimum" {
t.Fatalf("reason mismatch: got=%q", reason)
}
}
func TestInvalidArgumentSupportsBrokenArgumentName(t *testing.T) {
t.Run("without argument name keeps old behavior", func(t *testing.T) {
err := InvalidArgument("value is missing")
expected := "invalidArgError: value is missing"
if err.Error() != expected {
t.Fatalf("unexpected error message: %s", err)
}
if !errors.Is(err, ErrInvalidArg) {
t.Fatalf("error should wrap ErrInvalidArg")
}
})
t.Run("single argument name", func(t *testing.T) {
err := InvalidArgument("value is missing", "bot_token_env")
expected := `invalidArgError: broken argument "bot_token_env": value is missing`
if err.Error() != expected {
t.Fatalf("unexpected error message: %s", err)
}
})
t.Run("multiple argument names", func(t *testing.T) {
err := InvalidArgument("value mismatch", "bot_token_env", "chat_id_env", " ")
expected := `invalidArgError: broken arguments "bot_token_env", "chat_id_env": value mismatch`
if err.Error() != expected {
t.Fatalf("unexpected error message: %s", err)
}
})
}
func TestInvalidArgumentWithNamesfSupportsBrokenArgumentName(t *testing.T) {
err := InvalidArgumentWithNamesf([]string{"gateway.supported_assets.currency"}, "asset[%d] %s", 2, "is invalid")
expected := `invalidArgError: broken argument "gateway.supported_assets.currency": asset[2] is invalid`
if err.Error() != expected {
t.Fatalf("unexpected error message: %s", err)
}
if !errors.Is(err, ErrInvalidArg) {
t.Fatalf("error should wrap ErrInvalidArg")
}
}
func TestInvalidArgumentWrapSupportsBrokenArgumentName(t *testing.T) {
base := Define("root cause")
err := InvalidArgumentWrap(base, "value is missing", "bot_token_env")
if !strings.Contains(err.Error(), `invalidArgError: broken argument "bot_token_env": value is missing`) {
t.Fatalf("wrapped error should include broken argument name: %s", err)
}
if !errors.Is(err, ErrInvalidArg) || !errors.Is(err, base) {
t.Fatalf("wrapped error should preserve all error layers")
}
}
func TestInternalWrapAllPreservesAllCauses(t *testing.T) {
first := Define("first cause")
second := Define("second cause")
err := InternalWrapAll("combined failure", first, nil, second)
if !strings.Contains(err.Error(), "internal: combined failure") {
t.Fatalf("wrapped error should include context: %s", err)
}
if !errors.Is(err, ErrInternal) || !errors.Is(err, first) || !errors.Is(err, second) {
t.Fatalf("wrapped error should preserve all error layers")
}
}
func TestOpaqueWrapPreservesCauseWithoutExposingItsText(t *testing.T) {
cause := DataConflict("restricted storage key")
err := OpaqueWrap(ErrInternal, cause, "safe persistence failure")
if got, want := err.Error(), "internal: safe persistence failure"; got != want {
t.Fatalf("opaque error mismatch: got=%q want=%q", got, want)
}
if !errors.Is(err, ErrInternal) || !errors.Is(err, ErrDataConflict) {
t.Fatalf("opaque error did not preserve classifications: %v", err)
}
}
func TestOperationalWrapsPreserveClassificationAndCause(t *testing.T) {
cause := Define("dependency failure")
tests := []struct {
name string
err error
kind error
}{
{name: "failed precondition", err: FailedPreconditionWrap(cause, "AA capability unavailable"), kind: ErrFailedPrecondition},
{name: "service unavailable", err: ServiceUnavailableWrap(cause, "Arbitrum RPC unavailable"), kind: ErrServiceUnavailable},
{name: "data conflict", err: DataConflictWrap(cause, "managed wallet replay differs"), kind: ErrDataConflict},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if !errors.Is(tt.err, tt.kind) || !errors.Is(tt.err, cause) {
t.Fatalf("wrapped error should preserve classification and cause: %s", tt.err)
}
})
}
}