package errors import ( "errors" "reflect" "strings" "testing" ) func TestWrap(t *testing.T) { err := errors.New("0") err1 := Wrap(err, "1") err2 := Wrap(err1, "2") err3 := Wrap(err2) if got := Root(err1); got != err { t.Fatalf("Root(%v)=%v want %v", err1, got, err) } if got := Root(err2); got != err { t.Fatalf("Root(%v)=%v want %v", err2, got, err) } if err2.Error() != "2: 1: 0" { t.Fatalf("err msg = %s want '2: 1: 0'", err2.Error()) } if err3.Error() != "2: 1: 0" { t.Fatalf("err msg = %s want '2: 1: 0'", err3.Error()) } stack := Stack(err1) if len(stack) == 0 { t.Fatalf("len(stack) = %v want > 0", len(stack)) } if !strings.Contains(stack[0].String(), "TestWrap") { t.Fatalf("first stack frame should contain \"TestWrap\": %v", stack[0].String()) } if !reflect.DeepEqual(Stack(err2), Stack(err1)) { t.Errorf("err2 stack got %v want %v", Stack(err2), Stack(err1)) } if !reflect.DeepEqual(Stack(err3), Stack(err1)) { t.Errorf("err3 stack got %v want %v", Stack(err3), Stack(err1)) } } func TestWrapNil(t *testing.T) { var err error err1 := Wrap(err, "1") if err1 != nil { t.Fatal("wrapping nil error should yield nil") } } func TestWrapf(t *testing.T) { err := errors.New("0") err1 := Wrapf(err, "there are %d errors being wrapped", 1) if err1.Error() != "there are 1 errors being wrapped: 0" { t.Fatalf("err msg = %s want 'there are 1 errors being wrapped: 0'", err1.Error()) } } func TestWrapMsg(t *testing.T) { err := errors.New("rooti") err1 := Wrap(err, "cherry", " ", "guava") if err1.Error() != "cherry guava: rooti" { t.Fatalf("err msg = %s want 'cherry guava: rooti'", err1.Error()) } } func TestDetail(t *testing.T) { root := errors.New("foo") cases := []struct { err error detail string message string }{ {root, "foo", "foo"}, {WithDetail(root, "bar"), "bar", "bar: foo"}, {WithDetail(WithDetail(root, "bar"), "baz"), "bar; baz", "baz: bar: foo"}, {Wrap(WithDetail(root, "bar"), "baz"), "bar", "baz: bar: foo"}, } for _, test := range cases { if got := Detail(test.err); got != test.detail { t.Errorf("Detail(%v) = %v want %v", test.err, got, test.detail) } if got := Root(test.err); got != root { t.Errorf("Root(%v) = %v want %v", test.err, got, root) } if got := test.err.Error(); got != test.message { t.Errorf("(%v).Error() = %v want %v", test.err, got, test.message) } } } func TestData(t *testing.T) { root := errors.New("foo") cases := []struct { err error data interface{} }{ {WithData(root, "a", "b"), map[string]interface{}{"a": "b"}}, {WithData(WithData(root, "a", "b"), "c", "d"), map[string]interface{}{"a": "b", "c": "d"}}, {Wrap(WithData(root, "a", "b"), "baz"), map[string]interface{}{"a": "b"}}, } for _, test := range cases { if got := Data(test.err); !reflect.DeepEqual(got, test.data) { t.Errorf("Data(%#v) = %v want %v", test.err, got, test.data) } if got := Root(test.err); got != root { t.Errorf("Root(%#v) = %v want %v", test.err, got, root) } } } func TestSub(t *testing.T) { x := errors.New("x") y := errors.New("y") cases := []struct{ new, old, want error }{ {nil, nil, nil}, {x, nil, nil}, {nil, Wrap(y), nil}, {Wrap(x), nil, nil}, {nil, y, nil}, {x, y, errors.New("y: x")}, {Wrap(x), y, errors.New("y: x")}, {x, Wrap(y), errors.New("y: x")}, {Wrap(x, "z"), Wrap(y), errors.New("y: z: x")}, } for _, test := range cases { got := Sub(test.new, test.old) if !(got == nil && test.want == nil || got.Error() == test.want.Error()) { t.Errorf("Sub(%#v, %#v) = %v, want %v", test.new, test.old, got, test.want) } } }