2024-06-30 17:42:27 +08:00
|
|
|
package responsex_test
|
|
|
|
|
|
|
|
|
|
import (
|
2026-07-22 01:17:07 +08:00
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"net/http/httptest"
|
2024-06-30 17:42:27 +08:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"code.yun.ink/pkg/responsex"
|
|
|
|
|
)
|
|
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
// decodeBody 解码响应体为 map,失败则 Fatal
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Success ----------
|
|
|
|
|
|
|
|
|
|
func TestSuccess(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, "hello")
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(200) {
|
|
|
|
|
t.Errorf("code = %v, want 200", body["code"])
|
|
|
|
|
}
|
|
|
|
|
if body["message"] != "请求成功" {
|
|
|
|
|
t.Errorf("message = %v, want 请求成功", body["message"])
|
|
|
|
|
}
|
|
|
|
|
if body["data"] != "hello" {
|
|
|
|
|
t.Errorf("data = %v, want hello", body["data"])
|
|
|
|
|
}
|
|
|
|
|
if w.Code != 200 {
|
|
|
|
|
t.Errorf("http status = %d, want 200", w.Code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessNilData(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, nil)
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if _, ok := body["data"]; ok {
|
|
|
|
|
t.Errorf("data should be omitted for nil, got %v", body["data"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessWithHttpStatusCode(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, "created",
|
|
|
|
|
responsex.SetHttpStatusCode(201),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(200) {
|
|
|
|
|
t.Errorf("code = %v, want 200", body["code"])
|
|
|
|
|
}
|
|
|
|
|
if w.Code != 201 {
|
|
|
|
|
t.Errorf("http status = %d, want 201", w.Code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessWithHeader(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, "ok",
|
|
|
|
|
responsex.SetHeader("X-Request-Id", "req-123"),
|
|
|
|
|
responsex.SetHeader("X-Custom", "custom-val"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if v := w.Header().Get("X-Request-Id"); v != "req-123" {
|
|
|
|
|
t.Errorf("X-Request-Id = %q, want req-123", v)
|
|
|
|
|
}
|
|
|
|
|
if v := w.Header().Get("X-Custom"); v != "custom-val" {
|
|
|
|
|
t.Errorf("X-Custom = %q, want custom-val", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessWithHeaders(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, "ok",
|
|
|
|
|
responsex.SetHeaders(map[string]string{
|
|
|
|
|
"X-One": "1",
|
|
|
|
|
"X-Two": "2",
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if v := w.Header().Get("X-One"); v != "1" {
|
|
|
|
|
t.Errorf("X-One = %q, want 1", v)
|
|
|
|
|
}
|
|
|
|
|
if v := w.Header().Get("X-Two"); v != "2" {
|
|
|
|
|
t.Errorf("X-Two = %q, want 2", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessMultipleSetHeader(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Success(ctx, w, "ok",
|
|
|
|
|
responsex.SetHeader("X-A", "a1"),
|
|
|
|
|
responsex.SetHeader("X-A", "a2"), // 同 key 多次 SetHeader 覆盖
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if v := w.Header().Get("X-A"); v != "a2" {
|
|
|
|
|
t.Errorf("X-A = %q, want a2", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Error ----------
|
|
|
|
|
|
|
|
|
|
func TestError(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Error(ctx, w, errors.New("something went wrong"))
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(400) {
|
|
|
|
|
t.Errorf("code = %v, want 400", body["code"])
|
|
|
|
|
}
|
|
|
|
|
if body["message"] != "something went wrong" {
|
|
|
|
|
t.Errorf("message = %v, want 'something went wrong'", body["message"])
|
|
|
|
|
}
|
|
|
|
|
if w.Code != 200 {
|
|
|
|
|
t.Errorf("http status = %d, want 200 (default)", w.Code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestErrorWithHttpStatusCode(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Error(ctx, w, errors.New("internal 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()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Error(ctx, w, errors.New("bad request"),
|
|
|
|
|
responsex.SetHttpStatusCode(400),
|
|
|
|
|
responsex.SetHeader("X-Error-Code", "VALIDATION_001"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if w.Code != 400 {
|
|
|
|
|
t.Errorf("http status = %d, want 400", w.Code)
|
|
|
|
|
}
|
|
|
|
|
if v := w.Header().Get("X-Error-Code"); v != "VALIDATION_001" {
|
|
|
|
|
t.Errorf("X-Error-Code = %q, want VALIDATION_001", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestErrorWithData(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.ErrorWithData(ctx, w, errors.New("validation failed"), map[string]any{
|
|
|
|
|
"field": "email",
|
|
|
|
|
"msg": "invalid format",
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(400) {
|
|
|
|
|
t.Errorf("code = %v, want 400", body["code"])
|
|
|
|
|
}
|
|
|
|
|
data, ok := body["data"].(map[string]any)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("data should be a map, got %T", body["data"])
|
|
|
|
|
}
|
|
|
|
|
if data["field"] != "email" {
|
|
|
|
|
t.Errorf("data.field = %v, want email", data["field"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestErrorWithDataAndOptions(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.ErrorWithData(ctx, w, errors.New("gone"), "resource deleted",
|
|
|
|
|
responsex.SetHttpStatusCode(410),
|
|
|
|
|
responsex.SetHeader("X-Deleted-At", "2024-01-01"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if w.Code != 410 {
|
|
|
|
|
t.Errorf("http status = %d, want 410", w.Code)
|
|
|
|
|
}
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["data"] != "resource deleted" {
|
|
|
|
|
t.Errorf("data = %v, want 'resource deleted'", body["data"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestErrorNilError(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Error(ctx, w, nil)
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(400) {
|
|
|
|
|
t.Errorf("code = %v, want 400", body["code"])
|
|
|
|
|
}
|
|
|
|
|
if body["message"] != "请求失败" {
|
|
|
|
|
t.Errorf("message = %v, want 请求失败", body["message"])
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
// ---------- ErrorStr ----------
|
|
|
|
|
|
|
|
|
|
func TestErrorStr(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.ErrorStr(ctx, w, "unauthorized")
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["message"] == "" {
|
|
|
|
|
t.Error("message should not be empty")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestErrorStrWithOptions(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.ErrorStr(ctx, w, "forbidden",
|
|
|
|
|
responsex.SetHttpStatusCode(403),
|
|
|
|
|
responsex.SetHeader("X-Reason", "no permission"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if w.Code != 403 {
|
|
|
|
|
t.Errorf("http status = %d, want 403", w.Code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- SuccessWithPage ----------
|
|
|
|
|
|
|
|
|
|
func TestSuccessWithPage(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
page := &responsex.Pagination{
|
|
|
|
|
Page: 2,
|
|
|
|
|
Size: 10,
|
|
|
|
|
TotalPage: 5,
|
|
|
|
|
TotalCount: 50,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
responsex.SuccessWithPage(ctx, w, []string{"a", "b"}, page)
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
pagination, ok := body["pagination"].(map[string]any)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("pagination should be a map, got %T", body["pagination"])
|
|
|
|
|
}
|
|
|
|
|
if pagination["page"] != float64(2) {
|
|
|
|
|
t.Errorf("page = %v, want 2", pagination["page"])
|
|
|
|
|
}
|
|
|
|
|
if pagination["total_count"] != float64(50) {
|
|
|
|
|
t.Errorf("total_count = %v, want 50", pagination["total_count"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuccessWithPageAndOptions(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
page := &responsex.Pagination{Page: 1, Size: 20, TotalPage: 3, TotalCount: 50}
|
|
|
|
|
|
|
|
|
|
responsex.SuccessWithPage(ctx, w, []int{1, 2}, page,
|
|
|
|
|
responsex.SetHeader("X-Total-Count", "50"),
|
|
|
|
|
responsex.SetHeader("X-Page", "1"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if v := w.Header().Get("X-Total-Count"); v != "50" {
|
|
|
|
|
t.Errorf("X-Total-Count = %q, want 50", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- ResponseCtx ----------
|
|
|
|
|
|
|
|
|
|
func TestResponseCtx_Custom(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.ResponseCtx(ctx, w,
|
|
|
|
|
responsex.SetCode(0),
|
|
|
|
|
responsex.SetMessage("custom msg"),
|
|
|
|
|
responsex.SetHttpStatusCode(418),
|
|
|
|
|
responsex.SetHeaders(map[string]string{"X-Teapot": "true"}),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if w.Code != 418 {
|
|
|
|
|
t.Errorf("http status = %d, want 418", w.Code)
|
|
|
|
|
}
|
|
|
|
|
if v := w.Header().Get("X-Teapot"); v != "true" {
|
|
|
|
|
t.Errorf("X-Teapot = %q, want true", v)
|
|
|
|
|
}
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(0) {
|
|
|
|
|
t.Errorf("code = %v, want 0", body["code"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestResponseCtx_HttpStatusDefault(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
// 不设置 SetHttpStatusCode,默认应为 200
|
|
|
|
|
responsex.ResponseCtx(ctx, w,
|
|
|
|
|
responsex.SetCode(500),
|
|
|
|
|
responsex.SetMessage("error"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if w.Code != 200 {
|
|
|
|
|
t.Errorf("http status = %d, want 200 (default)", w.Code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- FormatMessage ----------
|
|
|
|
|
|
|
|
|
|
func TestFormatMessage(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.FormatMessage(ctx, w, "test_key", map[string]string{
|
|
|
|
|
"name": "world",
|
|
|
|
|
}, "some_data")
|
|
|
|
|
|
|
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
// FormatMessage 内部调用 langx,此处仅验证结构完整性和 HTTP 200
|
|
|
|
|
if w.Code != 200 {
|
|
|
|
|
t.Errorf("http status = %d, want 200", w.Code)
|
|
|
|
|
}
|
|
|
|
|
_ = body
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFormatMessageWithOptions(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.FormatMessage(ctx, w, "key", map[string]string{"k": "v"}, nil,
|
|
|
|
|
responsex.SetHeader("X-Lang", "zh-CN"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if v := w.Header().Get("X-Lang"); v != "zh-CN" {
|
|
|
|
|
t.Errorf("X-Lang = %q, want zh-CN", v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- GetOffset ----------
|
|
|
|
|
|
|
|
|
|
func TestGetOffset(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
page, size int
|
|
|
|
|
wantOffset int
|
|
|
|
|
wantLimit int
|
|
|
|
|
}{
|
|
|
|
|
{"page 1 size 10", 1, 10, 0, 10},
|
|
|
|
|
{"page 2 size 10", 2, 10, 10, 10},
|
|
|
|
|
{"page 3 size 20", 3, 20, 40, 20},
|
|
|
|
|
{"page 0 defaults to 1", 0, 10, 0, 10},
|
|
|
|
|
{"size 0 defaults to 10", 1, 0, 0, 10},
|
|
|
|
|
{"negative page defaults to 1", -1, 10, 0, 10},
|
|
|
|
|
{"both zero", 0, 0, 0, 10},
|
|
|
|
|
{"page 5 size 100", 5, 100, 400, 100},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
offset, limit := responsex.GetOffset(tt.page, tt.size)
|
|
|
|
|
if offset != tt.wantOffset || limit != tt.wantLimit {
|
|
|
|
|
t.Errorf("GetOffset(%d,%d) = (%d,%d), want (%d,%d)",
|
|
|
|
|
tt.page, tt.size, offset, limit, tt.wantOffset, tt.wantLimit)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- GetPage ----------
|
|
|
|
|
|
|
|
|
|
func TestGetPage(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
page, size, total int64
|
|
|
|
|
wantPage, wantSize int64
|
|
|
|
|
wantTotalPage int64
|
|
|
|
|
wantTotalCount int64
|
|
|
|
|
}{
|
|
|
|
|
{"normal", 1, 10, 100, 1, 10, 10, 100},
|
|
|
|
|
{"partial last page", 3, 10, 25, 3, 10, 3, 25},
|
|
|
|
|
{"size zero", 1, 0, 100, 1, 0, 0, 100},
|
|
|
|
|
{"total zero", 1, 10, 0, 1, 10, 0, 0},
|
|
|
|
|
{"exact division", 1, 25, 100, 1, 25, 4, 100},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
p := responsex.GetPage(tt.page, tt.size, tt.total)
|
|
|
|
|
if p.Page != tt.wantPage {
|
|
|
|
|
t.Errorf("Page = %d, want %d", p.Page, tt.wantPage)
|
|
|
|
|
}
|
|
|
|
|
if p.Size != tt.wantSize {
|
|
|
|
|
t.Errorf("Size = %d, want %d", p.Size, tt.wantSize)
|
|
|
|
|
}
|
|
|
|
|
if p.TotalPage != tt.wantTotalPage {
|
|
|
|
|
t.Errorf("TotalPage = %d, want %d", p.TotalPage, tt.wantTotalPage)
|
|
|
|
|
}
|
|
|
|
|
if p.TotalCount != tt.wantTotalCount {
|
|
|
|
|
t.Errorf("TotalCount = %d, want %d", p.TotalCount, tt.wantTotalCount)
|
|
|
|
|
}
|
2024-06-30 17:42:27 +08:00
|
|
|
})
|
2026-07-22 01:17:07 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- SetCode ----------
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
func TestSetCodeOption(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
responsex.ResponseCtx(ctx, w,
|
|
|
|
|
responsex.SetCode(1001),
|
|
|
|
|
responsex.SetMessage("custom code"),
|
|
|
|
|
)
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
body := decodeBody(t, w)
|
|
|
|
|
if body["code"] != float64(1001) {
|
|
|
|
|
t.Errorf("code = %v, want 1001", body["code"])
|
2024-06-30 17:42:27 +08:00
|
|
|
}
|
2026-07-22 01:17:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Content-Type ----------
|
|
|
|
|
|
|
|
|
|
func TestContentTypeHeader(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
responsex.Success(ctx, w, "ok")
|
|
|
|
|
|
|
|
|
|
ct := w.Header().Get("Content-Type")
|
|
|
|
|
if ct != "application/json; charset=utf-8" {
|
|
|
|
|
t.Errorf("Content-Type = %q, want application/json; charset=utf-8", ct)
|
2024-06-30 17:42:27 +08:00
|
|
|
}
|
2026-07-22 01:17:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- JSON Structure ----------
|
|
|
|
|
|
|
|
|
|
func TestErrorResponseJsonStructure(t *testing.T) {
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
responsex.Error(ctx, w, errors.New("not found"))
|
2024-06-30 17:42:27 +08:00
|
|
|
|
2026-07-22 01:17:07 +08:00
|
|
|
var resp struct {
|
|
|
|
|
Code int `json:"code"`
|
|
|
|
|
Message string `json:"message"`
|
|
|
|
|
}
|
|
|
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
|
|
|
t.Fatalf("json unmarshal failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if resp.Code != 400 {
|
|
|
|
|
t.Errorf("Code = %d, want 400", resp.Code)
|
|
|
|
|
}
|
|
|
|
|
if resp.Message != "not found" {
|
|
|
|
|
t.Errorf("Message = %q, want 'not found'", resp.Message)
|
|
|
|
|
}
|
2024-06-30 17:42:27 +08:00
|
|
|
}
|