Files
responsex/gin/gin_test.go
T

278 lines
5.8 KiB
Go
Raw Permalink Normal View History

2026-07-22 01:17:07 +08:00
package gin_test
import (
"encoding/json"
"errors"
"net/http/httptest"
"testing"
"code.yun.ink/pkg/responsex"
respgin "code.yun.ink/pkg/responsex/gin"
"github.com/gin-gonic/gin"
)
func init() {
gin.SetMode(gin.TestMode)
}
func decodeBody(t *testing.T, w *httptest.ResponseRecorder) map[string]any {
t.Helper()
var body map[string]any
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
t.Fatalf("decode body failed: %v, raw: %s", err, w.Body.String())
}
return body
}
func newGinCtx(w *httptest.ResponseRecorder) *gin.Context {
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("GET", "/", nil)
return c
}
// ---------- Success ----------
func TestSuccess(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Success(c, "hello world")
body := decodeBody(t, w)
if body["code"] != float64(200) {
t.Errorf("code = %v, want 200", body["code"])
}
if body["data"] != "hello world" {
t.Errorf("data = %v, want hello world", body["data"])
}
}
func TestSuccessWithOptions(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Success(c, "created",
responsex.SetHttpStatusCode(201),
responsex.SetHeader("X-Custom", "gin"),
)
if w.Code != 201 {
t.Errorf("http status = %d, want 201", w.Code)
}
if v := w.Header().Get("X-Custom"); v != "gin" {
t.Errorf("X-Custom = %q, want gin", v)
}
}
func TestSuccessNilData(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Success(c, nil)
body := decodeBody(t, w)
if _, ok := body["data"]; ok {
t.Errorf("data should be omitted for nil")
}
}
// ---------- Error ----------
func TestError(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Error(c, errors.New("gin error"))
body := decodeBody(t, w)
if body["code"] != float64(400) {
t.Errorf("code = %v, want 400", body["code"])
}
if body["message"] != "gin error" {
t.Errorf("message = %v, want 'gin error'", body["message"])
}
}
func TestErrorWithHttpStatus(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Error(c, errors.New("server error"),
responsex.SetHttpStatusCode(500),
)
if w.Code != 500 {
t.Errorf("http status = %d, want 500", w.Code)
}
}
func TestErrorWithHeader(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Error(c, errors.New("bad request"),
responsex.SetHttpStatusCode(400),
responsex.SetHeaders(map[string]string{
"X-Error-Code": "GIN_001",
"X-Request-Id": "abc",
}),
)
if v := w.Header().Get("X-Error-Code"); v != "GIN_001" {
t.Errorf("X-Error-Code = %q, want GIN_001", v)
}
if v := w.Header().Get("X-Request-Id"); v != "abc" {
t.Errorf("X-Request-Id = %q, want abc", v)
}
}
// ---------- ErrorWithData ----------
func TestErrorWithData(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.ErrorWithData(c, errors.New("validation error"), map[string]any{
"fields": []string{"email", "name"},
})
body := decodeBody(t, w)
data, ok := body["data"].(map[string]any)
if !ok {
t.Fatalf("data should be map, got %T", body["data"])
}
fields, _ := data["fields"].([]any)
if len(fields) != 2 {
t.Errorf("fields length = %d, want 2", len(fields))
}
}
func TestErrorWithDataAndOptions(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.ErrorWithData(c, errors.New("gone"), "resource",
responsex.SetHttpStatusCode(410),
)
if w.Code != 410 {
t.Errorf("http status = %d, want 410", w.Code)
}
}
// ---------- ErrorStr ----------
func TestErrorStr(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.ErrorStr(c, "string error")
body := decodeBody(t, w)
if body["message"] == "" {
t.Error("message should not be empty")
}
}
func TestErrorStrWithOptions(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.ErrorStr(c, "forbidden",
responsex.SetHttpStatusCode(403),
responsex.SetHeader("X-Reason", "no-access"),
)
if w.Code != 403 {
t.Errorf("http status = %d, want 403", w.Code)
}
}
// ---------- SuccessWithPage ----------
func TestSuccessWithPage(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
page := responsex.Pagination{
Page: 1,
Size: 10,
TotalPage: 3,
TotalCount: 30,
}
respgin.SuccessWithPage(c, []string{"a", "b"}, page)
body := decodeBody(t, w)
p, ok := body["pagination"].(map[string]any)
if !ok {
t.Fatalf("pagination should be map, got %T", body["pagination"])
}
if p["total_count"] != float64(30) {
t.Errorf("total_count = %v, want 30", p["total_count"])
}
}
func TestSuccessWithPageAndOptions(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
page := responsex.Pagination{Page: 1, Size: 20, TotalPage: 1, TotalCount: 20}
respgin.SuccessWithPage(c, []int{1}, page,
responsex.SetHeader("X-Total", "20"),
)
if v := w.Header().Get("X-Total"); v != "20" {
t.Errorf("X-Total = %q, want 20", v)
}
}
// ---------- MsgMapData / MsgKV ----------
func TestMsgKV(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.MsgKV(c, "welcome", "name", "Alice")
// 仅验证 HTTP 200 正常返回,具体内容由 langx 决定
if w.Code != 200 {
t.Errorf("http status = %d, want 200", w.Code)
}
}
func TestMsgKVWithOptions(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.MsgKV(c, "welcome", "name", "Alice",
responsex.SetHeader("X-Lang", "zh"),
)
if v := w.Header().Get("X-Lang"); v != "zh" {
t.Errorf("X-Lang = %q, want zh", v)
}
}
// ---------- Custom ----------
func TestCustom(t *testing.T) {
w := httptest.NewRecorder()
c := newGinCtx(w)
respgin.Custom(c,
responsex.SetCode(100),
responsex.SetMessage("custom gin"),
responsex.SetHttpStatusCode(202),
)
if w.Code != 202 {
t.Errorf("http status = %d, want 202", w.Code)
}
body := decodeBody(t, w)
if body["code"] != float64(100) {
t.Errorf("code = %v, want 100", body["code"])
}
}