From f7f1f07d93f506b45fbd1e6c5ef9c27d7e1b4c3a Mon Sep 17 00:00:00 2001 From: AmirHossein Fallah Date: Wed, 18 Feb 2026 20:29:09 +0330 Subject: [PATCH 1/2] test(render): add comprehensive error handling tests Add error case tests for XML, Data, BSON, and HTML renderers to improve test coverage and ensure proper error handling: - TestRenderXMLError: validates XML marshal error handling for unsupported types - TestRenderDataError: validates Data write error handling - TestRenderBSONError: validates BSON marshal error handling for unsupported types - TestRenderBSONWriteError: validates BSON write error handling - TestRenderHTMLTemplateError: validates HTML template execution error with invalid field access - TestRenderHTMLTemplateExecuteError: validates HTML template execution error with invalid nested field All tests pass and maintain 100% coverage for the render package. --- render/render_test.go | 79 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/render/render_test.go b/render/render_test.go index 7213e48f..019a24f7 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -23,9 +23,6 @@ import ( "google.golang.org/protobuf/proto" ) -// TODO unit tests -// test errors - func TestRenderJSON(t *testing.T) { w := httptest.NewRecorder() data := map[string]any{ @@ -385,6 +382,31 @@ func TestRenderBSON(t *testing.T) { assert.Equal(t, "application/bson", w.Header().Get("Content-Type")) } +func TestRenderBSONError(t *testing.T) { + w := httptest.NewRecorder() + data := make(chan int) + + err := (BSON{data}).Render(w) + require.Error(t, err) +} + +func TestRenderBSONWriteError(t *testing.T) { + type testStruct struct { + Value string + } + data := &testStruct{Value: "test"} + bsonData, err := bson.Marshal(data) + require.NoError(t, err) + + ew := &errorWriter{ + bufString: string(bsonData), + ResponseRecorder: httptest.NewRecorder(), + } + + err = (BSON{data}).Render(ew) + require.Error(t, err) +} + func TestRenderXML(t *testing.T) { w := httptest.NewRecorder() data := xmlmap{ @@ -401,6 +423,15 @@ func TestRenderXML(t *testing.T) { assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) } +func TestRenderXMLError(t *testing.T) { + w := httptest.NewRecorder() + data := make(chan int) + + err := (XML{data}).Render(w) + require.Error(t, err) + assert.Contains(t, err.Error(), "xml: unsupported type: chan int") +} + func TestRenderRedirect(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/test-redirect", nil) require.NoError(t, err) @@ -455,6 +486,22 @@ func TestRenderData(t *testing.T) { assert.Equal(t, "image/png", w.Header().Get("Content-Type")) } +func TestRenderDataError(t *testing.T) { + ew := &errorWriter{ + bufString: "#!PNG some raw data", + ResponseRecorder: httptest.NewRecorder(), + } + data := []byte("#!PNG some raw data") + + err := (Data{ + ContentType: "image/png", + Data: data, + }).Render(ew) + + require.Error(t, err) + assert.Contains(t, err.Error(), "write \"#!PNG some raw data\" error") +} + func TestRenderString(t *testing.T) { w := httptest.NewRecorder() @@ -594,6 +641,32 @@ func TestRenderHTMLDebugPanics(t *testing.T) { assert.Panics(t, func() { htmlRender.Instance("", nil) }) } +func TestRenderHTMLTemplateError(t *testing.T) { + w := httptest.NewRecorder() + templ := template.Must(template.New("t").Parse(`Hello {{if .name}}{{.name.DoesNotExist}}{{end}}`)) + + htmlRender := HTMLProduction{Template: templ} + instance := htmlRender.Instance("t", map[string]any{ + "name": "alexandernyquist", + }) + + err := instance.Render(w) + require.Error(t, err) +} + +func TestRenderHTMLTemplateExecuteError(t *testing.T) { + w := httptest.NewRecorder() + templ := template.Must(template.New("t").Parse(`Hello {{.name.invalid}}`)) + + htmlRender := HTMLProduction{Template: templ} + instance := htmlRender.Instance("t", map[string]any{ + "name": "alexandernyquist", + }) + + err := instance.Render(w) + require.Error(t, err) +} + func TestRenderReader(t *testing.T) { w := httptest.NewRecorder() From 2d2c93076a713d537abb739039fe651ab4820c38 Mon Sep 17 00:00:00 2001 From: AmirHossein Fallah Date: Sun, 22 Feb 2026 14:56:10 +0330 Subject: [PATCH 2/2] test(render): improve robustness of error handling tests based on PR feedback --- render/render_test.go | 79 ++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/render/render_test.go b/render/render_test.go index 019a24f7..71132ffa 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -15,7 +15,6 @@ import ( "strings" "testing" - "github.com/gin-gonic/gin/codec/json" testdata "github.com/gin-gonic/gin/testdata/protoexample" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -137,19 +136,44 @@ func TestRenderJsonpJSON(t *testing.T) { } type errorWriter struct { - bufString string + bufString string + ErrThreshold int // 1-based threshold. If 1, errors on the 1st Write call. + writeCount int *httptest.ResponseRecorder } var _ http.ResponseWriter = (*errorWriter)(nil) +func (w *errorWriter) Header() http.Header { + if w.ResponseRecorder == nil { + w.ResponseRecorder = httptest.NewRecorder() + } + return w.ResponseRecorder.Header() +} + +func (w *errorWriter) WriteHeader(statusCode int) { + if w.ResponseRecorder == nil { + w.ResponseRecorder = httptest.NewRecorder() + } + w.ResponseRecorder.WriteHeader(statusCode) +} + func (w *errorWriter) Write(buf []byte) (int, error) { - if string(buf) == w.bufString { - return 0, errors.New(`write "` + w.bufString + `" error`) + w.writeCount++ + if (w.bufString != "" && string(buf) == w.bufString) || (w.ErrThreshold > 0 && w.writeCount >= w.ErrThreshold) { + return 0, errors.New(`write error`) + } + if w.ResponseRecorder == nil { + w.ResponseRecorder = httptest.NewRecorder() } return w.ResponseRecorder.Write(buf) } +func (w *errorWriter) reset() { + w.writeCount = 0 + w.ResponseRecorder = httptest.NewRecorder() +} + func TestRenderJsonpJSONError(t *testing.T) { ew := &errorWriter{ ResponseRecorder: httptest.NewRecorder(), @@ -162,23 +186,33 @@ func TestRenderJsonpJSONError(t *testing.T) { }, } - cb := template.JSEscapeString(jsonpJSON.Callback) - ew.bufString = cb - err := jsonpJSON.Render(ew) // error was returned while writing callback - assert.Equal(t, `write "`+cb+`" error`, err.Error()) + // error was returned while writing callback + ew.reset() + ew.ErrThreshold = 1 + err := jsonpJSON.Render(ew) + require.Error(t, err) + assert.Equal(t, "write error", err.Error()) - ew.bufString = `(` + // error was returned while writing "(" + ew.reset() + ew.ErrThreshold = 2 err = jsonpJSON.Render(ew) - assert.Equal(t, `write "`+`(`+`" error`, err.Error()) + require.Error(t, err) + assert.Equal(t, "write error", err.Error()) - data, _ := json.API.Marshal(jsonpJSON.Data) // error was returned while writing data - ew.bufString = string(data) + // error was returned while writing data + ew.reset() + ew.ErrThreshold = 3 err = jsonpJSON.Render(ew) - assert.Equal(t, `write "`+string(data)+`" error`, err.Error()) + require.Error(t, err) + assert.Equal(t, "write error", err.Error()) - ew.bufString = `);` + // error was returned while writing ");" + ew.reset() + ew.ErrThreshold = 4 err = jsonpJSON.Render(ew) - assert.Equal(t, `write "`+`);`+`" error`, err.Error()) + require.Error(t, err) + assert.Equal(t, "write error", err.Error()) } func TestRenderJsonpJSONError2(t *testing.T) { @@ -395,16 +429,15 @@ func TestRenderBSONWriteError(t *testing.T) { Value string } data := &testStruct{Value: "test"} - bsonData, err := bson.Marshal(data) - require.NoError(t, err) ew := &errorWriter{ - bufString: string(bsonData), + ErrThreshold: 1, ResponseRecorder: httptest.NewRecorder(), } - err = (BSON{data}).Render(ew) + err := (BSON{data}).Render(ew) require.Error(t, err) + assert.Equal(t, "write error", err.Error()) } func TestRenderXML(t *testing.T) { @@ -488,7 +521,7 @@ func TestRenderData(t *testing.T) { func TestRenderDataError(t *testing.T) { ew := &errorWriter{ - bufString: "#!PNG some raw data", + ErrThreshold: 1, ResponseRecorder: httptest.NewRecorder(), } data := []byte("#!PNG some raw data") @@ -499,7 +532,7 @@ func TestRenderDataError(t *testing.T) { }).Render(ew) require.Error(t, err) - assert.Contains(t, err.Error(), "write \"#!PNG some raw data\" error") + assert.Equal(t, "write error", err.Error()) } func TestRenderString(t *testing.T) { @@ -718,10 +751,10 @@ func TestRenderWriteError(t *testing.T) { prefix := "my-prefix:" r := SecureJSON{Data: data, Prefix: prefix} ew := &errorWriter{ - bufString: prefix, + ErrThreshold: 1, ResponseRecorder: httptest.NewRecorder(), } err := r.Render(ew) require.Error(t, err) - assert.Equal(t, `write "my-prefix:" error`, err.Error()) + assert.Equal(t, "write error", err.Error()) }