Skip to content

Commit 0a282f0

Browse files
authored
feat: implement errors interfaces & improve tests (#91)
1 parent 060d18a commit 0a282f0

3 files changed

Lines changed: 75 additions & 90 deletions

File tree

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ issues:
5151
- path: (.+)_test.go
5252
linters:
5353
- errcheck
54+
- errorlint
5455
- funlen
5556
- goerr113
5657
- gosec

errors.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding"
77
"encoding/xml"
88
"errors"
9-
"net/http"
109
"strconv"
1110

1211
"github.com/abemedia/go-don/internal/byteconv"
@@ -33,6 +32,14 @@ func (e *HTTPError) Error() string {
3332
return e.err.Error()
3433
}
3534

35+
func (e *HTTPError) Is(err error) bool {
36+
return errors.Is(e.err, err) || errors.Is(StatusError(e.code), err)
37+
}
38+
39+
func (e *HTTPError) Unwrap() error {
40+
return e.err
41+
}
42+
3643
func (e *HTTPError) StatusCode() int {
3744
if e.code != 0 {
3845
return e.code
@@ -43,7 +50,7 @@ func (e *HTTPError) StatusCode() int {
4350
return sc.StatusCode()
4451
}
4552

46-
return http.StatusInternalServerError
53+
return fasthttp.StatusInternalServerError
4754
}
4855

4956
func (e *HTTPError) MarshalText() ([]byte, error) {

errors_test.go

Lines changed: 65 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,100 @@
11
package don_test
22

33
import (
4-
"context"
54
"encoding/xml"
65
"errors"
76
"fmt"
8-
"net/http"
97
"testing"
108

119
"github.com/abemedia/go-don"
1210
_ "github.com/abemedia/go-don/encoding/json"
1311
_ "github.com/abemedia/go-don/encoding/text"
1412
_ "github.com/abemedia/go-don/encoding/xml"
1513
_ "github.com/abemedia/go-don/encoding/yaml"
16-
"github.com/abemedia/go-don/internal/byteconv"
17-
"github.com/abemedia/go-don/pkg/httptest"
14+
"github.com/goccy/go-json"
1815
"github.com/google/go-cmp/cmp"
16+
"github.com/valyala/fasthttp"
17+
"gopkg.in/yaml.v3"
1918
)
2019

21-
func TestError(t *testing.T) {
22-
tests := []struct {
23-
err error
24-
mime string
25-
body string
26-
code int
27-
}{
28-
{
29-
err: don.ErrBadRequest,
30-
mime: "text/plain; charset=utf-8",
31-
body: "Bad Request\n",
32-
code: http.StatusBadRequest,
33-
},
34-
{
35-
err: don.Error(errors.New("test"), http.StatusBadRequest),
36-
mime: "text/plain; charset=utf-8",
37-
body: "test\n",
38-
code: http.StatusBadRequest,
39-
},
40-
{
41-
err: errors.New("test"),
42-
mime: "text/plain; charset=utf-8",
43-
body: "test\n",
44-
code: http.StatusInternalServerError,
45-
},
46-
{
47-
err: errors.New("test"),
48-
mime: "application/json; charset=utf-8",
49-
body: `{"message":"test"}` + "\n",
50-
code: http.StatusInternalServerError,
51-
},
52-
{
53-
err: errors.New("test"),
54-
mime: "application/x-yaml; charset=utf-8",
55-
body: "message: test\n",
56-
code: http.StatusInternalServerError,
57-
},
58-
{
59-
err: errors.New("test"),
60-
mime: "application/xml; charset=utf-8",
61-
body: "<message>test</message>",
62-
code: http.StatusInternalServerError,
63-
},
64-
{
65-
err: &testError{},
66-
mime: "text/plain; charset=utf-8",
67-
body: "test\n",
68-
code: http.StatusInternalServerError,
69-
},
70-
{
71-
err: &testError{},
72-
mime: "application/json; charset=utf-8",
73-
body: `{"custom":"test"}` + "\n",
74-
code: http.StatusInternalServerError,
75-
},
76-
{
77-
err: &testError{},
78-
mime: "application/x-yaml; charset=utf-8",
79-
body: "custom: test\n",
80-
code: http.StatusInternalServerError,
81-
},
82-
{
83-
err: &testError{},
84-
mime: "application/xml; charset=utf-8",
85-
body: "<custom>test</custom>",
86-
code: http.StatusInternalServerError,
87-
},
20+
func TestError_Is(t *testing.T) {
21+
if !errors.Is(don.Error(errTest, 0), errTest) {
22+
t.Error("should match wrapped error")
8823
}
24+
if !errors.Is(don.Error(errTest, fasthttp.StatusBadRequest), don.ErrBadRequest) {
25+
t.Error("should match status error")
26+
}
27+
}
8928

90-
for _, tc := range tests {
91-
ctx := httptest.NewRequest("", "/", "", map[string]string{"Accept": tc.mime})
29+
func TestError_Unwrap(t *testing.T) {
30+
if errors.Unwrap(don.Error(errTest, 0)) != errTest {
31+
t.Error("should unwrap wrapped error")
32+
}
33+
}
9234

93-
api := don.New(nil)
94-
api.Get("/", don.H(func(ctx context.Context, req don.Empty) (any, error) { return nil, tc.err }))
95-
api.RequestHandler()(ctx)
35+
func TestError_StatusCode(t *testing.T) {
36+
if don.Error(don.ErrBadRequest, 0).StatusCode() != fasthttp.StatusBadRequest {
37+
t.Error("should respect wrapped error's status code")
38+
}
39+
if don.Error(don.ErrBadRequest, fasthttp.StatusConflict).StatusCode() != fasthttp.StatusConflict {
40+
t.Error("should ignore wrapped error's status code if explicitly set")
41+
}
42+
}
9643

97-
type response struct {
98-
Code int
99-
Body string
100-
Header map[string]string
101-
}
44+
func TestError_MarshalText(t *testing.T) {
45+
b, _ := don.Error(errTest, 0).MarshalText()
46+
if diff := cmp.Diff("test", string(b)); diff != "" {
47+
t.Error(diff)
48+
}
49+
b, _ = don.Error(&testError{}, 0).MarshalText()
50+
if diff := cmp.Diff("custom", string(b)); diff != "" {
51+
t.Error(diff)
52+
}
53+
}
10254

103-
res := response{ctx.Response.StatusCode(), string(ctx.Response.Body()), map[string]string{}}
104-
ctx.Response.Header.VisitAll(func(key, value []byte) { res.Header[string(key)] = string(value) })
55+
func TestError_MarshalJSON(t *testing.T) {
56+
b, _ := json.Marshal(don.Error(errTest, 0))
57+
if diff := cmp.Diff(`{"message":"test"}`, string(b)); diff != "" {
58+
t.Error(diff)
59+
}
60+
b, _ = json.Marshal(don.Error(&testError{}, 0))
61+
if diff := cmp.Diff(`{"custom":"test"}`, string(b)); diff != "" {
62+
t.Error(diff)
63+
}
64+
}
10565

106-
want := response{tc.code, tc.body, map[string]string{"Content-Type": tc.mime}}
107-
if diff := cmp.Diff(want, res); diff != "" {
108-
t.Error(diff)
109-
}
66+
func TestError_MarshalXML(t *testing.T) {
67+
b, _ := xml.Marshal(don.Error(errTest, 0))
68+
if diff := cmp.Diff("<message>test</message>", string(b)); diff != "" {
69+
t.Error(diff)
70+
}
71+
b, _ = xml.Marshal(don.Error(&testError{}, 0))
72+
if diff := cmp.Diff("<custom>test</custom>", string(b)); diff != "" {
73+
t.Error(diff)
11074
}
11175
}
11276

77+
func TestError_MarshalYAML(t *testing.T) {
78+
b, _ := yaml.Marshal(don.Error(errTest, 0))
79+
if diff := cmp.Diff("message: test\n", string(b)); diff != "" {
80+
t.Error(diff)
81+
}
82+
b, _ = yaml.Marshal(don.Error(&testError{}, 0))
83+
if diff := cmp.Diff("custom: test\n", string(b)); diff != "" {
84+
t.Error(diff)
85+
}
86+
}
87+
88+
var errTest = errors.New("test")
89+
11390
type testError struct{}
11491

11592
func (e *testError) Error() string {
11693
return "test"
11794
}
11895

11996
func (e *testError) MarshalText() ([]byte, error) {
120-
return byteconv.Atob(e.Error()), nil
97+
return []byte("custom"), nil
12198
}
12299

123100
func (e *testError) MarshalJSON() ([]byte, error) {

0 commit comments

Comments
 (0)