Skip to content

Commit

Permalink
Merge pull request #5 from jsteenb2/chore/wrap_tests
Browse files Browse the repository at this point in the history
chore: isolate TestErrors and add missing Wrap tests
  • Loading branch information
jsteenb2 authored Mar 18, 2024
2 parents 09c7f1d + 1e3c995 commit 7bb1e7d
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 173 deletions.
192 changes: 192 additions & 0 deletions errors_stack_traces_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package errors_test

import (
"fmt"
"testing"

"github.com/jsteenb2/errors"
)

/*
This file exists b/c the below tests do not interoperate well with
active development as any import statement will throw off the stack
traces. Isolating them here, allows us to make errors_stack_traces_test.go more
active, without having to worry about imports dorking up a large
swathe of tests.
*/

func Test_Errors(t *testing.T) {
type wants struct {
msg string
fields []any
}

tests := []struct {
name string
input error
want wants
}{
{
name: "simple new error",
input: errors.New("simple msg"),
want: wants{
msg: "simple msg",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:31[Test_Errors]"}},
},
},
{
name: "with error kind",
input: errors.New("simple msg", errors.Kind("tester")),
want: wants{
msg: "simple msg",
fields: []any{"err_kind", "tester", "stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:39[Test_Errors]"}},
},
},
{
name: "with kv pair",
input: errors.New("simple msg", errors.KV{K: "key1", V: "val1"}),
want: wants{
msg: "simple msg",
fields: []any{"key1", "val1", "stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:47[Test_Errors]"}},
},
},
{
name: "with kv pairs",
input: errors.New("simple msg", errors.KVs("k1", "v1", "k2", []string{"somevalslc"})),
want: wants{
msg: "simple msg",
fields: []any{"k1", "v1", "k2", []string{"somevalslc"}, "stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:55[Test_Errors]"}},
},
},
{
name: "without stack trace",
input: errors.New("simple msg", errors.NoFrame),
want: wants{
msg: "simple msg",
fields: []any{},
},
},
{
name: "with New and error to wrap",
input: errors.New("wrap msg", fmt.Errorf("a std lib error")),
want: wants{
msg: "wrap msg: a std lib error",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:71[Test_Errors]"}},
},
},
{
name: "with frame skip",
input: func() error {
// should match line 75 (function call execution) in stack trace
return errors.New("simple msg", errors.SkipCaller)
}(),
want: wants{
msg: "simple msg",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:82[Test_Errors]"}},
},
},
{
name: "with wrap of std lib error",
input: errors.Wrap(fmt.Errorf("simple error"), "wrap msg"),
want: wants{
msg: "wrap msg: simple error",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_stack_traces_test.go:90[Test_Errors]"}},
},
},
{
name: "with wrap of errors error",
input: errors.Wrap(
errors.New("simple error"),
"wrap msg",
),
want: wants{
msg: "wrap msg: simple error",
fields: []any{"stack_trace", []string{
"github.com/jsteenb2/errors/errors_stack_traces_test.go:98[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:99[Test_Errors]",
}},
},
},
{
name: "with wrap of errors error and mix of options",
input: errors.Wrap(
errors.New("simple error", errors.KVs("inner_k1", "inner_v1")),
"wrap msg",
errors.KVs("wrapped_k1", "wrapped_v1"),
),
want: wants{
msg: "wrap msg: simple error",
fields: []any{
"wrapped_k1", "wrapped_v1",
"inner_k1", "inner_v1",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_stack_traces_test.go:112[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:113[Test_Errors]",
},
},
},
},
{
name: "with wrap of errors error with outer error kind",
input: errors.Wrap(
errors.New("simple error"),
errors.Kind("wrapper"),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "wrapper",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_stack_traces_test.go:131[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:132[Test_Errors]",
},
},
},
},
{
name: "with wrap of errors error with inner error kind",
input: errors.Wrap(
errors.New("simple error", errors.Kind("inner")),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "inner",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_stack_traces_test.go:148[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:149[Test_Errors]",
},
},
},
},
{
name: "with multiple wraps of errors error with inner error kind",
input: errors.Wrap(
errors.Wrap(
errors.Wrap(
errors.New("simple error", errors.Kind("inner")),
),
),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "inner",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_stack_traces_test.go:164[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:165[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:166[Test_Errors]",
"github.com/jsteenb2/errors/errors_stack_traces_test.go:167[Test_Errors]",
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
eq(t, tt.want.msg, tt.input.Error())
eqFields(t, tt.want.fields, errors.Fields(tt.input))
})
}
}
192 changes: 19 additions & 173 deletions errors_test.go
Original file line number Diff line number Diff line change
@@ -1,187 +1,33 @@
package errors_test

import (
"fmt"
stderrors "errors"
"reflect"
"testing"

"github.com/jsteenb2/errors"
)

