From 9245cc75e0253b76b5eaeb3727c2b6e15571753f Mon Sep 17 00:00:00 2001 From: Gogo Date: Wed, 5 Jun 2024 15:14:58 +0800 Subject: [PATCH] feat: support GetProperty --- eris.go | 28 +++++++++++++++++++++++ eris_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/eris.go b/eris.go index d3cf1a8..58d822a 100644 --- a/eris.go +++ b/eris.go @@ -45,6 +45,34 @@ func GetKVs(err error) map[string]any { return kvErr.KVs() } +// GetProperty returns the property. If the property doesn't exist or type doesn't match, returns T{}, false +func GetProperty[T any](err error, key string) (T, bool) { + val, ok := GetKVs(err)[key] + if !ok { + var empty T + return empty, false + } + typed, ok := val.(T) + if !ok { + var empty T + return empty, false + } + return typed, true +} + +// GetPropertyP returns the property pointer. If the property doesn't exist or type doesn't match, returns nil +func GetPropertyP[T any](err error, key string) *T { + val, ok := GetKVs(err)[key] + if !ok { + return nil + } + typed, ok := val.(T) + if !ok { + return nil + } + return &typed +} + // New creates a new root error with a static message and an error code 'unknown'. func New(msg string) statusError { stack := callers(3) // callers(3) skips this method, stack.callers, and runtime.Callers diff --git a/eris_test.go b/eris_test.go index a92e160..6e7e254 100644 --- a/eris_test.go +++ b/eris_test.go @@ -145,6 +145,70 @@ func TestExternalKVs(t *testing.T) { } } +func TestProperty(t *testing.T) { + tests := map[string]struct { + cause error + key string + exist bool + property string // expected output + }{ + "no property": { + cause: eris.New("error message"), + key: "key1", + exist: false, + }, + "property not found": { + cause: eris.New("error message").WithProperty("key2", "val2"), + key: "key1", + exist: false, + }, + "property type mismatch": { + cause: eris.New("error message").WithProperty("key1", 1234).WithProperty("key2", "val2"), + key: "key1", + exist: false, + }, + "error new property found": { + cause: eris.New("error message").WithProperty("key1", "val1").WithProperty("key2", 2), + key: "key1", + exist: true, + property: "val1", + }, + "error wrap property found": { + cause: eris.WithProperty(eris.WithProperty( + eris.Wrap(fmt.Errorf("external error"), "wrap"), + "key1", "val1", + ), "key2", 2), + key: "key1", + exist: true, + property: "val1", + }, + } + for desc, tc := range tests { + t.Run(desc, func(t *testing.T) { + v1, ok := eris.GetProperty[string](tc.cause, tc.key) + v2 := eris.GetPropertyP[string](tc.cause, tc.key) + if tc.exist { + if !ok { + t.Errorf("%v: expected ok { %v } got { %v }", desc, true, ok) + } + if v1 != tc.property { + t.Errorf("%v: expected { %v } got { %v }", desc, tc.property, v1) + } + if *v2 != tc.property { + t.Errorf("%v: expected { %v } got { %v }", desc, tc.property, v2) + } + } else { + if ok { + t.Errorf("%v: expected ok { %v } got { %v }", desc, false, ok) + } + if v2 != nil { + t.Errorf("%v: expected { %v } got { %v }", desc, nil, v2) + } + } + }) + } +} + func TestErrorWrapping(t *testing.T) { tests := map[string]struct { cause error // root error