fix(10.1): WR-04 judge action fill values by their JSON encoding
isJSONScalar now encodes each value and keeps it only when the encoding is a string, number, boolean or null, so a named scalar whose MarshalJSON writes an array or object, NaN and the infinities are dropped. writeJSON encodes into a buffer before the status line, so an encode failure is a logged 500 with the generic envelope instead of a 200 with a truncated body.
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -552,3 +553,55 @@ func TestCRUDFillTypeIsValidation(t *testing.T) {
|
||||
t.Fatalf("year after rejected update = %v, want 1977", after.Year)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWriteJSONEncodeFailure covers WR-04: a body that cannot be encoded is
|
||||
// a 500 with the generic error envelope, not a 200 with a truncated body.
|
||||
func TestWriteJSONEncodeFailure(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
WriteData(rec, http.StatusOK, map[string]any{"price": math.Inf(1)}, nil)
|
||||
if rec.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("status=%d body=%q, want 500", rec.Code, rec.Body.String())
|
||||
}
|
||||
var body struct {
|
||||
Error struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Details map[string]any `json:"details"`
|
||||
} `json:"error"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("body %q: %v", rec.Body.String(), err)
|
||||
}
|
||||
if body.Error.Code != "error" || body.Error.Message != msgServerError || body.Error.Details == nil {
|
||||
t.Fatalf("envelope=%s", rec.Body.String())
|
||||
}
|
||||
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
|
||||
t.Fatalf("content type %q", ct)
|
||||
}
|
||||
|
||||
ok := httptest.NewRecorder()
|
||||
WriteData(ok, http.StatusCreated, map[string]any{"n": 1}, nil)
|
||||
if ok.Code != http.StatusCreated || ok.Body.String() != "{\"data\":{\"n\":1},\"meta\":{}}\n" {
|
||||
t.Fatalf("status=%d body=%q", ok.Code, ok.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsJSONScalar covers WR-04: scalar-ness is decided by the encoding.
|
||||
func TestIsJSONScalar(t *testing.T) {
|
||||
name := "x"
|
||||
var nilPtr *string
|
||||
for _, v := range []any{nil, "s", true, 1, uint8(2), 1.5, json.Number("3"), &name, nilPtr} {
|
||||
if !isJSONScalar(v) {
|
||||
t.Fatalf("%#v refused", v)
|
||||
}
|
||||
}
|
||||
for _, v := range []any{math.NaN(), math.Inf(-1), []string{"a"}, map[string]any{}, struct{}{}, scalarAsArray("a"), func() {}} {
|
||||
if isJSONScalar(v) {
|
||||
t.Fatalf("%#v accepted", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type scalarAsArray string
|
||||
|
||||
func (s scalarAsArray) MarshalJSON() ([]byte, error) { return json.Marshal([]string{string(s)}) }
|
||||
|
||||
Reference in New Issue
Block a user