Created
November 22, 2024 15:38
-
-
Save IlyasYOY/8c3334f760b42eda393ffc81504f586c to your computer and use it in GitHub Desktop.
make your errors detailed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package detailederror | |
import "errors" | |
type detailedError struct { | |
err error | |
key string | |
val string | |
} | |
func (d *detailedError) Error() string { | |
return d.err.Error() | |
} | |
func WithDetails(err error, key, value string) error { | |
return &detailedError{ | |
err: err, | |
key: key, | |
val: value, | |
} | |
} | |
func GetDetail(err error, key string) (string, bool) { | |
nextErr := err | |
var derr *detailedError | |
for errors.As(nextErr, &derr) { | |
if derr.key == key { | |
return derr.val, true | |
} | |
nextErr = derr.err | |
} | |
return "", false | |
} | |
func GetDetails(err error) map[string]string { | |
nextErr := err | |
var derr *detailedError | |
details := make(map[string]string, 0) | |
for errors.As(nextErr, &derr) { | |
details[derr.key] = derr.val | |
nextErr = derr.err | |
} | |
return details | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package detailederror_test | |
import ( | |
"errors" | |
"testing" | |
"github.com/IlyasYOY/detailederror" | |
"github.com/google/go-cmp/cmp" | |
) | |
func TestWithDetails(t *testing.T) { | |
err := errors.New("test") | |
gotErr := detailederror.WithDetails(err, "user", "ilya") | |
if gotErr == nil { | |
t.Errorf("error must not be nil: %v", gotErr) | |
} | |
} | |
func TestGetDetail_Nested(t *testing.T) { | |
err := errors.New("test") | |
key1 := "user1" | |
want1 := "ilya1" | |
detailedErr1 := detailederror.WithDetails(err, key1, want1) | |
key2 := "user2" | |
want2 := "ilya2" | |
detailedErr2 := detailederror.WithDetails(detailedErr1, key2, want2) | |
got2, ok2 := detailederror.GetDetail(detailedErr2, key2) | |
got1, ok1 := detailederror.GetDetail(detailedErr2, key1) | |
if !ok1 { | |
t.Fatalf("value not found by key: %q", key1) | |
} | |
if !ok2 { | |
t.Fatalf("value not found by key: %q", key2) | |
} | |
if got2 != want2 { | |
t.Errorf("value must be equal to %q", want2) | |
} | |
if got1 != want1 { | |
t.Errorf("value must be equal to %q", want1) | |
} | |
} | |
func TestGetDetails_Nested(t *testing.T) { | |
err := errors.New("test") | |
detailedErr1 := detailederror.WithDetails(err, "user1", "ilya1") | |
detailedErr2 := detailederror.WithDetails(detailedErr1, "user2", "ilya2") | |
got := detailederror.GetDetails(detailedErr2) | |
if diff := cmp.Diff(map[string]string{ | |
"user1": "ilya1", | |
"user2": "ilya2", | |
}, got); diff != "" { | |
t.Errorf("(-want +got):\\n%s", diff) | |
} | |
} | |
func TestGetDetail(t *testing.T) { | |
err := errors.New("test") | |
key := "user" | |
want := "ilya" | |
detailedErr := detailederror.WithDetails(err, key, want) | |
got, ok := detailederror.GetDetail(detailedErr, key) | |
if !ok { | |
t.Fatalf("value not found by key: %q", key) | |
} | |
if got != want { | |
t.Errorf("value must be equal to %q", want) | |
} | |
} | |
func TestGetDetail_Absent(t *testing.T) { | |
err := errors.New("test") | |
want := "ilya" | |
detailedErr := detailederror.WithDetails(err, "name", want) | |
_, ok := detailederror.GetDetail(detailedErr, "user") | |
if ok { | |
t.Fatalf("value was found") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment