package ezhandler_test import ( "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "codeberg.org/danjones000/ezhandler" "github.com/stretchr/testify/assert" ) func TestJSONResponse(t *testing.T) { type testData struct { Message string `json:"message"` Code int `json:"code"` } data := testData{Message: "Hello", Code: 200} respHelper := ezhandler.JSONResponse(data) assert.Equal(t, http.StatusOK, respHelper.Status()) headers := respHelper.Headers() assert.Equal(t, "application/json", headers.Get("Content-Type")) body, err := respHelper.Body() assert.NoError(t, err) assert.NotNil(t, body) var decodedData testData err = json.NewDecoder(body).Decode(&decodedData) assert.NoError(t, err) assert.Equal(t, data, decodedData) } func TestJSONResponseWithStatus(t *testing.T) { type testData struct { Key string `json:"key"` } data := testData{Key: "value"} customStatus := http.StatusCreated respHelper := ezhandler.JSONResponseWithStatus(data, customStatus) assert.Equal(t, customStatus, respHelper.Status()) headers := respHelper.Headers() assert.Equal(t, "application/json", headers.Get("Content-Type")) body, err := respHelper.Body() assert.NoError(t, err) assert.NotNil(t, body) var decodedData testData err = json.NewDecoder(body).Decode(&decodedData) assert.NoError(t, err) assert.Equal(t, data, decodedData) } func TestJSONResponse_BodyError(t *testing.T) { // This type cannot be marshaled to JSON due to a circular reference type Circular struct { Self *Circular } data := Circular{} data.Self = &data respHelper := ezhandler.JSONResponse(data) body, err := respHelper.Body() assert.Error(t, err) assert.Nil(t, body) } type jsonServeTestCase struct { name string handler ezhandler.ResponseHandler expectedStatus int expectedBody string expectedError error } func TestResponseHandler_ServeHTTP_JSONResponse(t *testing.T) { type testData struct { Message string `json:"message"` } tests := []jsonServeTestCase{ { name: "successful JSON response", handler: ezhandler.ResponseHandler(func(r *http.Request) (ezhandler.ResponseHelper, error) { return ezhandler.JSONResponse(testData{Message: "success"}), nil }), expectedStatus: http.StatusOK, expectedBody: "{\"message\":\"success\"}", expectedError: nil, }, { name: "JSON response with custom status", handler: ezhandler.ResponseHandler(func(r *http.Request) (ezhandler.ResponseHelper, error) { return ezhandler.JSONResponseWithStatus(testData{Message: "created"}, http.StatusCreated), nil }), expectedStatus: http.StatusCreated, expectedBody: "{\"message\":\"created\"}", expectedError: nil, }, { name: "error from ResponseHandler", handler: ezhandler.ResponseHandler(func(r *http.Request) (ezhandler.ResponseHelper, error) { return nil, errTest // Using errTest from helper_test.go }), expectedError: errTest, }, { name: "error from Body() method", handler: ezhandler.ResponseHandler(func(r *http.Request) (ezhandler.ResponseHelper, error) { type Circular struct { Self *Circular } data := Circular{} data.Self = &data return ezhandler.JSONResponse(data), nil }), expectedError: errors.New("json: unsupported value: encountered a cycle"), // The error is returned by ServeHTTP, not the handler func }, } for _, tc := range tests { runResponseHandlerTest(t, tc) } } func runResponseHandlerTest(tt *testing.T, tc jsonServeTestCase) { tt.Run(tc.name, func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", http.NoBody) rec := httptest.NewRecorder() err := tc.handler.ServeHTTP(rec, req) if tc.expectedError != nil { assert.ErrorContains(t, err, tc.expectedError.Error()) } else { assert.NoError(t, err) assert.Equal(t, tc.expectedStatus, rec.Code) assert.Equal(t, tc.expectedBody, rec.Body.String()) if tc.expectedBody != "" { assert.Equal(t, "application/json", rec.Header().Get("Content-Type")) } } }) }