Repository: looplab/fsm

Issue:
Return errors as wrapped errors instead of a custom struct
This will allow us to use errors.Is to detect sub errors instead of string comparisons.

Discussion:
@maxekman: Definitely something I want too. Thanks for bringing this up.

A PR is welcome if you have the time, not sure when I'll get to it.@harry-stebbins-dailypay: fyi @maxekman https://github.com/looplab/fsm/pull/113@maxekman: Fixed in #113.

Solution patch:
diff --git a/errors.go b/errors.go
index add5dbe..7df308a 100644
--- a/errors.go
+++ b/errors.go
@@ -69,6 +69,10 @@ func (e NoTransitionError) Error() string {
 	return "no transition"
 }
 
+func (e NoTransitionError) Unwrap() error {
+	return e.Err
+}
+
 // CanceledError is returned by FSM.Event() when a callback have canceled a
 // transition.
 type CanceledError struct {
@@ -82,6 +86,10 @@ func (e CanceledError) Error() string {
 	return "transition canceled"
 }
 
+func (e CanceledError) Unwrap() error {
+	return e.Err
+}
+
 // AsyncError is returned by FSM.Event() when a callback have initiated an
 // asynchronous state transition.
 type AsyncError struct {
@@ -98,6 +106,10 @@ func (e AsyncError) Error() string {
 	return "async started"
 }
 
+func (e AsyncError) Unwrap() error {
+	return e.Err
+}
+
 // InternalError is returned by FSM.Event() and should never occur. It is a
 // probably because of a bug.
 type InternalError struct{}



Test patch:
diff --git a/errors_test.go b/errors_test.go
index ba384ee..31637d0 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -60,6 +60,12 @@ func TestNoTransitionError(t *testing.T) {
 	if e.Error() != "no transition with error: "+e.Err.Error() {
 		t.Error("NoTransitionError string mismatch")
 	}
+	if e.Unwrap() == nil {
+		t.Error("CanceledError Unwrap() should not be nil")
+	}
+	if !errors.Is(e, e.Err) {
+		t.Error("CanceledError should be equal to its error")
+	}
 }
 
 func TestCanceledError(t *testing.T) {
@@ -71,6 +77,12 @@ func TestCanceledError(t *testing.T) {
 	if e.Error() != "transition canceled with error: "+e.Err.Error() {
 		t.Error("CanceledError string mismatch")
 	}
+	if e.Unwrap() == nil {
+		t.Error("CanceledError Unwrap() should not be nil")
+	}
+	if !errors.Is(e, e.Err) {
+		t.Error("CanceledError should be equal to its error")
+	}
 }
 
 func TestAsyncError(t *testing.T) {
@@ -82,6 +94,12 @@ func TestAsyncError(t *testing.T) {
 	if e.Error() != "async started with error: "+e.Err.Error() {
 		t.Error("AsyncError string mismatch")
 	}
+	if e.Unwrap() == nil {
+		t.Error("AsyncError Unwrap() should not be nil")
+	}
+	if !errors.Is(e, e.Err) {
+		t.Error("AsyncError should be equal to its error")
+	}
 }
 
 func TestInternalError(t *testing.T) {