Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete interface definitions for errors #18

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,28 @@ type errAlreadyExists struct{}

func (errAlreadyExists) Error() string { return "already exists" }

func (errAlreadyExists) AlreadyExists() {}

func (e errAlreadyExists) WithMessage(msg string) error {
return customMessage{e, msg}
}

type alreadyExists interface {
AlreadyExists()
}

// IsAlreadyExists returns true if the error is due to an already existing
// metadata item
func IsAlreadyExists(err error) bool {
return errors.Is(err, ErrAlreadyExists)
return errors.Is(err, ErrAlreadyExists) || isInterface[alreadyExists](err)
}

type errPermissionDenied struct{}

func (errPermissionDenied) Error() string { return "permission denied" }

func (errPermissionDenied) Forbidden() {}

func (e errPermissionDenied) WithMessage(msg string) error {
return customMessage{e, msg}
}
Expand All @@ -172,28 +180,40 @@ type errResourceExhausted struct{}

func (errResourceExhausted) Error() string { return "resource exhausted" }

func (errResourceExhausted) ResourceExhausted() {}

func (e errResourceExhausted) WithMessage(msg string) error {
return customMessage{e, msg}
}

type resourceExhausted interface {
ResourceExhausted()
}

// IsResourceExhausted returns true if the error is due to
// a lack of resources or too many attempts.
func IsResourceExhausted(err error) bool {
return errors.Is(err, errResourceExhausted{})
return errors.Is(err, errResourceExhausted{}) || isInterface[resourceExhausted](err)
}

type errFailedPrecondition struct{}

func (e errFailedPrecondition) Error() string { return "failed precondition" }

func (errFailedPrecondition) FailedPrecondition() {}

func (e errFailedPrecondition) WithMessage(msg string) error {
return customMessage{e, msg}
}

type failedPrecondition interface {
FailedPrecondition()
}

// IsFailedPrecondition returns true if an operation could not proceed due to
// the lack of a particular condition
func IsFailedPrecondition(err error) bool {
return errors.Is(err, errFailedPrecondition{})
return errors.Is(err, errFailedPrecondition{}) || isInterface[failedPrecondition](err)
}

type errConflict struct{}
Expand Down Expand Up @@ -242,27 +262,39 @@ type errAborted struct{}

func (errAborted) Error() string { return "aborted" }

func (errAborted) Aborted() {}

func (e errAborted) WithMessage(msg string) error {
return customMessage{e, msg}
}

type aborted interface {
Aborted()
}

// IsAborted returns true if an operation was aborted.
func IsAborted(err error) bool {
return errors.Is(err, errAborted{})
return errors.Is(err, errAborted{}) || isInterface[aborted](err)
}

type errOutOfRange struct{}

func (errOutOfRange) Error() string { return "out of range" }

func (errOutOfRange) OutOfRange() {}

func (e errOutOfRange) WithMessage(msg string) error {
return customMessage{e, msg}
}

type outOfRange interface {
OutOfRange()
}

// IsOutOfRange returns true if an operation could not proceed due
// to data being out of the expected range.
func IsOutOfRange(err error) bool {
return errors.Is(err, errOutOfRange{})
return errors.Is(err, errOutOfRange{}) || isInterface[outOfRange](err)
}

type errNotImplemented struct{}
Expand Down
34 changes: 34 additions & 0 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package errdefs
import (
"context"
"errors"
"fmt"
"reflect"
"testing"
)
Expand Down Expand Up @@ -158,6 +159,39 @@ func TestWithMessage(t *testing.T) {
}
}

func TestInterfaceMatch(t *testing.T) {
testCases := []struct {
err error
check func(error) bool
}{
{ErrUnknown, isInterface[unknown]},
{ErrInvalidArgument, isInterface[invalidParameter]},
{ErrNotFound, isInterface[notFound]},
{ErrAlreadyExists, isInterface[alreadyExists]},
{ErrPermissionDenied, isInterface[forbidden]},
{ErrResourceExhausted, isInterface[resourceExhausted]},
{ErrFailedPrecondition, isInterface[failedPrecondition]},
{ErrConflict, isInterface[conflict]},
{ErrNotModified, isInterface[notModified]},
{ErrAborted, isInterface[aborted]},
{ErrOutOfRange, isInterface[outOfRange]},
{ErrNotImplemented, isInterface[notImplemented]},
{ErrInternal, isInterface[system]},
{ErrUnavailable, isInterface[unavailable]},
{ErrDataLoss, isInterface[dataLoss]},
{ErrUnauthenticated, isInterface[unauthorized]},
}

for _, tc := range testCases {
tc := tc
t.Run(fmt.Sprintf("%T", tc.err), func(t *testing.T) {
if !tc.check(tc.err) {
t.Fatal("Error does not match interface")
}
})
}
}

type customInvalidArgument struct{}

func (*customInvalidArgument) Error() string {
Expand Down
15 changes: 10 additions & 5 deletions resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,22 @@ func firstError(err error) error {
return ErrInvalidArgument
case notFound:
return ErrNotFound
// Skip ErrAlreadyExists, no interface defined
case alreadyExists:
return ErrAlreadyExists
case forbidden:
return ErrPermissionDenied
// Skip ErrResourceExhasuted, no interface defined
// Skip ErrFailedPrecondition, no interface defined
case resourceExhausted:
return ErrResourceExhausted
case failedPrecondition:
return ErrFailedPrecondition
case conflict:
return ErrConflict
case notModified:
return ErrNotModified
// Skip ErrAborted, no interface defined
// Skip ErrOutOfRange, no interface defined
case aborted:
return ErrAborted
case errOutOfRange:
return ErrOutOfRange
case notImplemented:
return ErrNotImplemented
case system:
Expand Down
Loading