Browse Source

<feature>(IS): Use original errors.Is as final test for Is function

issue: Current is does not support custom Is definition on underlying errors
fix proposition: delegate the error check to standard errors.Is checker
so it does have expected behaviour on wrapped errors as well as custom
Is implementation
tfreville 5 years ago
parent
commit
4ac07ff6b5
3 changed files with 65 additions and 4 deletions
  1. 3 0
      README.md
  2. 4 4
      error.go
  3. 58 0
      error_test.go

+ 3 - 0
README.md

@@ -64,3 +64,6 @@ packages by Facebook and Dropbox, it was moved to one canonical location so
 everyone can benefit.
 everyone can benefit.
 
 
 This package is licensed under the MIT license, see LICENSE.MIT for details.
 This package is licensed under the MIT license, see LICENSE.MIT for details.
+
+## Changelog
+* v1.1.0 updated to use go1.13's standard-library errors.Is method instead of == in errors.Is

+ 4 - 4
error.go

@@ -47,6 +47,7 @@ package errors
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	baseErrors "errors"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
 	"runtime"
 	"runtime"
@@ -140,11 +141,10 @@ func WrapPrefix(e interface{}, prefix string, skip int) *Error {
 }
 }
 
 
 // Is detects whether the error is equal to a given error. Errors
 // Is detects whether the error is equal to a given error. Errors
-// are considered equal by this function if they are the same object,
-// or if they both contain the same error inside an errors.Error.
+// are considered equal by this function if they are matched by errors.Is
+// or if their contained errors are matched through errors.Is
 func Is(e error, original error) bool {
 func Is(e error, original error) bool {
-
-	if e == original {
+	if baseErrors.Is(e, original) {
 		return true
 		return true
 	}
 	}
 
 

+ 58 - 0
error_test.go

@@ -129,6 +129,50 @@ func TestIs(t *testing.T) {
 		t.Errorf("io.EOF is fmt.Errorf")
 		t.Errorf("io.EOF is fmt.Errorf")
 	}
 	}
 
 
+	custErr := errorWithCustomIs{
+		Key: "TestForFun",
+		Err: io.EOF,
+	}
+
+	shouldMatch := errorWithCustomIs{
+		Key: "TestForFun",
+	}
+
+	shouldNotMatch := errorWithCustomIs{Key: "notOk"}
+
+	if !Is(custErr, shouldMatch) {
+		t.Errorf("custErr is not a TestForFun customError")
+	}
+
+	if Is(custErr, shouldNotMatch) {
+		t.Errorf("custErr is a notOk customError")
+	}
+
+	if !Is(custErr, New(shouldMatch)) {
+		t.Errorf("custErr is not a New(TestForFun customError)")
+	}
+
+	if Is(custErr, New(shouldNotMatch)) {
+		t.Errorf("custErr is a New(notOk customError)")
+	}
+
+	if !Is(New(custErr), shouldMatch) {
+		t.Errorf("New(custErr) is not a TestForFun customError")
+	}
+
+	if Is(New(custErr), shouldNotMatch) {
+		t.Errorf("New(custErr) is a notOk customError")
+	}
+
+	if !Is(New(custErr), New(shouldMatch)) {
+		t.Errorf("New(custErr) is not a New(TestForFun customError)")
+	}
+
+	if Is(New(custErr), New(shouldNotMatch)) {
+		t.Errorf("New(custErr) is a New(notOk customError)")
+	}
+
+
 }
 }
 
 
 func TestWrapError(t *testing.T) {
 func TestWrapError(t *testing.T) {
@@ -317,3 +361,17 @@ func callersToFrames(callers []uintptr) []runtime.Frame {
 		}
 		}
 	}
 	}
 }
 }
+
+type errorWithCustomIs struct {
+	Key string
+	Err error
+}
+
+func (ewci errorWithCustomIs) Error() string {
+	return "["+ewci.Key+"]: " + ewci.Err.Error()
+}
+
+func (ewci errorWithCustomIs) Is(target error) bool {
+	matched, ok := target.(errorWithCustomIs)
+	return ok && matched.Key == ewci.Key
+}