Skip to content

Commit 217ec38

Browse files
authored
chore(api-error): change unauthorized msg and add tests (#2190)
* chore(api-error): change unauthorized msg and add tests * chore: add Error test
1 parent 48ea497 commit 217ec38

File tree

2 files changed

+265
-1
lines changed

2 files changed

+265
-1
lines changed

api/types/errors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func NewBadRequestError(err error) *APIError {
5757
func NewUnauthorizedError(err error) *APIError {
5858
return &APIError{
5959
StatusCode: http.StatusUnauthorized,
60-
Message: err.Error(),
60+
Message: "Unauthorized",
6161
err: err,
6262
}
6363
}

api/types/errors_test.go

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"net/http"
8+
"net/http/httptest"
79
"testing"
10+
11+
"github.com/stretchr/testify/assert"
812
)
913

1014
func TestAppendFieldError(t *testing.T) {
@@ -51,3 +55,263 @@ func TestAppendFieldError(t *testing.T) {
5155
})
5256
}
5357
}
58+
59+
func TestNewAPIError(t *testing.T) {
60+
tests := []struct {
61+
name string
62+
err error
63+
newFunction func(err error) *APIError
64+
want struct {
65+
statusCode int
66+
message string
67+
}
68+
}{
69+
{
70+
name: "BadRequestError",
71+
err: errors.New("bad request"),
72+
newFunction: NewBadRequestError,
73+
want: struct {
74+
statusCode int
75+
message string
76+
}{
77+
statusCode: http.StatusBadRequest,
78+
message: "bad request",
79+
},
80+
},
81+
{
82+
name: "UnauthorizedError",
83+
err: errors.New("auth failed"),
84+
newFunction: NewUnauthorizedError,
85+
want: struct {
86+
statusCode int
87+
message string
88+
}{
89+
statusCode: http.StatusUnauthorized,
90+
message: "Unauthorized",
91+
},
92+
},
93+
{
94+
name: "InternalServerError",
95+
newFunction: NewInternalServerError,
96+
err: errors.New("internal server error"),
97+
want: struct {
98+
statusCode int
99+
message string
100+
}{
101+
statusCode: http.StatusInternalServerError,
102+
message: "internal server error",
103+
},
104+
},
105+
}
106+
107+
for _, tt := range tests {
108+
t.Run(tt.name, func(t *testing.T) {
109+
apiErr := tt.newFunction(tt.err)
110+
111+
assert.Equal(t, tt.want.statusCode, apiErr.StatusCode, "StatusCode should match")
112+
assert.Equal(t, tt.want.message, apiErr.Message, "Message should match")
113+
assert.Equal(t, tt.err, apiErr.err, "Original error should be stored")
114+
})
115+
}
116+
}
117+
118+
func TestAPIError_Error(t *testing.T) {
119+
tests := []struct {
120+
name string
121+
apiError *APIError
122+
expected string
123+
}{
124+
{
125+
name: "nil error",
126+
apiError: nil,
127+
expected: "",
128+
},
129+
{
130+
name: "error with message, no sub-errors",
131+
apiError: &APIError{
132+
Message: "main error message",
133+
Errors: []*APIError{},
134+
},
135+
expected: "main error message",
136+
},
137+
{
138+
name: "error with message and one sub-error",
139+
apiError: &APIError{
140+
Message: "main error message",
141+
Errors: []*APIError{
142+
{Message: "sub-error 1"},
143+
},
144+
},
145+
expected: "main error message: sub-error 1",
146+
},
147+
{
148+
name: "error with message and multiple sub-errors",
149+
apiError: &APIError{
150+
Message: "main error message",
151+
Errors: []*APIError{
152+
{Message: "sub-error 1"},
153+
{Message: "sub-error 2"},
154+
{Message: "sub-error 3"},
155+
},
156+
},
157+
expected: "main error message: sub-error 1; sub-error 2; sub-error 3",
158+
},
159+
}
160+
161+
for _, tt := range tests {
162+
t.Run(tt.name, func(t *testing.T) {
163+
got := tt.apiError.Error()
164+
assert.Equal(t, tt.expected, got, "Error() should return the expected string")
165+
})
166+
}
167+
}
168+
169+
func TestAPIError_ErrorOrNil(t *testing.T) {
170+
tests := []struct {
171+
name string
172+
err *APIError
173+
wantNil bool
174+
}{
175+
{
176+
name: "nil error",
177+
err: (*APIError)(nil),
178+
wantNil: true,
179+
},
180+
{
181+
name: "error without child errors",
182+
err: &APIError{
183+
StatusCode: http.StatusBadRequest,
184+
Message: "bad request",
185+
Errors: nil,
186+
},
187+
wantNil: true,
188+
},
189+
{
190+
name: "error with empty errors slice",
191+
err: &APIError{
192+
StatusCode: http.StatusBadRequest,
193+
Message: "bad request",
194+
Errors: []*APIError{},
195+
},
196+
wantNil: true,
197+
},
198+
{
199+
name: "error with child errors",
200+
err: &APIError{
201+
StatusCode: http.StatusBadRequest,
202+
Message: "validation failed",
203+
Errors: []*APIError{
204+
{
205+
Message: "field1: invalid value",
206+
Field: "field1",
207+
},
208+
},
209+
},
210+
wantNil: false,
211+
},
212+
}
213+
214+
for _, tt := range tests {
215+
t.Run(tt.name, func(t *testing.T) {
216+
result := tt.err.ErrorOrNil()
217+
218+
if tt.wantNil {
219+
assert.Nil(t, result, "ErrorOrNil() should return nil")
220+
} else {
221+
assert.NotNil(t, result, "ErrorOrNil() should not return nil")
222+
assert.Equal(t, tt.err, result, "ErrorOrNil() should return the error itself")
223+
}
224+
})
225+
}
226+
}
227+
228+
func TestAPIError_JSON(t *testing.T) {
229+
tests := []struct {
230+
name string
231+
apiErr *APIError
232+
wantCode int
233+
wantJSON map[string]any
234+
}{
235+
{
236+
name: "simple error",
237+
apiErr: &APIError{
238+
StatusCode: http.StatusInternalServerError,
239+
Message: "invalid request",
240+
},
241+
wantCode: http.StatusInternalServerError,
242+
wantJSON: map[string]any{
243+
"status_code": float64(http.StatusInternalServerError),
244+
"message": "invalid request",
245+
},
246+
},
247+
{
248+
name: "field error",
249+
apiErr: &APIError{
250+
StatusCode: http.StatusBadRequest,
251+
Message: "validation error",
252+
Field: "username",
253+
},
254+
wantCode: http.StatusBadRequest,
255+
wantJSON: map[string]any{
256+
"status_code": float64(http.StatusBadRequest),
257+
"message": "validation error",
258+
"field": "username",
259+
},
260+
},
261+
{
262+
name: "error with nested errors",
263+
apiErr: &APIError{
264+
StatusCode: http.StatusBadRequest,
265+
Message: "multiple validation errors",
266+
Errors: []*APIError{
267+
{
268+
Message: "field1 is required",
269+
Field: "field1",
270+
},
271+
{
272+
Message: "field2 must be a number",
273+
Field: "field2",
274+
},
275+
},
276+
},
277+
wantCode: http.StatusBadRequest,
278+
wantJSON: map[string]any{
279+
"status_code": float64(http.StatusBadRequest),
280+
"message": "multiple validation errors",
281+
"errors": []any{
282+
map[string]any{
283+
"message": "field1 is required",
284+
"field": "field1",
285+
},
286+
map[string]any{
287+
"message": "field2 must be a number",
288+
"field": "field2",
289+
},
290+
},
291+
},
292+
},
293+
}
294+
295+
for _, tt := range tests {
296+
t.Run(tt.name, func(t *testing.T) {
297+
// Create a mock HTTP response recorder
298+
rec := httptest.NewRecorder()
299+
300+
// Call the JSON method
301+
tt.apiErr.JSON(rec)
302+
303+
// Check status code
304+
assert.Equal(t, tt.wantCode, rec.Code, "Status code should match")
305+
306+
// Check content type header
307+
contentType := rec.Header().Get("Content-Type")
308+
assert.Equal(t, "application/json", contentType, "Content-Type header should be application/json")
309+
310+
// Parse and check the JSON response
311+
var gotJSON map[string]any
312+
err := json.Unmarshal(rec.Body.Bytes(), &gotJSON)
313+
assert.NoError(t, err, "Should be able to parse the JSON response")
314+
assert.Equal(t, tt.wantJSON, gotJSON, "JSON response should match expected structure")
315+
})
316+
}
317+
}

0 commit comments

Comments
 (0)