278 lines
5.8 KiB
Go
278 lines
5.8 KiB
Go
package ginx_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"code.yun.ink/pkg/responsex"
|
|
respgin "code.yun.ink/pkg/responsex/ginx"
|
|
"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"])
|
|
}
|
|
}
|