func Test_Errors(t *testing.T) {
type wants struct {
msg string
fields []any
}
func TestWrap(t *testing.T) {
t.Run("simple wrapped error is returned when calling std lib errors.Unwrap", func(t *testing.T) {
baseErr := errors.New("first error")

tests := []struct {
name string
input error
want wants
}{
{
name: "simple new error",
input: errors.New("simple msg"),
want: wants{
msg: "simple msg",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:24[Test_Errors]"}},
},
},
{
name: "with error kind",
input: errors.New("simple msg", errors.Kind("tester")),
want: wants{
msg: "simple msg",
fields: []any{"err_kind", "tester", "stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:32[Test_Errors]"}},
},
},
{
name: "with kv pair",
input: errors.New("simple msg", errors.KV{K: "key1", V: "val1"}),
want: wants{
msg: "simple msg",
fields: []any{"key1", "val1", "stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:40[Test_Errors]"}},
},
},
{
name: "with kv pairs",
input: errors.New("simple msg", errors.KVs("k1", "v1", "k2", []string{"somevalslc"})),
want: wants{
msg: "simple msg",
fields: []any{"k1", "v1", "k2", []string{"somevalslc"}, "stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:48[Test_Errors]"}},
},
},
{
name: "without stack trace",
input: errors.New("simple msg", errors.NoFrame),
want: wants{
msg: "simple msg",
fields: []any{},
},
},
{
name: "with New and error to wrap",
input: errors.New("wrap msg", fmt.Errorf("a std lib error")),
want: wants{
msg: "wrap msg: a std lib error",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:64[Test_Errors]"}},
},
},
{
name: "with frame skip",
input: func() error {
// should match line 75 (function call execution) in stack trace
return errors.New("simple msg", errors.SkipCaller)
}(),
want: wants{
msg: "simple msg",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:75[Test_Errors]"}},
},
},
{
name: "with wrap of std lib error",
input: errors.Wrap(fmt.Errorf("simple error"), "wrap msg"),
want: wants{
msg: "wrap msg: simple error",
fields: []any{"stack_trace", []string{"github.com/jsteenb2/errors/errors_test.go:83[Test_Errors]"}},
},
},
{
name: "with wrap of errors error",
input: errors.Wrap(
errors.New("simple error"),
"wrap msg",
),
want: wants{
msg: "wrap msg: simple error",
fields: []any{"stack_trace", []string{
"github.com/jsteenb2/errors/errors_test.go:91[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:92[Test_Errors]",
}},
},
},
{
name: "with wrap of errors error and mix of options",
input: errors.Wrap(
errors.New("simple error", errors.KVs("inner_k1", "inner_v1")),
"wrap msg",
errors.KVs("wrapped_k1", "wrapped_v1"),
),
want: wants{
msg: "wrap msg: simple error",
fields: []any{
"wrapped_k1", "wrapped_v1",
"inner_k1", "inner_v1",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_test.go:105[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:106[Test_Errors]",
},
},
},
},
{
name: "with wrap of errors error with outer error kind",
input: errors.Wrap(
errors.New("simple error"),
errors.Kind("wrapper"),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "wrapper",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_test.go:124[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:125[Test_Errors]",
},
},
},
},
{
name: "with wrap of errors error with inner error kind",
input: errors.Wrap(
errors.New("simple error", errors.Kind("inner")),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "inner",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_test.go:141[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:142[Test_Errors]",
},
},
},
},
{
name: "with multiple wraps of errors error with inner error kind",
input: errors.Wrap(
errors.Wrap(
errors.Wrap(
errors.New("simple error", errors.Kind("inner")),
),
),
),
want: wants{
msg: "simple error",
fields: []any{
"err_kind", "inner",
"stack_trace", []string{
"github.com/jsteenb2/errors/errors_test.go:157[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:158[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:159[Test_Errors]",
"github.com/jsteenb2/errors/errors_test.go:160[Test_Errors]",
},
},
},
},
}
if unwrapped := stderrors.Unwrap(baseErr); unwrapped != nil {
t.Fatalf("recieved unexpected unwrapped error:\n\t\tgot:\t%v", unwrapped)
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
eq(t, tt.want.msg, tt.input.Error())
eqFields(t, tt.want.fields, errors.Fields(tt.input))
})
}
wrappedErr := errors.Wrap(baseErr)
if unwrapped := stderrors.Unwrap(wrappedErr); unwrapped == nil {
t.Fatalf("recieved unexpected nil unwrapped error")
}
})

t.Run("unwrapping nil error should return nil", func(t *testing.T) {
err := errors.Wrap(nil)
if err != nil {
t.Fatalf("recieved unexpected wrapped error:\n\t\tgot:\t%v", err)
}
})
}

func TestV(t *testing.T) {
Expand Down

0 comments on commit 7bb1e7d

Please sign in to comment.