2025-07-07 21:04:42 -05:00
|
|
|
package ezhandler_test
|
2025-07-07 21:39:47 -05:00
|
|
|
|
|
|
|
|
import (
|
2025-07-08 16:41:08 -05:00
|
|
|
"encoding/json"
|
2025-07-08 16:04:28 -05:00
|
|
|
"io"
|
2025-07-07 21:39:47 -05:00
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
2025-07-08 16:04:28 -05:00
|
|
|
"strings"
|
2025-07-07 21:39:47 -05:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"codeberg.org/danjones000/ezhandler"
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestHandlerFunc_ServeHTTP(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
handlerFunc ezhandler.HandlerFunc
|
|
|
|
|
expectedErr error
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "no error",
|
|
|
|
|
handlerFunc: ezhandler.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
return nil
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "with error",
|
|
|
|
|
handlerFunc: ezhandler.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
|
|
|
|
return errTest
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: errTest,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/", http.NoBody)
|
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
err := tt.handlerFunc.ServeHTTP(rec, req)
|
|
|
|
|
if tt.expectedErr != nil {
|
|
|
|
|
assert.Equal(t, tt.expectedErr, err)
|
|
|
|
|
} else {
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-08 16:04:28 -05:00
|
|
|
|
|
|
|
|
type testBody struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Age int `json:"age"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type jsonBodyTest struct {
|
|
|
|
|
name string
|
|
|
|
|
requestBody string
|
|
|
|
|
handler ezhandler.JSONBodyHandler[testBody]
|
|
|
|
|
expectedStatus int
|
|
|
|
|
expectedBody string
|
|
|
|
|
expectedErr error
|
|
|
|
|
expectedErrContains string
|
|
|
|
|
additionAssert func(*assert.Assertions, testBody)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var jsonBodyHandlerTests = []jsonBodyTest{
|
|
|
|
|
{
|
|
|
|
|
name: "successful decoding and handler execution",
|
|
|
|
|
requestBody: `{"name":"John Doe","age":30}`,
|
|
|
|
|
handler: ezhandler.JSONBodyHandler[testBody](func(w http.ResponseWriter, r *http.Request, body testBody) error {
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
_, _ = w.Write([]byte("success"))
|
|
|
|
|
return nil
|
|
|
|
|
}),
|
|
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
|
expectedBody: "success",
|
|
|
|
|
expectedErr: nil,
|
|
|
|
|
additionAssert: func(as *assert.Assertions, body testBody) {
|
|
|
|
|
as.Equal("John Doe", body.Name)
|
|
|
|
|
as.Equal(30, body.Age)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "invalid JSON body",
|
|
|
|
|
requestBody: `{"name":"John Doe","age":}`,
|
|
|
|
|
handler: ezhandler.JSONBodyHandler[testBody](func(w http.ResponseWriter, r *http.Request, body testBody) error {
|
|
|
|
|
return nil // Should not be called
|
|
|
|
|
}),
|
|
|
|
|
expectedErrContains: "invalid character",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "empty body for struct type",
|
|
|
|
|
requestBody: "",
|
|
|
|
|
handler: ezhandler.JSONBodyHandler[testBody](func(w http.ResponseWriter, r *http.Request, body testBody) error {
|
|
|
|
|
return nil // Should not be called
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: io.EOF,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "handler function returns error",
|
|
|
|
|
requestBody: `{"name":"Jane Doe","age":25}`,
|
|
|
|
|
handler: ezhandler.JSONBodyHandler[testBody](func(w http.ResponseWriter, r *http.Request, body testBody) error {
|
|
|
|
|
return errTest
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: errTest,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestJSONBodyHandler_ServeHTTP(t *testing.T) {
|
|
|
|
|
for _, tc := range jsonBodyHandlerTests {
|
|
|
|
|
runJSONBodyHandlerTest(t, tc)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func runJSONBodyHandlerTest(tt *testing.T, tc jsonBodyTest) {
|
|
|
|
|
tt.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
handler := ezhandler.JSONBodyHandler[testBody](func(w http.ResponseWriter, r *http.Request, body testBody) error {
|
|
|
|
|
if err := tc.handler(w, r, body); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if tc.additionAssert != nil {
|
|
|
|
|
as := assert.New(t)
|
|
|
|
|
tc.additionAssert(as, body)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tc.requestBody))
|
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
err := handler.ServeHTTP(rec, req)
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case tc.expectedErr != nil:
|
|
|
|
|
assert.Equal(t, tc.expectedErr, err)
|
|
|
|
|
case tc.expectedErrContains != "":
|
|
|
|
|
assert.ErrorContains(t, err, tc.expectedErrContains)
|
|
|
|
|
default:
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tc.expectedStatus, rec.Code)
|
|
|
|
|
assert.Equal(t, tc.expectedBody, rec.Body.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-07-08 16:41:08 -05:00
|
|
|
|
|
|
|
|
type jsonBodyResponderTest struct {
|
|
|
|
|
name string
|
|
|
|
|
requestBody string
|
|
|
|
|
handler ezhandler.JSONResponder[testBody]
|
|
|
|
|
expectedStatus int
|
|
|
|
|
expectedBody testBody
|
|
|
|
|
expectedErr error
|
|
|
|
|
expectedErrContains string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var jsonBodyResponderTests = []jsonBodyResponderTest{
|
|
|
|
|
{
|
|
|
|
|
name: "successful decoding and response",
|
|
|
|
|
requestBody: `{"name":"John Doe","age":30}`,
|
|
|
|
|
handler: ezhandler.JSONResponder[testBody](func(r *http.Request, body testBody) (ezhandler.ResponseHelper, error) {
|
|
|
|
|
return ezhandler.JSONResponse(body), nil
|
|
|
|
|
}),
|
|
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
|
expectedBody: testBody{Name: "John Doe", Age: 30},
|
|
|
|
|
expectedErr: nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "invalid JSON body",
|
|
|
|
|
requestBody: `{"name":"John Doe","age":}`,
|
|
|
|
|
handler: ezhandler.JSONResponder[testBody](func(r *http.Request, body testBody) (ezhandler.ResponseHelper, error) {
|
|
|
|
|
return nil, nil // Should not be called
|
|
|
|
|
}),
|
|
|
|
|
expectedErrContains: "invalid character",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "empty body for struct type",
|
|
|
|
|
requestBody: "",
|
|
|
|
|
handler: ezhandler.JSONResponder[testBody](func(r *http.Request, body testBody) (ezhandler.ResponseHelper, error) {
|
|
|
|
|
return nil, nil // Should not be called
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: io.EOF,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "handler function returns error",
|
|
|
|
|
requestBody: `{"name":"Jane Doe","age":25}`,
|
|
|
|
|
handler: ezhandler.JSONResponder[testBody](func(r *http.Request, body testBody) (ezhandler.ResponseHelper, error) {
|
|
|
|
|
return nil, errTest
|
|
|
|
|
}),
|
|
|
|
|
expectedErr: errTest,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestJSONResponder_ServeHTTP(t *testing.T) {
|
|
|
|
|
for _, tc := range jsonBodyResponderTests {
|
|
|
|
|
runJSONResponderTest(t, tc)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func runJSONResponderTest(tt *testing.T, tc jsonBodyResponderTest) {
|
|
|
|
|
tt.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tc.requestBody))
|
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
|
|
|
|
|
|
err := tc.handler.ServeHTTP(rec, req)
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case tc.expectedErr != nil:
|
|
|
|
|
assert.Equal(t, tc.expectedErr, err)
|
|
|
|
|
case tc.expectedErrContains != "":
|
|
|
|
|
assert.ErrorContains(t, err, tc.expectedErrContains)
|
|
|
|
|
default:
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tc.expectedStatus, rec.Code)
|
|
|
|
|
// Marshal expectedBody to JSON string for comparison
|
|
|
|
|
expectedBodyBytes, marshalErr := json.Marshal(tc.expectedBody)
|
|
|
|
|
assert.NoError(t, marshalErr)
|
|
|
|
|
assert.JSONEq(t, string(expectedBodyBytes), rec.Body.String())
|
|
|
|
|
assert.Equal(t, "application/json", rec.Header().Get("Content-Type"))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|