This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
package ginext
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gin.SetMode(gin.TestMode)
|
||||
}
|
||||
|
||||
func newTestCtx() (*gin.Context, *httptest.ResponseRecorder) {
|
||||
rec := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(rec)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
return c, rec
|
||||
}
|
||||
|
||||
func TestJSONResponse_Basics(t *testing.T) {
|
||||
r := JSON(http.StatusOK, map[string]any{"a": 1})
|
||||
if !r.IsSuccess() {
|
||||
t.Fatalf("expected IsSuccess true for 200")
|
||||
}
|
||||
ir, ok := r.(InspectableHTTPResponse)
|
||||
if !ok {
|
||||
t.Fatalf("expected InspectableHTTPResponse")
|
||||
}
|
||||
if ir.Statuscode() != http.StatusOK {
|
||||
t.Fatalf("statuscode mismatch: %d", ir.Statuscode())
|
||||
}
|
||||
if ir.ContentType() != "application/json" {
|
||||
t.Fatalf("expected content-type application/json, got %q", ir.ContentType())
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONResponse_Write(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
r := JSON(http.StatusCreated, map[string]any{"hello": "world"})
|
||||
r.Write(c)
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d", rec.Code)
|
||||
}
|
||||
if !bytes.Contains(rec.Body.Bytes(), []byte("\"hello\":\"world\"")) {
|
||||
t.Fatalf("unexpected body: %s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONResponse_BodyString(t *testing.T) {
|
||||
c, _ := newTestCtx()
|
||||
r := JSON(http.StatusOK, map[string]any{"x": 42})
|
||||
ir := r.(InspectableHTTPResponse)
|
||||
body := ir.BodyString(c)
|
||||
if body == nil {
|
||||
t.Fatalf("expected body, got nil")
|
||||
}
|
||||
if !bytes.Contains([]byte(*body), []byte("\"x\":42")) {
|
||||
t.Fatalf("unexpected body: %q", *body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONResponse_FilterFromContext(t *testing.T) {
|
||||
c, _ := newTestCtx()
|
||||
SetJSONFilter(c, "abc")
|
||||
r := JSON(http.StatusOK, map[string]any{"x": 1})
|
||||
body := r.(InspectableHTTPResponse).BodyString(c)
|
||||
if body == nil {
|
||||
t.Fatalf("expected body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONResponse_FilterOverride(t *testing.T) {
|
||||
c, _ := newTestCtx()
|
||||
SetJSONFilter(c, "abc")
|
||||
r := JSONWithFilter(http.StatusOK, map[string]any{"x": 1}, "override")
|
||||
if r == nil {
|
||||
t.Fatalf("expected response")
|
||||
}
|
||||
if !r.IsSuccess() {
|
||||
t.Fatalf("expected success")
|
||||
}
|
||||
body := r.(InspectableHTTPResponse).BodyString(c)
|
||||
if body == nil {
|
||||
t.Fatalf("expected body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponse_IsSuccessRanges(t *testing.T) {
|
||||
cases := []struct {
|
||||
code int
|
||||
ok bool
|
||||
}{
|
||||
{100, false},
|
||||
{199, false},
|
||||
{200, true},
|
||||
{201, true},
|
||||
{299, true},
|
||||
{300, true},
|
||||
{399, true},
|
||||
{400, false},
|
||||
{500, false},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
r := JSON(tc.code, nil)
|
||||
if r.IsSuccess() != tc.ok {
|
||||
t.Errorf("status %d: expected IsSuccess=%v", tc.code, tc.ok)
|
||||
}
|
||||
r2 := Status(tc.code)
|
||||
if r2.IsSuccess() != tc.ok {
|
||||
t.Errorf("Status(%d): expected IsSuccess=%v", tc.code, tc.ok)
|
||||
}
|
||||
r3 := Text(tc.code, "x")
|
||||
if r3.IsSuccess() != tc.ok {
|
||||
t.Errorf("Text(%d): expected IsSuccess=%v", tc.code, tc.ok)
|
||||
}
|
||||
r4 := Data(tc.code, "text/plain", []byte("x"))
|
||||
if r4.IsSuccess() != tc.ok {
|
||||
t.Errorf("Data(%d): expected IsSuccess=%v", tc.code, tc.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponse_WithHeader(t *testing.T) {
|
||||
r := JSON(http.StatusOK, nil).
|
||||
WithHeader("X-Foo", "bar").
|
||||
WithHeader("X-Baz", "qux")
|
||||
headers := r.(InspectableHTTPResponse).Headers()
|
||||
if len(headers) != 2 {
|
||||
t.Fatalf("expected 2 headers, got %d", len(headers))
|
||||
}
|
||||
if headers[0] != "X-Foo=bar" || headers[1] != "X-Baz=qux" {
|
||||
t.Fatalf("headers wrong: %v", headers)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponse_WithCookie_DoesNotPanic(t *testing.T) {
|
||||
r := JSON(http.StatusOK, nil).
|
||||
WithCookie("session", "abc", 3600, "/", "example.com", true, true)
|
||||
if r == nil {
|
||||
t.Fatalf("expected response")
|
||||
}
|
||||
c, rec := newTestCtx()
|
||||
r.Write(c)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rec.Code)
|
||||
}
|
||||
cookies := rec.Result().Cookies()
|
||||
if len(cookies) != 1 {
|
||||
t.Fatalf("expected 1 cookie, got %d", len(cookies))
|
||||
}
|
||||
if cookies[0].Name != "session" || cookies[0].Value != "abc" {
|
||||
t.Fatalf("cookie wrong: %+v", cookies[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextResponse(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
r := Text(http.StatusOK, "hello")
|
||||
if r.(InspectableHTTPResponse).ContentType() != "text/plain" {
|
||||
t.Fatalf("expected text/plain")
|
||||
}
|
||||
body := r.(InspectableHTTPResponse).BodyString(c)
|
||||
if body == nil || *body != "hello" {
|
||||
t.Fatalf("body mismatch")
|
||||
}
|
||||
r.Write(c)
|
||||
if rec.Body.String() != "hello" {
|
||||
t.Fatalf("write body mismatch: %q", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataResponse(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
payload := []byte{0x01, 0x02, 0x03}
|
||||
r := Data(http.StatusOK, "application/octet-stream", payload)
|
||||
if r.(InspectableHTTPResponse).ContentType() != "application/octet-stream" {
|
||||
t.Fatalf("contenttype mismatch")
|
||||
}
|
||||
r.Write(c)
|
||||
if !bytes.Equal(rec.Body.Bytes(), payload) {
|
||||
t.Fatalf("body mismatch")
|
||||
}
|
||||
body := r.(InspectableHTTPResponse).BodyString(c)
|
||||
if body == nil || *body != string(payload) {
|
||||
t.Fatalf("BodyString mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusResponse(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
r := Status(http.StatusNoContent)
|
||||
if r.(InspectableHTTPResponse).ContentType() != "" {
|
||||
t.Fatalf("expected empty content type")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).BodyString(c) != nil {
|
||||
t.Fatalf("expected nil body")
|
||||
}
|
||||
r.Write(c)
|
||||
if c.Writer.Status() != http.StatusNoContent {
|
||||
t.Fatalf("expected 204, got %d", c.Writer.Status())
|
||||
}
|
||||
_ = rec
|
||||
}
|
||||
|
||||
func TestRedirectResponse(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
r := Redirect(http.StatusFound, "/elsewhere")
|
||||
if r.(InspectableHTTPResponse).Statuscode() != http.StatusFound {
|
||||
t.Fatalf("status mismatch")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).ContentType() != "" {
|
||||
t.Fatalf("expected empty content type")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).BodyString(c) != nil {
|
||||
t.Fatalf("expected nil body")
|
||||
}
|
||||
r.Write(c)
|
||||
if rec.Code != http.StatusFound {
|
||||
t.Fatalf("expected 302, got %d", rec.Code)
|
||||
}
|
||||
if rec.Header().Get("Location") != "/elsewhere" {
|
||||
t.Fatalf("expected Location header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotImplemented(t *testing.T) {
|
||||
r := NotImplemented()
|
||||
if r == nil {
|
||||
t.Fatalf("expected response")
|
||||
}
|
||||
if r.IsSuccess() {
|
||||
t.Fatalf("NotImplemented must not be success")
|
||||
}
|
||||
}
|
||||
|
||||
func TestError_NotSuccess(t *testing.T) {
|
||||
r := Error(http.ErrAbortHandler)
|
||||
if r.IsSuccess() {
|
||||
t.Fatalf("error response must not be success")
|
||||
}
|
||||
herr, ok := r.(HTTPErrorResponse)
|
||||
if !ok {
|
||||
t.Fatalf("expected HTTPErrorResponse")
|
||||
}
|
||||
if herr.Error() == nil {
|
||||
t.Fatalf("expected non-nil err")
|
||||
}
|
||||
}
|
||||
|
||||
func TestError_ContentTypeJSON(t *testing.T) {
|
||||
r := Error(http.ErrAbortHandler)
|
||||
if r.(InspectableHTTPResponse).ContentType() != "application/json" {
|
||||
t.Fatalf("expected application/json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadData(t *testing.T) {
|
||||
c, rec := newTestCtx()
|
||||
payload := []byte("file content")
|
||||
r := DownloadData(http.StatusOK, "text/plain", "f.txt", payload)
|
||||
if r.(InspectableHTTPResponse).ContentType() != "text/plain" {
|
||||
t.Fatalf("contenttype mismatch")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).Statuscode() != http.StatusOK {
|
||||
t.Fatalf("status mismatch")
|
||||
}
|
||||
body := r.(InspectableHTTPResponse).BodyString(c)
|
||||
if body == nil || *body != string(payload) {
|
||||
t.Fatalf("body mismatch")
|
||||
}
|
||||
r.Write(c)
|
||||
if rec.Header().Get("Content-Disposition") == "" {
|
||||
t.Fatalf("expected Content-Disposition header")
|
||||
}
|
||||
if !bytes.Contains([]byte(rec.Header().Get("Content-Disposition")), []byte("f.txt")) {
|
||||
t.Fatalf("Content-Disposition does not contain filename: %q", rec.Header().Get("Content-Disposition"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeekable(t *testing.T) {
|
||||
r := Seekable("foo.bin", "application/octet-stream", bytes.NewReader([]byte("xyz")))
|
||||
if !r.IsSuccess() {
|
||||
t.Fatalf("seekable must be success")
|
||||
}
|
||||
ir := r.(InspectableHTTPResponse)
|
||||
if ir.Statuscode() != 200 {
|
||||
t.Fatalf("expected 200")
|
||||
}
|
||||
if ir.ContentType() != "application/octet-stream" {
|
||||
t.Fatalf("contenttype mismatch")
|
||||
}
|
||||
body := ir.BodyString(nil)
|
||||
if body == nil || *body != "(seekable)" {
|
||||
t.Fatalf("BodyString mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_Builders(t *testing.T) {
|
||||
r := File("text/plain", "/tmp/this-file-should-not-exist-xyz")
|
||||
if !r.IsSuccess() {
|
||||
t.Fatalf("File must IsSuccess true")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).Statuscode() != 200 {
|
||||
t.Fatalf("expected 200")
|
||||
}
|
||||
if r.(InspectableHTTPResponse).ContentType() != "text/plain" {
|
||||
t.Fatalf("contenttype mismatch")
|
||||
}
|
||||
r2 := Download("application/pdf", "/tmp/this-file-should-not-exist-xyz", "doc.pdf")
|
||||
if r2.(InspectableHTTPResponse).ContentType() != "application/pdf" {
|
||||
t.Fatalf("contenttype mismatch")
|
||||
}
|
||||
body := r.(InspectableHTTPResponse).BodyString(nil)
|
||||
if body != nil {
|
||||
t.Fatalf("expected nil body for nonexistent file")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user