Commit 79e328c5 authored by Kirill Smelkov's avatar Kirill Smelkov

xerr += First, Merge

This are handy utilities to reduce several errors into only 1 either
picking the first error or merging, if there are several, into Errorv.

It is unfortunate but an issue with Errorv was realized that even though
it satisfies the error interface, it cannot be generally worked with as
error because it (being []error) is uncomparable. Thus e.g. the following
code, if err dynamic type is Errorv, will panic:

	if err == io.EOF

It is pity Go slices are uncomparable.
parent 8f170959
...@@ -73,6 +73,29 @@ func (errv Errorv) Err() error { ...@@ -73,6 +73,29 @@ func (errv Errorv) Err() error {
} }
} }
// Merge merges non-nil errors into one error
// it returns:
// - nil if all errors are nil
// - single error if there is only one non-nil error
// - Errorv with non-nil errors if there is more than one non-nil error
func Merge(errv ...error) error {
ev := Errorv{}
for _, err := range errv {
ev.Appendif(err)
}
return ev.Err()
}
// First returns first non-nil error, or nil if there is no errors
func First(errv ...error) error {
for _, err := range errv {
if err != nil {
return err
}
}
return nil
}
// ---------------------------------------- // ----------------------------------------
// Context provides error context to be automatically added on error return // Context provides error context to be automatically added on error return
......
...@@ -64,6 +64,66 @@ func TestErrorv(t *testing.T) { ...@@ -64,6 +64,66 @@ func TestErrorv(t *testing.T) {
`) `)
} }
func TestMerge(t *testing.T) {
e := errors.New("e")
e2 := errors.New("e2")
testv := []struct {
in []error
out error
}{
{nil, nil},
{[]error{}, nil},
{[]error{nil}, nil},
{[]error{nil, nil}, nil},
{[]error{e}, e},
{[]error{e, nil}, e},
{[]error{nil, e}, e},
{[]error{nil, e, nil}, e},
{[]error{nil, e, e2}, Errorv{e, e2}},
{[]error{nil, e2, e}, Errorv{e2, e}},
{[]error{nil, e2, nil, e}, Errorv{e2, e}},
{[]error{nil, e2, nil, e, nil}, Errorv{e2, e}},
}
for _, tt := range testv {
err := Merge(tt.in...)
//if err != tt.out {
// XXX Errorv is uncomparable because it is []
if !reflect.DeepEqual(err, tt.out) {
t.Errorf("Merge(%v) -> %v ; want %v", tt.in, err, tt.out)
}
}
}
func TestFirst(t *testing.T) {
e := errors.New("e")
e2 := errors.New("e2")
testv := []struct {
in []error
out error
}{
{nil, nil},
{[]error{}, nil},
{[]error{nil}, nil},
{[]error{nil, nil}, nil},
{[]error{e}, e},
{[]error{e, nil}, e},
{[]error{nil, e}, e},
{[]error{nil, e, nil}, e},
{[]error{nil, e, e2}, e},
{[]error{nil, e2, e}, e2},
}
for _, tt := range testv {
err := First(tt.in...)
if err != tt.out {
t.Errorf("First(%v) -> %v ; want %v", tt.in, err, tt.out)
}
}
}
func TestContext(t *testing.T) { func TestContext(t *testing.T) {
test := func(e error) (err error) { test := func(e error) (err error) {
defer Context(&err, "test ctx") defer Context(&err, "test ctx")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment