goyave.dev/goyave/v4@v4.4.11/response_test.go (about) 1 package goyave 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io" 8 "net" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "strconv" 13 "strings" 14 "testing" 15 16 "gorm.io/gorm" 17 "goyave.dev/goyave/v4/config" 18 "goyave.dev/goyave/v4/database" 19 ) 20 21 type ResponseTestSuite struct { 22 TestSuite 23 } 24 25 func (suite *ResponseTestSuite) getFileSize(path string) string { 26 file, err := os.Open(path) 27 if err != nil { 28 suite.FailNow(err.Error()) 29 } 30 stats, err := file.Stat() 31 if err != nil { 32 suite.FailNow(err.Error()) 33 } 34 return strconv.FormatInt(stats.Size(), 10) 35 } 36 37 func (suite *ResponseTestSuite) TestResponseStatus() { 38 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 39 response := newResponse(httptest.NewRecorder(), rawRequest) 40 response.Status(403) 41 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 42 43 suite.Equal(200, resp.StatusCode) // Not written yet 44 suite.True(response.empty) 45 suite.Equal(403, response.GetStatus()) 46 resp.Body.Close() 47 48 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 49 response = newResponse(httptest.NewRecorder(), rawRequest) 50 response.String(403, "test") 51 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 52 53 suite.Equal(403, resp.StatusCode) 54 suite.False(response.empty) 55 suite.Equal(403, response.GetStatus()) 56 resp.Body.Close() 57 58 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 59 response = newResponse(httptest.NewRecorder(), rawRequest) 60 response.Status(403) 61 response.Status(200) // Should have no effect 62 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 63 64 suite.Equal(200, resp.StatusCode) // Not written yet 65 suite.True(response.empty) 66 suite.Equal(403, response.GetStatus()) 67 resp.Body.Close() 68 } 69 70 func (suite *ResponseTestSuite) TestResponseHeader() { 71 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 72 response := newResponse(httptest.NewRecorder(), rawRequest) 73 response.Header().Set("Content-Type", "application/json") 74 response.Status(200) 75 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 76 77 suite.Equal(200, resp.StatusCode) 78 suite.Equal("application/json", resp.Header.Get("Content-Type")) 79 suite.True(response.empty) 80 suite.Equal(200, response.status) 81 resp.Body.Close() 82 } 83 84 func (suite *ResponseTestSuite) TestResponseError() { 85 config.Set("app.debug", true) 86 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 87 response := newResponse(httptest.NewRecorder(), rawRequest) 88 response.Error(fmt.Errorf("random error")) 89 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 90 91 suite.Equal(500, resp.StatusCode) 92 93 body, err := io.ReadAll(resp.Body) 94 resp.Body.Close() 95 suite.Nil(err) 96 suite.Equal("{\"error\":\"random error\"}\n", string(body)) 97 suite.False(response.empty) 98 suite.Equal(500, response.status) 99 suite.NotNil(response.err) 100 101 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 102 response = newResponse(httptest.NewRecorder(), rawRequest) 103 response.Error("random error") 104 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 105 106 suite.Equal(500, resp.StatusCode) 107 suite.NotNil(response.err) 108 109 body, err = io.ReadAll(resp.Body) 110 resp.Body.Close() 111 suite.Nil(err) 112 suite.Equal("{\"error\":\"random error\"}\n", string(body)) 113 suite.False(response.empty) 114 suite.Equal(500, response.status) 115 suite.NotNil(response.err) 116 117 config.Set("app.debug", false) 118 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 119 response = newResponse(httptest.NewRecorder(), rawRequest) 120 response.Error("random error") 121 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 122 123 suite.Equal(500, response.GetStatus()) 124 125 body, err = io.ReadAll(resp.Body) 126 resp.Body.Close() 127 suite.Nil(err) 128 suite.Empty(string(body)) 129 suite.True(response.empty) 130 suite.Equal("random error", response.GetError()) 131 suite.Equal(500, response.status) 132 config.Set("app.debug", true) 133 134 // Take user-defined status code in debug mode 135 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 136 response = newResponse(httptest.NewRecorder(), rawRequest) 137 response.Status(503) 138 response.Error("random error") 139 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 140 141 suite.Equal(503, response.GetStatus()) 142 143 body, err = io.ReadAll(resp.Body) 144 resp.Body.Close() 145 suite.Nil(err) 146 suite.Equal("{\"error\":\"random error\"}\n", string(body)) 147 suite.False(response.empty) 148 suite.Equal("random error", response.GetError()) 149 suite.Equal(503, response.status) 150 suite.NotNil(response.err) 151 } 152 153 func (suite *ResponseTestSuite) TestIsEmpty() { 154 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 155 response := newResponse(httptest.NewRecorder(), rawRequest) 156 157 suite.True(response.IsEmpty()) 158 159 response.String(http.StatusOK, "test") 160 suite.False(response.IsEmpty()) 161 } 162 163 func (suite *ResponseTestSuite) TestIsHeaderWritten() { 164 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 165 response := newResponse(httptest.NewRecorder(), rawRequest) 166 167 suite.False(response.IsHeaderWritten()) 168 169 response.Status(http.StatusOK) 170 suite.False(response.IsHeaderWritten()) 171 172 response.String(http.StatusOK, "test") 173 suite.True(response.IsHeaderWritten()) 174 } 175 176 func (suite *ResponseTestSuite) TestGetStacktrace() { 177 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 178 response := newResponse(httptest.NewRecorder(), rawRequest) 179 suite.Empty(response.GetStacktrace()) 180 181 response.stacktrace = "fake stacktrace" 182 suite.Equal("fake stacktrace", response.GetStacktrace()) 183 } 184 185 func (suite *ResponseTestSuite) TestResponseFile() { 186 size := suite.getFileSize("config/config.test.json") 187 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 188 response := newResponse(httptest.NewRecorder(), rawRequest) 189 190 response.File("config/config.test.json") 191 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 192 193 suite.Equal(200, resp.StatusCode) 194 suite.Equal("inline", resp.Header.Get("Content-Disposition")) 195 suite.Equal("application/json", resp.Header.Get("Content-Type")) 196 suite.Equal(size, resp.Header.Get("Content-Length")) 197 suite.False(response.empty) 198 suite.Equal(200, response.status) 199 resp.Body.Close() 200 201 // Test no Content-Type override 202 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 203 response = newResponse(httptest.NewRecorder(), rawRequest) 204 response.Header().Set("Content-Type", "text/plain") 205 response.File("config/config.test.json") 206 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 207 suite.Equal("text/plain", resp.Header.Get("Content-Type")) 208 resp.Body.Close() 209 210 // File doesn't exist 211 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 212 response = newResponse(httptest.NewRecorder(), rawRequest) 213 err := response.File("config/doesntexist") 214 suite.Equal("open config/doesntexist: no such file or directory", err.Error()) 215 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 216 suite.Equal(404, response.status) 217 suite.True(response.empty) 218 suite.False(response.wroteHeader) 219 suite.Empty(resp.Header.Get("Content-Type")) 220 suite.Empty(resp.Header.Get("Content-Disposition")) 221 resp.Body.Close() 222 } 223 224 func (suite *ResponseTestSuite) TestResponseJSON() { 225 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 226 response := newResponse(httptest.NewRecorder(), rawRequest) 227 228 response.JSON(http.StatusOK, map[string]interface{}{ 229 "status": "ok", 230 "code": 200, 231 }) 232 233 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 234 suite.Equal(200, resp.StatusCode) 235 suite.Equal("application/json; charset=utf-8", resp.Header.Get("Content-Type")) 236 suite.False(response.empty) 237 238 body, err := io.ReadAll(resp.Body) 239 resp.Body.Close() 240 if err != nil { 241 panic(err) 242 } 243 suite.Equal("{\"code\":200,\"status\":\"ok\"}\n", string(body)) 244 } 245 246 func (suite *ResponseTestSuite) TestResponseDownload() { 247 size := suite.getFileSize("config/config.test.json") 248 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 249 response := newResponse(httptest.NewRecorder(), rawRequest) 250 251 response.Download("config/config.test.json", "config.json") 252 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 253 254 suite.Equal(200, resp.StatusCode) 255 suite.Equal("attachment; filename=\"config.json\"", resp.Header.Get("Content-Disposition")) 256 suite.Equal("application/json", resp.Header.Get("Content-Type")) 257 suite.Equal(size, resp.Header.Get("Content-Length")) 258 suite.False(response.empty) 259 suite.Equal(200, response.status) 260 resp.Body.Close() 261 262 rawRequest = httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 263 response = newResponse(httptest.NewRecorder(), rawRequest) 264 265 err := response.Download("config/doesntexist", "config.json") 266 suite.Equal("open config/doesntexist: no such file or directory", err.Error()) 267 resp = response.responseWriter.(*httptest.ResponseRecorder).Result() 268 suite.Equal(404, response.status) 269 suite.True(response.empty) 270 suite.False(response.wroteHeader) 271 suite.Empty(resp.Header.Get("Content-Type")) 272 suite.Empty(resp.Header.Get("Content-Disposition")) 273 resp.Body.Close() 274 } 275 276 func (suite *ResponseTestSuite) TestResponseRedirect() { 277 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 278 response := newResponse(httptest.NewRecorder(), rawRequest) 279 280 response.Redirect("https://www.google.com") 281 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 282 283 suite.Equal(308, resp.StatusCode) 284 body, err := io.ReadAll(resp.Body) 285 resp.Body.Close() 286 suite.Nil(err) 287 suite.Equal("<a href=\"https://www.google.com\">Permanent Redirect</a>.\n\n", string(body)) 288 suite.False(response.empty) 289 suite.Equal(308, response.status) 290 } 291 292 func (suite *ResponseTestSuite) TestResponseTemporaryRedirect() { 293 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 294 response := newResponse(httptest.NewRecorder(), rawRequest) 295 296 response.TemporaryRedirect("https://www.google.com") 297 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 298 299 suite.Equal(307, resp.StatusCode) 300 body, err := io.ReadAll(resp.Body) 301 resp.Body.Close() 302 suite.Nil(err) 303 suite.Equal("<a href=\"https://www.google.com\">Temporary Redirect</a>.\n\n", string(body)) 304 suite.False(response.empty) 305 suite.Equal(307, response.status) 306 } 307 308 func (suite *ResponseTestSuite) TestResponseCookie() { 309 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 310 response := newResponse(httptest.NewRecorder(), rawRequest) 311 response.Cookie(&http.Cookie{ 312 Name: "cookie-name", 313 Value: "test", 314 }) 315 316 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 317 cookies := resp.Cookies() 318 suite.Equal(1, len(cookies)) 319 suite.Equal("cookie-name", cookies[0].Name) 320 suite.Equal("test", cookies[0].Value) 321 resp.Body.Close() 322 } 323 324 func (suite *ResponseTestSuite) TestResponseWrite() { 325 rawRequest := httptest.NewRequest("GET", "/test-route", strings.NewReader("body")) 326 response := newResponse(httptest.NewRecorder(), rawRequest) 327 response.Write([]byte("byte array")) 328 resp := response.responseWriter.(*httptest.ResponseRecorder).Result() 329 body, err := io.ReadAll(resp.Body) 330 resp.Body.Close() 331 suite.Nil(err) 332 suite.Equal("byte array", string(body)) 333 suite.False(response.empty) 334 } 335 336 func (suite *ResponseTestSuite) TestCreateTestResponse() { 337 recorder := httptest.NewRecorder() 338 response := suite.CreateTestResponse(recorder) 339 suite.NotNil(response) 340 if response != nil { 341 suite.Equal(recorder, response.responseWriter) 342 } 343 } 344 345 func (suite *ResponseTestSuite) TestRender() { 346 // With map data 347 recorder := httptest.NewRecorder() 348 response := suite.CreateTestResponse(recorder) 349 350 mapData := map[string]interface{}{ 351 "Status": http.StatusNotFound, 352 "Message": "Not Found.", 353 } 354 suite.Nil(response.Render(http.StatusNotFound, "error.txt", mapData)) 355 resp := recorder.Result() 356 suite.Equal(404, resp.StatusCode) 357 body, err := io.ReadAll(resp.Body) 358 resp.Body.Close() 359 suite.Nil(err) 360 suite.Equal("Error 404: Not Found.", string(body)) 361 362 // With struct data 363 recorder = httptest.NewRecorder() 364 response = suite.CreateTestResponse(recorder) 365 366 structData := struct { 367 Message string 368 Status int 369 }{ 370 Status: http.StatusNotFound, 371 Message: "Not Found.", 372 } 373 suite.Nil(response.Render(http.StatusNotFound, "error.txt", structData)) 374 resp = recorder.Result() 375 suite.Equal(404, resp.StatusCode) 376 body, err = io.ReadAll(resp.Body) 377 resp.Body.Close() 378 suite.Nil(err) 379 suite.Equal("Error 404: Not Found.", string(body)) 380 resp.Body.Close() 381 382 // Non-existing template and exec error 383 recorder = httptest.NewRecorder() 384 response = suite.CreateTestResponse(recorder) 385 386 suite.NotNil(response.Render(http.StatusNotFound, "non-existing-template", nil)) 387 388 suite.NotNil(response.Render(http.StatusNotFound, "invalid.txt", nil)) 389 resp = recorder.Result() 390 suite.Equal(0, response.status) 391 suite.Equal(200, resp.StatusCode) // Status not written in case of error 392 resp.Body.Close() 393 } 394 395 func (suite *ResponseTestSuite) TestRenderHTML() { 396 // With map data 397 recorder := httptest.NewRecorder() 398 response := suite.CreateTestResponse(recorder) 399 400 mapData := map[string]interface{}{ 401 "Status": http.StatusNotFound, 402 "Message": "Not Found.", 403 } 404 suite.Nil(response.RenderHTML(http.StatusNotFound, "error.html", mapData)) 405 resp := recorder.Result() 406 suite.Equal(404, resp.StatusCode) 407 body, err := io.ReadAll(resp.Body) 408 resp.Body.Close() 409 suite.Nil(err) 410 suite.Equal("<html>\n <head></head>\n <body>\n <p>Error 404: Not Found.</p>\n </body>\n</html>", string(body)) 411 412 // With struct data 413 recorder = httptest.NewRecorder() 414 response = suite.CreateTestResponse(recorder) 415 416 structData := struct { 417 Message string 418 Status int 419 }{ 420 Status: http.StatusNotFound, 421 Message: "Not Found.", 422 } 423 suite.Nil(response.RenderHTML(http.StatusNotFound, "error.html", structData)) 424 resp = recorder.Result() 425 suite.Equal(404, resp.StatusCode) 426 body, err = io.ReadAll(resp.Body) 427 resp.Body.Close() 428 suite.Nil(err) 429 suite.Equal("<html>\n <head></head>\n <body>\n <p>Error 404: Not Found.</p>\n </body>\n</html>", string(body)) 430 431 // Non-existing template and exec error 432 recorder = httptest.NewRecorder() 433 response = suite.CreateTestResponse(recorder) 434 435 suite.NotNil(response.RenderHTML(http.StatusNotFound, "non-existing-template", nil)) 436 437 suite.NotNil(response.RenderHTML(http.StatusNotFound, "invalid.txt", nil)) 438 resp = recorder.Result() 439 suite.Equal(0, response.status) 440 suite.Equal(200, resp.StatusCode) // Status not written in case of error 441 resp.Body.Close() 442 } 443 444 func (suite *ResponseTestSuite) TestHandleDatabaseError() { 445 type TestRecord struct { 446 gorm.Model 447 } 448 config.Set("database.connection", "mysql") 449 defer config.Set("database.connection", "none") 450 db := database.GetConnection() 451 452 response := newResponse(httptest.NewRecorder(), nil) 453 suite.False(response.HandleDatabaseError(db.Find(&TestRecord{}))) 454 455 suite.Equal(http.StatusInternalServerError, response.status) 456 457 db.AutoMigrate(&TestRecord{}) 458 defer db.Migrator().DropTable(&TestRecord{}) 459 response = newResponse(httptest.NewRecorder(), nil) 460 461 suite.False(response.HandleDatabaseError(db.First(&TestRecord{}, -1))) 462 463 suite.Equal(http.StatusNotFound, response.status) 464 465 response = newResponse(httptest.NewRecorder(), nil) 466 suite.True(response.HandleDatabaseError(db.Exec("SHOW TABLES;"))) 467 468 suite.Equal(0, response.status) 469 470 response = newResponse(httptest.NewRecorder(), nil) 471 results := []TestRecord{} 472 suite.True(response.HandleDatabaseError(db.Find(&results))) // Get all but empty result should not be an error 473 suite.Equal(0, response.status) 474 } 475 476 func (suite *ResponseTestSuite) TestHead() { 477 suite.RunServer(func(router *Router) { 478 router.Route("GET|HEAD", "/test", func(response *Response, r *Request) { 479 response.String(http.StatusOK, "hello world") 480 }) 481 }, func() { 482 resp, err := suite.Request("HEAD", "/test", nil, nil) 483 if err != nil { 484 suite.Fail(err.Error()) 485 } 486 defer resp.Body.Close() 487 488 body := suite.GetBody(resp) 489 suite.Equal(http.StatusOK, resp.StatusCode) 490 suite.Equal("text/plain; charset=utf-8", resp.Header.Get("Content-Type")) 491 suite.Empty(body) 492 }) 493 494 suite.RunServer(func(router *Router) { 495 router.Route("GET", "/test", func(response *Response, r *Request) { 496 response.String(http.StatusOK, "hello world") 497 }) 498 }, func() { 499 resp, err := suite.Request("HEAD", "/test", nil, nil) 500 if err != nil { 501 suite.Fail(err.Error()) 502 } 503 defer resp.Body.Close() 504 505 body := suite.GetBody(resp) 506 suite.Equal(http.StatusOK, resp.StatusCode) 507 suite.Equal("text/plain; charset=utf-8", resp.Header.Get("Content-Type")) 508 suite.Empty(body) 509 }) 510 511 suite.RunServer(func(router *Router) { 512 router.Route("POST", "/test", func(response *Response, r *Request) { 513 response.String(http.StatusOK, "hello world") 514 }) 515 }, func() { 516 resp, err := suite.Request("HEAD", "/test", nil, nil) 517 if err != nil { 518 suite.Fail(err.Error()) 519 } 520 defer resp.Body.Close() 521 522 body := suite.GetBody(resp) 523 suite.Equal(http.StatusMethodNotAllowed, resp.StatusCode) 524 suite.Equal("application/json; charset=utf-8", resp.Header.Get("Content-Type")) 525 suite.Empty(body) 526 }) 527 528 suite.RunServer(func(router *Router) { 529 router.Route("HEAD", "/test", func(response *Response, r *Request) { 530 response.Header().Set("Content-Type", "text/plain; charset=utf-8") 531 response.Status(http.StatusOK) 532 }) 533 router.Route("GET", "/test", func(response *Response, r *Request) { 534 response.String(http.StatusOK, "hello world") 535 }) 536 }, func() { 537 resp, err := suite.Request("HEAD", "/test", nil, nil) 538 if err != nil { 539 suite.Fail(err.Error()) 540 } 541 defer resp.Body.Close() 542 543 body := suite.GetBody(resp) 544 suite.Equal(http.StatusOK, resp.StatusCode) 545 suite.Equal("text/plain; charset=utf-8", resp.Header.Get("Content-Type")) 546 suite.Empty(body) 547 }) 548 } 549 550 type hijackableRecorder struct { 551 *httptest.ResponseRecorder 552 } 553 554 func (r *hijackableRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { 555 conn := &net.TCPConn{} 556 return conn, bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)), nil 557 } 558 559 func (suite *ResponseTestSuite) TestHijack() { 560 recorder := &hijackableRecorder{httptest.NewRecorder()} 561 req := httptest.NewRequest(http.MethodGet, "/hijack", nil) 562 resp := newResponse(recorder, req) 563 564 suite.False(resp.hijacked) 565 suite.False(resp.Hijacked()) 566 567 c, b, err := resp.Hijack() 568 if err != nil { 569 suite.Fail(err.Error()) 570 } 571 defer c.Close() 572 573 suite.Nil(err) 574 suite.NotNil(c) 575 suite.NotNil(b) 576 suite.True(resp.hijacked) 577 suite.True(resp.Hijacked()) 578 579 } 580 581 func (suite *ResponseTestSuite) TestErrorOnHijacked() { 582 recorder := &hijackableRecorder{httptest.NewRecorder()} 583 req := httptest.NewRequest(http.MethodGet, "/hijack", nil) 584 resp := newResponse(recorder, req) 585 586 c, _, _ := resp.Hijack() 587 defer c.Close() 588 589 suite.Nil(resp.error("test error")) 590 res := recorder.Result() 591 defer res.Body.Close() 592 suite.Equal(http.StatusInternalServerError, resp.status) 593 594 body, err := io.ReadAll(res.Body) 595 suite.Nil(err) 596 suite.Empty(body) 597 } 598 599 func (suite *ResponseTestSuite) TestHijackNotHijackable() { 600 recorder := httptest.NewRecorder() 601 602 req := httptest.NewRequest(http.MethodGet, "/hijack", nil) 603 resp := newResponse(recorder, req) 604 605 c, b, err := resp.Hijack() 606 suite.Nil(c) 607 suite.Nil(b) 608 suite.NotNil(err) 609 suite.True(errors.Is(err, ErrNotHijackable)) 610 } 611 612 // ------------------------ 613 614 type testWriter struct { 615 io.Writer 616 result *string 617 id string 618 closed bool 619 } 620 621 func (w *testWriter) Write(b []byte) (int, error) { 622 *w.result += w.id + string(b) 623 return w.Writer.Write(b) 624 } 625 626 func (w *testWriter) Close() error { 627 w.closed = true 628 return fmt.Errorf("Test close error") 629 } 630 631 func (suite *ResponseTestSuite) TestChainedWriter() { 632 writer := httptest.NewRecorder() 633 response := newResponse(writer, nil) 634 result := "" 635 testWr := &testWriter{response.Writer(), &result, "0", false} 636 response.SetWriter(testWr) 637 638 response.String(http.StatusOK, "hello world") 639 640 suite.Equal("0hello world", result) 641 suite.Equal(200, response.status) 642 suite.True(response.wroteHeader) 643 suite.False(response.empty) 644 645 suite.Equal("Test close error", response.close().Error()) 646 suite.True(testWr.closed) 647 648 resp := writer.Result() 649 body, _ := io.ReadAll(resp.Body) 650 resp.Body.Close() 651 suite.Equal("hello world", string(body)) 652 653 // Test double chained writer 654 writer = httptest.NewRecorder() 655 response = newResponse(writer, nil) 656 result = "" 657 testWr = &testWriter{response.Writer(), &result, "0", false} 658 testWr2 := &testWriter{testWr, &result, "1", false} 659 response.SetWriter(testWr2) 660 661 response.String(http.StatusOK, "hello world") 662 suite.Equal("1hello world0hello world", result) 663 suite.Equal(200, response.status) 664 suite.True(response.wroteHeader) 665 suite.False(response.empty) 666 resp = writer.Result() 667 body, _ = io.ReadAll(resp.Body) 668 resp.Body.Close() 669 suite.Equal("hello world", string(body)) 670 } 671 672 func TestResponseTestSuite(t *testing.T) { 673 RunTest(t, new(ResponseTestSuite)) 674 }