From 8d929d2983dacb2a1e7892242cf90c8795bf2bff Mon Sep 17 00:00:00 2001 From: Jose Sitanggang Date: Sat, 20 May 2023 16:19:51 +0700 Subject: [PATCH] feat: add internal error wrapper (#48) --- errors.go | 15 +++++++++++++++ goval.go | 7 ++++++- goval_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/errors.go b/errors.go index 5cfddc8..ceb5930 100644 --- a/errors.go +++ b/errors.go @@ -134,3 +134,18 @@ func stringifyJSON(m json.Marshaler) string { } return string(b) } + +// InternalError is an error wrapper to indicate an internal error. +// If goval got this type of error, it will not include in Errors and KeyError. +type InternalError struct { + Err error +} + +// NewInternalError creates a new InternalError. +func NewInternalError(err error) *InternalError { + return &InternalError{Err: err} +} + +func (e *InternalError) Error() string { return e.String() } +func (e *InternalError) Unwrap() error { return e.Err } +func (e *InternalError) String() string { return "goval.InternalError: " + e.Err.Error() } diff --git a/goval.go b/goval.go index 2f4cdba..8e6d3d7 100644 --- a/goval.go +++ b/goval.go @@ -2,6 +2,7 @@ package goval import ( "context" + "errors" "github.com/pkg-id/goval/funcs" "regexp" ) @@ -107,6 +108,10 @@ func execChain[T any, Func FunctionValidatorConstraint[T]](ctx context.Context, func Named[T any, F RuleValidator[T]](name string, value T, validator F) Validator { return ValidatorFunc(func(ctx context.Context) error { if err := validator.Validate(ctx, value); err != nil { + var ie *InternalError + if errors.As(err, &ie) { + return ie + } return NewKeyError(name, err) } return nil @@ -160,7 +165,7 @@ func validatorReducer(ctx context.Context, internalError chan error) func(errs E err := validator.Validate(ctx) if err != nil { switch err.(type) { - default: + default: // *InternalError or something else. internalError <- err case *RuleError, *KeyError, Errors: errs = append(errs, err) diff --git a/goval_test.go b/goval_test.go index 26d4fd7..c97c6cc 100644 --- a/goval_test.go +++ b/goval_test.go @@ -34,6 +34,39 @@ func TestNamed(t *testing.T) { t.Fatalf("expect not error") } }) + + t.Run("internal error", func(t *testing.T) { + ctx := context.Background() + + retErr := errors.New("internal error") + custom := func(ctx context.Context, value string) error { + return goval.NewInternalError(retErr) + } + + err := goval.Named("field-name", "a", goval.String().With(custom)).Validate(ctx) + if !errors.Is(err, retErr) { + t.Fatalf("expect error is internal error") + } + }) + + t.Run("without internal error", func(t *testing.T) { + ctx := context.Background() + + retErr := errors.New("internal error") + custom := func(ctx context.Context, value string) error { + return retErr + } + + err := goval.Named("field-name", "a", goval.String().With(custom)).Validate(ctx) + var kErr *goval.KeyError + if !errors.As(err, &kErr) { + t.Fatalf("expect error type: %T; got error type: %T", kErr, err) + } + + if !errors.Is(kErr.Err, retErr) { + t.Fatalf("expect error is internal error") + } + }) } func TestEach(t *testing.T) {