Skip to content

Commit 880ab3b

Browse files
committed
breaking change: updates New to take in a string instead of an error and creates Wrap which will now take in an error.
1 parent 3376a6c commit 880ab3b

2 files changed

Lines changed: 128 additions & 8 deletions

File tree

errors.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package errutil
22

33
import (
4+
"errors"
45
"fmt"
56
"strings"
67
)
78

8-
// New creates a new error with the ability to add multiple behavior to that error
9+
// Wrap wraps an error with the ability to add multiple behavior to that error
910
// e.g.
1011
//
11-
// New(errors.New("my error"), WithAccessDenied(true), WithRateLimit(true))
12-
func New(err error, opts ...OptsFunc) error {
12+
// Wrap(errors.New("my error"), WithAccessDenied(true), WithRateLimit(true))
13+
func Wrap(err error, opts ...OptsFunc) error {
1314
e := multiKindErr{
1415
opts: ToOpts(opts...),
1516
error: err,
@@ -19,12 +20,27 @@ func New(err error, opts ...OptsFunc) error {
1920
e.error = NewTagged(err, e.opts.Tags...)
2021
}
2122
if e.opts.StackTrace != nil {
22-
e.error = NewStacked(err, *e.opts.StackTrace+1)
23+
e.error = NewStacked(e.error, *e.opts.StackTrace+1)
2324
}
2425

2526
return e
2627
}
2728

29+
// New creates a new error with the ability to add multiple behavior to that error
30+
// e.g.
31+
//
32+
// New("my error", WithAccessDenied(true), WithRateLimit(true))
33+
func New(message string, opts ...OptsFunc) error {
34+
info := ToOpts(opts...)
35+
if info.StackTrace != nil {
36+
opts = append(opts, WithStackTrace(*info.StackTrace+1))
37+
} else {
38+
opts = append(opts, WithStackTrace(1))
39+
}
40+
41+
return Wrap(errors.New(message), opts...)
42+
}
43+
2844
var (
2945
_ AccessDenier = (*multiKindErr)(nil)
3046
_ Conflicter = (*multiKindErr)(nil)

errors_test.go

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"testing"
1010
)
1111

12-
func TestNewError(t *testing.T) {
12+
func TestWrapError(t *testing.T) {
1313
t.Run("happy path", func(t *testing.T) {
1414
err := errors.New("yo son")
1515
tests := []struct {
@@ -65,6 +65,110 @@ func TestNewError(t *testing.T) {
6565
},
6666
}
6767

68+
for idx, tt := range tests {
69+
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
70+
e := Wrap(err, tt.opts...)
71+
if len(tt.fns) != len(tt.expectations) {
72+
t.Fatal("fns and expectations should be the same length")
73+
}
74+
75+
for idx, fn := range tt.fns {
76+
if tt.expectations[idx] != fn(e) {
77+
t.Fatalf("expected %s to return %v", getFunctionName(fn), tt.expectations[idx])
78+
}
79+
}
80+
})
81+
}
82+
})
83+
84+
t.Run("should handle tagged errors as expected", func(t *testing.T) {
85+
e := Wrap(errors.New("hi"), WithTags(NewTag("what", "is"), NewTag("hello", "world")))
86+
if !IsTaggable(e) {
87+
t.Fatal("expected IsTaggable to return true")
88+
}
89+
90+
if tags := GetTags(e); len(tags) != 2 {
91+
t.Fatalf("expected 2 tags back but got %d", len(tags))
92+
} else {
93+
t.Log(tags)
94+
}
95+
96+
t.Run("should handle nested tags as well", func(t *testing.T) {
97+
nested := Wrap(e, WithEasyTags("yes", "sir", "will", "be"))
98+
if !IsTaggable(nested) {
99+
t.Fatal("expected IsTaggable to return true")
100+
}
101+
102+
if tags := GetTags(nested); len(tags) != 4 {
103+
t.Fatalf("expected 4 tags back but got %d", len(tags))
104+
} else {
105+
t.Log(tags)
106+
}
107+
})
108+
109+
})
110+
111+
t.Run("should generate stack trace when option provided", func(t *testing.T) {
112+
err := Wrap(errors.New("hey there"), WithStackTrace(0))
113+
fmt.Printf("%+v\n", err)
114+
})
115+
}
116+
func TestNewError(t *testing.T) {
117+
t.Run("happy path", func(t *testing.T) {
118+
err := "yo son"
119+
tests := []struct {
120+
opts []OptsFunc
121+
fns []CheckerFn
122+
expectations []bool
123+
}{
124+
{
125+
opts: []OptsFunc{WithAccessDenied(true)},
126+
fns: append([]CheckerFn{IsAccessDenied}, allFuncsExcept(IsAccessDenied)...),
127+
expectations: []bool{true, false, false, false, false, false},
128+
},
129+
{
130+
opts: []OptsFunc{WithConflict(true)},
131+
fns: append([]CheckerFn{IsConflict}, allFuncsExcept(IsConflict)...),
132+
expectations: []bool{true, false, false, false, false, false},
133+
},
134+
{
135+
opts: []OptsFunc{WithExists(true)},
136+
fns: append([]CheckerFn{IsExist}, allFuncsExcept(IsExist)...),
137+
expectations: []bool{true, false, false, false, false, false},
138+
},
139+
{
140+
opts: []OptsFunc{WithNotFound(true)},
141+
fns: append([]CheckerFn{IsNotFound}, allFuncsExcept(IsNotFound)...),
142+
expectations: []bool{true, false, false, false, false, false},
143+
},
144+
{
145+
opts: []OptsFunc{WithRateLimit(true)},
146+
fns: append([]CheckerFn{IsRateLimit}, allFuncsExcept(IsRateLimit)...),
147+
expectations: []bool{true, false, false, false, false, false},
148+
},
149+
{
150+
opts: []OptsFunc{WithTooLarge(true)},
151+
fns: append([]CheckerFn{IsTooLarge}, allFuncsExcept(IsTooLarge)...),
152+
expectations: []bool{true, false, false, false, false, false},
153+
},
154+
{
155+
opts: []OptsFunc{WithAccessDenied(true), WithTooLarge(true),
156+
WithConflict(true), WithNotFound(true), WithExists(true),
157+
WithRateLimit(true), WithTooLarge(true),
158+
},
159+
fns: allFuncs,
160+
expectations: []bool{true, true, true, true, true, true},
161+
},
162+
{
163+
opts: []OptsFunc{WithAccessDenied(true), WithTooLarge(true),
164+
WithConflict(true), WithNotFound(true), WithExists(true),
165+
WithRateLimit(true), WithTooLarge(false),
166+
},
167+
fns: allFuncs,
168+
expectations: []bool{true, true, true, true, true, false},
169+
},
170+
}
171+
68172
for idx, tt := range tests {
69173
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
70174
e := New(err, tt.opts...)
@@ -82,7 +186,7 @@ func TestNewError(t *testing.T) {
82186
})
83187

84188
t.Run("should handle tagged errors as expected", func(t *testing.T) {
85-
e := New(errors.New("hi"), WithTags(NewTag("what", "is"), NewTag("hello", "world")))
189+
e := New("hi", WithTags(NewTag("what", "is"), NewTag("hello", "world")))
86190
if !IsTaggable(e) {
87191
t.Fatal("expected IsTaggable to return true")
88192
}
@@ -94,7 +198,7 @@ func TestNewError(t *testing.T) {
94198
}
95199

96200
t.Run("should handle nested tags as well", func(t *testing.T) {
97-
nested := New(e, WithEasyTags("yes", "sir", "will", "be"))
201+
nested := Wrap(e, WithEasyTags("yes", "sir", "will", "be"))
98202
if !IsTaggable(nested) {
99203
t.Fatal("expected IsTaggable to return true")
100204
}
@@ -109,7 +213,7 @@ func TestNewError(t *testing.T) {
109213
})
110214

111215
t.Run("should generate stack trace when option provided", func(t *testing.T) {
112-
err := New(errors.New("hey there"), WithStackTrace(0))
216+
err := New("hey there", WithStackTrace(0))
113217
fmt.Printf("%+v\n", err)
114218
})
115219
}

0 commit comments

Comments
 (0)