From 4cc5e15c33e28c99d075c49a70fe7c326ba5ba2a Mon Sep 17 00:00:00 2001 From: Jordan Barrett Date: Fri, 29 Sep 2023 12:50:50 +0700 Subject: [PATCH 1/2] Satisfy errors.Is even if formatting is incorrect --- errortypes.go | 47 ++++++++++++++++++++++++---------------------- errortypes_test.go | 26 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/errortypes.go b/errortypes.go index 0029f91d..0f176879 100644 --- a/errortypes.go +++ b/errortypes.go @@ -4,10 +4,8 @@ package errors import ( - "errors" stderror "errors" "fmt" - "strings" ) // a ConstError is a prototype for a certain type of error @@ -86,12 +84,17 @@ func wrapErrorWithMsg(err error, msg string) error { return fmt.Errorf("%s: %w", msg, err) } -func makeWrappedConstError(err error, format string, args ...interface{}) error { - separator := " " - if err.Error() == "" || errors.Is(err, &fmtNoop{}) { - separator = "" +// fmtErrWithType returns an error with the provided error type and format. +func fmtErrWithType(errType ConstError, hideSuffix bool, format string, args ...interface{}) error { + msg := fmt.Sprintf(format, args...) + if !hideSuffix { + msg += " " + errType.Error() + } + + return &errWithType{ + error: New(msg), + errType: errType, } - return fmt.Errorf(strings.Join([]string{format, "%w"}, separator), append(args, err)...) } // WithType is responsible for annotating an already existing error so that it @@ -116,7 +119,7 @@ func WithType(err error, errType ConstError) error { // interface. func Timeoutf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Timeout, format, args...), + fmtErrWithType(Timeout, false, format, args...), 1, ) } @@ -140,7 +143,7 @@ func IsTimeout(err error) bool { // Locationer interface. func NotFoundf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotFound, format, args...), + fmtErrWithType(NotFound, false, format, args...), 1, ) } @@ -164,7 +167,7 @@ func IsNotFound(err error) bool { // Locationer interface. func UserNotFoundf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(UserNotFound, format, args...), + fmtErrWithType(UserNotFound, false, format, args...), 1, ) } @@ -188,7 +191,7 @@ func IsUserNotFound(err error) bool { // the Locationer interface. func Unauthorizedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(Unauthorized), format, args...), + fmtErrWithType(Unauthorized, true, format, args...), 1, ) } @@ -212,7 +215,7 @@ func IsUnauthorized(err error) bool { // the Locationer interface. func NotImplementedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotImplemented, format, args...), + fmtErrWithType(NotImplemented, false, format, args...), 1, ) } @@ -236,7 +239,7 @@ func IsNotImplemented(err error) bool { // the Locationer interface. func AlreadyExistsf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(AlreadyExists, format, args...), + fmtErrWithType(AlreadyExists, false, format, args...), 1, ) } @@ -260,7 +263,7 @@ func IsAlreadyExists(err error) bool { // Locationer interface. func NotSupportedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotSupported, format, args...), + fmtErrWithType(NotSupported, false, format, args...), 1, ) } @@ -284,7 +287,7 @@ func IsNotSupported(err error) bool { // Locationer interface. func NotValidf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotValid, format, args...), + fmtErrWithType(NotValid, false, format, args...), 1, ) } @@ -308,7 +311,7 @@ func IsNotValid(err error) bool { // the Locationer interface. func NotProvisionedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotProvisioned, format, args...), + fmtErrWithType(NotProvisioned, false, format, args...), 1, ) } @@ -332,7 +335,7 @@ func IsNotProvisioned(err error) bool { // Locationer interface. func NotAssignedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(NotAssigned, format, args...), + fmtErrWithType(NotAssigned, false, format, args...), 1, ) } @@ -356,7 +359,7 @@ func IsNotAssigned(err error) bool { // Locationer interface. func BadRequestf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(BadRequest), format, args...), + fmtErrWithType(BadRequest, true, format, args...), 1, ) } @@ -380,7 +383,7 @@ func IsBadRequest(err error) bool { // and the Locationer interface. func MethodNotAllowedf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(MethodNotAllowed), format, args...), + fmtErrWithType(MethodNotAllowed, true, format, args...), 1, ) } @@ -404,7 +407,7 @@ func IsMethodNotAllowed(err error) bool { // Locationer interface. func Forbiddenf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(Forbidden), format, args...), + fmtErrWithType(Forbidden, true, format, args...), 1, ) } @@ -428,7 +431,7 @@ func IsForbidden(err error) bool { // Is(err, QuotaLimitExceeded) and the Locationer interface. func QuotaLimitExceededf(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(QuotaLimitExceeded), format, args...), + fmtErrWithType(QuotaLimitExceeded, true, format, args...), 1, ) } @@ -452,7 +455,7 @@ func IsQuotaLimitExceeded(err error) bool { // and the Locationer interface. func NotYetAvailablef(format string, args ...interface{}) error { return newLocationError( - makeWrappedConstError(Hide(NotYetAvailable), format, args...), + fmtErrWithType(NotYetAvailable, true, format, args...), 1, ) } diff --git a/errortypes_test.go b/errortypes_test.go index edd20159..4700fae0 100644 --- a/errortypes_test.go +++ b/errortypes_test.go @@ -193,3 +193,29 @@ func (*errorTypeSuite) TestWithType(c *gc.C) { c.Assert(err.Error(), gc.Equals, "yes") c.Assert(errors.Is(err, myErr2), gc.Equals, false) } + +func (*errorTypeSuite) TestBadFormatNotEnoughArgs(c *gc.C) { + errorTests := make([]errorTest, 0, len(allErrors)) + for _, errInfo := range allErrors { + errorTests = append(errorTests, errorTest{ + errInfo.argsConstructor("missing arg %v"), + ".*", + errInfo, + }) + } + + runErrorTests(c, errorTests, true) +} + +func (*errorTypeSuite) TestBadFormatTooManyArgs(c *gc.C) { + errorTests := make([]errorTest, 0, len(allErrors)) + for _, errInfo := range allErrors { + errorTests = append(errorTests, errorTest{ + errInfo.argsConstructor("extra arg %v", "foo", "bar"), + ".*", + errInfo, + }) + } + + runErrorTests(c, errorTests, true) +} From 059352046e8e8ff627ab4251679ed4faf8d4a2ca Mon Sep 17 00:00:00 2001 From: Jordan Barrett Date: Fri, 29 Sep 2023 13:46:21 +0700 Subject: [PATCH 2/2] Test suffix still present w/ incorrect fmt string --- errortypes_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/errortypes_test.go b/errortypes_test.go index 4700fae0..fdffef5a 100644 --- a/errortypes_test.go +++ b/errortypes_test.go @@ -199,7 +199,7 @@ func (*errorTypeSuite) TestBadFormatNotEnoughArgs(c *gc.C) { for _, errInfo := range allErrors { errorTests = append(errorTests, errorTest{ errInfo.argsConstructor("missing arg %v"), - ".*", + ".*" + errInfo.suffix, errInfo, }) } @@ -212,7 +212,7 @@ func (*errorTypeSuite) TestBadFormatTooManyArgs(c *gc.C) { for _, errInfo := range allErrors { errorTests = append(errorTests, errorTest{ errInfo.argsConstructor("extra arg %v", "foo", "bar"), - ".*", + ".*" + errInfo.suffix, errInfo, }) }