Compare commits
2 Commits
98486842ae
...
0f52b860ea
Author | SHA1 | Date | |
---|---|---|---|
0f52b860ea | |||
b5cd116219 |
@ -156,7 +156,6 @@ import (
|
|||||||
// an error.
|
// an error.
|
||||||
func Marshal(v any) ([]byte, error) {
|
func Marshal(v any) ([]byte, error) {
|
||||||
e := newEncodeState()
|
e := newEncodeState()
|
||||||
defer encodeStatePool.Put(e)
|
|
||||||
|
|
||||||
err := e.marshal(v, encOpts{escapeHTML: true})
|
err := e.marshal(v, encOpts{escapeHTML: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -164,6 +163,8 @@ func Marshal(v any) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
buf := append([]byte(nil), e.Bytes()...)
|
buf := append([]byte(nil), e.Bytes()...)
|
||||||
|
|
||||||
|
encodeStatePool.Put(e)
|
||||||
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +175,9 @@ type IndentOpt struct {
|
|||||||
|
|
||||||
// MarshalSafeCollections is like Marshal except it will marshal nil maps and
|
// MarshalSafeCollections is like Marshal except it will marshal nil maps and
|
||||||
// slices as '{}' and '[]' respectfully instead of 'null'
|
// slices as '{}' and '[]' respectfully instead of 'null'
|
||||||
func MarshalSafeCollections(v interface{}, nilSafeSlices bool, nilSafeMaps bool, indent *IndentOpt) ([]byte, error) {
|
func MarshalSafeCollections(v interface{}, nilSafeSlices bool, nilSafeMaps bool, indent *IndentOpt, filter *string) ([]byte, error) {
|
||||||
e := &encodeState{}
|
e := &encodeState{}
|
||||||
err := e.marshal(v, encOpts{escapeHTML: true, nilSafeSlices: nilSafeSlices, nilSafeMaps: nilSafeMaps})
|
err := e.marshal(v, encOpts{escapeHTML: true, nilSafeSlices: nilSafeSlices, nilSafeMaps: nilSafeMaps, filter: filter})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -393,6 +394,9 @@ type encOpts struct {
|
|||||||
nilSafeSlices bool
|
nilSafeSlices bool
|
||||||
// nilSafeMaps marshals a nil maps '{}' instead of 'null'
|
// nilSafeMaps marshals a nil maps '{}' instead of 'null'
|
||||||
nilSafeMaps bool
|
nilSafeMaps bool
|
||||||
|
// filter matches jsonfilter tag of struct
|
||||||
|
// marshals if no jsonfilter is set or otherwise if jsonfilter has the filter value
|
||||||
|
filter *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
|
type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
|
||||||
@ -777,6 +781,8 @@ FieldLoop:
|
|||||||
|
|
||||||
if f.omitEmpty && isEmptyValue(fv) {
|
if f.omitEmpty && isEmptyValue(fv) {
|
||||||
continue
|
continue
|
||||||
|
} else if opts.filter != nil && len(f.jsonfilter) > 0 && !f.jsonfilter.Contains(*opts.filter) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
e.WriteByte(next)
|
e.WriteByte(next)
|
||||||
next = ','
|
next = ','
|
||||||
@ -1220,15 +1226,28 @@ type field struct {
|
|||||||
nameNonEsc string // `"` + name + `":`
|
nameNonEsc string // `"` + name + `":`
|
||||||
nameEscHTML string // `"` + HTMLEscape(name) + `":`
|
nameEscHTML string // `"` + HTMLEscape(name) + `":`
|
||||||
|
|
||||||
tag bool
|
tag bool
|
||||||
index []int
|
index []int
|
||||||
typ reflect.Type
|
typ reflect.Type
|
||||||
omitEmpty bool
|
omitEmpty bool
|
||||||
quoted bool
|
jsonfilter jsonfilter
|
||||||
|
quoted bool
|
||||||
|
|
||||||
encoder encoderFunc
|
encoder encoderFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// jsonfilter stores the value of the jsonfilter struct tag
|
||||||
|
type jsonfilter []string
|
||||||
|
|
||||||
|
func (j jsonfilter) Contains(t string) bool {
|
||||||
|
for _, tag := range j {
|
||||||
|
if t == tag {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// byIndex sorts field by index sequence.
|
// byIndex sorts field by index sequence.
|
||||||
type byIndex []field
|
type byIndex []field
|
||||||
|
|
||||||
@ -1304,6 +1323,13 @@ func typeFields(t reflect.Type) structFields {
|
|||||||
if !isValidTag(name) {
|
if !isValidTag(name) {
|
||||||
name = ""
|
name = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jsonfilter []string
|
||||||
|
jsonfilterTag := sf.Tag.Get("jsonfilter")
|
||||||
|
if isValidTag(jsonfilterTag) {
|
||||||
|
jsonfilter = strings.Split(jsonfilterTag, ",")
|
||||||
|
}
|
||||||
|
|
||||||
index := make([]int, len(f.index)+1)
|
index := make([]int, len(f.index)+1)
|
||||||
copy(index, f.index)
|
copy(index, f.index)
|
||||||
index[len(f.index)] = i
|
index[len(f.index)] = i
|
||||||
@ -1334,12 +1360,13 @@ func typeFields(t reflect.Type) structFields {
|
|||||||
name = sf.Name
|
name = sf.Name
|
||||||
}
|
}
|
||||||
field := field{
|
field := field{
|
||||||
name: name,
|
name: name,
|
||||||
tag: tagged,
|
tag: tagged,
|
||||||
index: index,
|
index: index,
|
||||||
typ: ft,
|
typ: ft,
|
||||||
omitEmpty: opts.Contains("omitempty"),
|
omitEmpty: opts.Contains("omitempty"),
|
||||||
quoted: quoted,
|
jsonfilter: jsonfilter,
|
||||||
|
quoted: quoted,
|
||||||
}
|
}
|
||||||
field.nameBytes = []byte(field.name)
|
field.nameBytes = []byte(field.name)
|
||||||
field.equalFold = foldFunc(field.nameBytes)
|
field.equalFold = foldFunc(field.nameBytes)
|
||||||
|
@ -1253,6 +1253,10 @@ func TestMarshalSafeCollections(t *testing.T) {
|
|||||||
nilMapStruct struct {
|
nilMapStruct struct {
|
||||||
NilMap map[string]interface{} `json:"nil_map"`
|
NilMap map[string]interface{} `json:"nil_map"`
|
||||||
}
|
}
|
||||||
|
testWithFilter struct {
|
||||||
|
Test1 string `json:"test1" jsonfilter:"FILTERONE"`
|
||||||
|
Test2 string `json:"test2" jsonfilter:"FILTERTWO"`
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -1271,10 +1275,12 @@ func TestMarshalSafeCollections(t *testing.T) {
|
|||||||
{map[string]interface{}{"1": 1, "2": 2, "3": 3}, "{\"1\":1,\"2\":2,\"3\":3}"},
|
{map[string]interface{}{"1": 1, "2": 2, "3": 3}, "{\"1\":1,\"2\":2,\"3\":3}"},
|
||||||
{pNilMap, "null"},
|
{pNilMap, "null"},
|
||||||
{nilMapStruct{}, "{\"nil_map\":{}}"},
|
{nilMapStruct{}, "{\"nil_map\":{}}"},
|
||||||
|
{testWithFilter{}, "{\"test1\":\"\"}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter := "FILTERONE"
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
b, err := MarshalSafeCollections(tt.in, true, true, nil)
|
b, err := MarshalSafeCollections(tt.in, true, true, nil, &filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d, unexpected failure: %v", i, err)
|
t.Errorf("test %d, unexpected failure: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,10 @@ func equalFoldRight(s, t []byte) bool {
|
|||||||
t = t[size:]
|
t = t[size:]
|
||||||
|
|
||||||
}
|
}
|
||||||
return len(t) == 0
|
if len(t) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
||||||
|
@ -52,7 +52,9 @@ func TestFold(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFoldAgainstUnicode(t *testing.T) {
|
func TestFoldAgainstUnicode(t *testing.T) {
|
||||||
var buf1, buf2 []byte
|
const bufSize = 5
|
||||||
|
buf1 := make([]byte, 0, bufSize)
|
||||||
|
buf2 := make([]byte, 0, bufSize)
|
||||||
var runes []rune
|
var runes []rune
|
||||||
for i := 0x20; i <= 0x7f; i++ {
|
for i := 0x20; i <= 0x7f; i++ {
|
||||||
runes = append(runes, rune(i))
|
runes = append(runes, rune(i))
|
||||||
@ -94,8 +96,12 @@ func TestFoldAgainstUnicode(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, r2 := range runes {
|
for _, r2 := range runes {
|
||||||
buf1 = append(utf8.AppendRune(append(buf1[:0], 'x'), r), 'x')
|
buf1 := append(buf1[:0], 'x')
|
||||||
buf2 = append(utf8.AppendRune(append(buf2[:0], 'x'), r2), 'x')
|
buf2 := append(buf2[:0], 'x')
|
||||||
|
buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
|
||||||
|
buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
|
||||||
|
buf1 = append(buf1, 'x')
|
||||||
|
buf2 = append(buf2, 'x')
|
||||||
want := bytes.EqualFold(buf1, buf2)
|
want := bytes.EqualFold(buf1, buf2)
|
||||||
if got := ff.fold(buf1, buf2); got != want {
|
if got := ff.fold(buf1, buf2); got != want {
|
||||||
t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
|
t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
|
||||||
|
@ -17,6 +17,7 @@ type GoJsonRender struct {
|
|||||||
NilSafeSlices bool
|
NilSafeSlices bool
|
||||||
NilSafeMaps bool
|
NilSafeMaps bool
|
||||||
Indent *IndentOpt
|
Indent *IndentOpt
|
||||||
|
Filter *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r GoJsonRender) Render(w http.ResponseWriter) error {
|
func (r GoJsonRender) Render(w http.ResponseWriter) error {
|
||||||
@ -25,7 +26,7 @@ func (r GoJsonRender) Render(w http.ResponseWriter) error {
|
|||||||
header["Content-Type"] = []string{"application/json; charset=utf-8"}
|
header["Content-Type"] = []string{"application/json; charset=utf-8"}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, err := MarshalSafeCollections(r.Data, r.NilSafeSlices, r.NilSafeMaps, r.Indent)
|
jsonBytes, err := MarshalSafeCollections(r.Data, r.NilSafeSlices, r.NilSafeMaps, r.Indent, r.Filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -116,3 +116,18 @@ func TestNumberIsValid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkNumberIsValid(b *testing.B) {
|
||||||
|
s := "-61657.61667E+61673"
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
isValidNumber(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNumberIsValidRegexp(b *testing.B) {
|
||||||
|
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
|
||||||
|
s := "-61657.61667E+61673"
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
jsonNumberRegexp.MatchString(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -594,7 +594,7 @@ func (s *scanner) error(c byte, context string) int {
|
|||||||
return scanError
|
return scanError
|
||||||
}
|
}
|
||||||
|
|
||||||
// quoteChar formats c as a quoted character literal.
|
// quoteChar formats c as a quoted character literal
|
||||||
func quoteChar(c byte) string {
|
func quoteChar(c byte) string {
|
||||||
// special cases - different from quoted strings
|
// special cases - different from quoted strings
|
||||||
if c == '\'' {
|
if c == '\'' {
|
||||||
|
@ -179,11 +179,9 @@ func nonSpace(b []byte) bool {
|
|||||||
|
|
||||||
// An Encoder writes JSON values to an output stream.
|
// An Encoder writes JSON values to an output stream.
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
err error
|
err error
|
||||||
escapeHTML bool
|
escapeHTML bool
|
||||||
nilSafeSlices bool
|
|
||||||
nilSafeMaps bool
|
|
||||||
|
|
||||||
indentBuf *bytes.Buffer
|
indentBuf *bytes.Buffer
|
||||||
indentPrefix string
|
indentPrefix string
|
||||||
@ -204,11 +202,8 @@ func (enc *Encoder) Encode(v any) error {
|
|||||||
if enc.err != nil {
|
if enc.err != nil {
|
||||||
return enc.err
|
return enc.err
|
||||||
}
|
}
|
||||||
|
|
||||||
e := newEncodeState()
|
e := newEncodeState()
|
||||||
defer encodeStatePool.Put(e)
|
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
|
||||||
|
|
||||||
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML, nilSafeMaps: enc.nilSafeMaps, nilSafeSlices: enc.nilSafeSlices})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -236,6 +231,7 @@ func (enc *Encoder) Encode(v any) error {
|
|||||||
if _, err = enc.w.Write(b); err != nil {
|
if _, err = enc.w.Write(b); err != nil {
|
||||||
enc.err = err
|
enc.err = err
|
||||||
}
|
}
|
||||||
|
encodeStatePool.Put(e)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,13 +243,6 @@ func (enc *Encoder) SetIndent(prefix, indent string) {
|
|||||||
enc.indentValue = indent
|
enc.indentValue = indent
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNilSafeCollection specifies whether to represent nil slices and maps as
|
|
||||||
// '[]' or '{}' respectfully (flag on) instead of 'null' (default) when marshaling json.
|
|
||||||
func (enc *Encoder) SetNilSafeCollection(nilSafeSlices bool, nilSafeMaps bool) {
|
|
||||||
enc.nilSafeSlices = nilSafeSlices
|
|
||||||
enc.nilSafeMaps = nilSafeMaps
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEscapeHTML specifies whether problematic HTML characters
|
// SetEscapeHTML specifies whether problematic HTML characters
|
||||||
// should be escaped inside JSON quoted strings.
|
// should be escaped inside JSON quoted strings.
|
||||||
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e
|
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime/debug"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -42,7 +41,7 @@ false
|
|||||||
|
|
||||||
func TestEncoder(t *testing.T) {
|
func TestEncoder(t *testing.T) {
|
||||||
for i := 0; i <= len(streamTest); i++ {
|
for i := 0; i <= len(streamTest); i++ {
|
||||||
var buf strings.Builder
|
var buf bytes.Buffer
|
||||||
enc := NewEncoder(&buf)
|
enc := NewEncoder(&buf)
|
||||||
// Check that enc.SetIndent("", "") turns off indentation.
|
// Check that enc.SetIndent("", "") turns off indentation.
|
||||||
enc.SetIndent(">", ".")
|
enc.SetIndent(">", ".")
|
||||||
@ -60,43 +59,6 @@ func TestEncoder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncoderErrorAndReuseEncodeState(t *testing.T) {
|
|
||||||
// Disable the GC temporarily to prevent encodeState's in Pool being cleaned away during the test.
|
|
||||||
percent := debug.SetGCPercent(-1)
|
|
||||||
defer debug.SetGCPercent(percent)
|
|
||||||
|
|
||||||
// Trigger an error in Marshal with cyclic data.
|
|
||||||
type Dummy struct {
|
|
||||||
Name string
|
|
||||||
Next *Dummy
|
|
||||||
}
|
|
||||||
dummy := Dummy{Name: "Dummy"}
|
|
||||||
dummy.Next = &dummy
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
enc := NewEncoder(&buf)
|
|
||||||
if err := enc.Encode(dummy); err == nil {
|
|
||||||
t.Errorf("Encode(dummy) == nil; want error")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Data struct {
|
|
||||||
A string
|
|
||||||
I int
|
|
||||||
}
|
|
||||||
data := Data{A: "a", I: 1}
|
|
||||||
if err := enc.Encode(data); err != nil {
|
|
||||||
t.Errorf("Marshal(%v) = %v", data, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var data2 Data
|
|
||||||
if err := Unmarshal(buf.Bytes(), &data2); err != nil {
|
|
||||||
t.Errorf("Unmarshal(%v) = %v", data2, err)
|
|
||||||
}
|
|
||||||
if data2 != data {
|
|
||||||
t.Errorf("expect: %v, but get: %v", data, data2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var streamEncodedIndent = `0.1
|
var streamEncodedIndent = `0.1
|
||||||
"hello"
|
"hello"
|
||||||
null
|
null
|
||||||
@ -115,7 +77,7 @@ false
|
|||||||
`
|
`
|
||||||
|
|
||||||
func TestEncoderIndent(t *testing.T) {
|
func TestEncoderIndent(t *testing.T) {
|
||||||
var buf strings.Builder
|
var buf bytes.Buffer
|
||||||
enc := NewEncoder(&buf)
|
enc := NewEncoder(&buf)
|
||||||
enc.SetIndent(">", ".")
|
enc.SetIndent(">", ".")
|
||||||
for _, v := range streamTest {
|
for _, v := range streamTest {
|
||||||
@ -185,7 +147,7 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
|
|||||||
`{"bar":"\"<html>foobar</html>\""}`,
|
`{"bar":"\"<html>foobar</html>\""}`,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
var buf strings.Builder
|
var buf bytes.Buffer
|
||||||
enc := NewEncoder(&buf)
|
enc := NewEncoder(&buf)
|
||||||
if err := enc.Encode(tt.v); err != nil {
|
if err := enc.Encode(tt.v); err != nil {
|
||||||
t.Errorf("Encode(%s): %s", tt.name, err)
|
t.Errorf("Encode(%s): %s", tt.name, err)
|
||||||
@ -347,6 +309,21 @@ func TestBlocking(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncoderEncode(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
type T struct {
|
||||||
|
X, Y string
|
||||||
|
}
|
||||||
|
v := &T{"foo", "bar"}
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
if err := NewEncoder(io.Discard).Encode(v); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type tokenStreamCase struct {
|
type tokenStreamCase struct {
|
||||||
json string
|
json string
|
||||||
expTokens []any
|
expTokens []any
|
||||||
@ -495,45 +472,3 @@ func TestHTTPDecoding(t *testing.T) {
|
|||||||
t.Errorf("err = %v; want io.EOF", err)
|
t.Errorf("err = %v; want io.EOF", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncoderSetNilSafeCollection(t *testing.T) {
|
|
||||||
var (
|
|
||||||
nilSlice []interface{}
|
|
||||||
pNilSlice *[]interface{}
|
|
||||||
nilMap map[string]interface{}
|
|
||||||
pNilMap *map[string]interface{}
|
|
||||||
)
|
|
||||||
for _, tt := range []struct {
|
|
||||||
name string
|
|
||||||
v interface{}
|
|
||||||
want string
|
|
||||||
rescuedWant string
|
|
||||||
}{
|
|
||||||
{"nilSlice", nilSlice, "null", "[]"},
|
|
||||||
{"nonNilSlice", []interface{}{}, "[]", "[]"},
|
|
||||||
{"sliceWithValues", []interface{}{1, 2, 3}, "[1,2,3]", "[1,2,3]"},
|
|
||||||
{"pNilSlice", pNilSlice, "null", "null"},
|
|
||||||
{"nilMap", nilMap, "null", "{}"},
|
|
||||||
{"nonNilMap", map[string]interface{}{}, "{}", "{}"},
|
|
||||||
{"mapWithValues", map[string]interface{}{"1": 1, "2": 2, "3": 3}, "{\"1\":1,\"2\":2,\"3\":3}", "{\"1\":1,\"2\":2,\"3\":3}"},
|
|
||||||
{"pNilMap", pNilMap, "null", "null"},
|
|
||||||
} {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
enc := NewEncoder(&buf)
|
|
||||||
if err := enc.Encode(tt.v); err != nil {
|
|
||||||
t.Fatalf("Encode(%s): %s", tt.name, err)
|
|
||||||
}
|
|
||||||
if got := strings.TrimSpace(buf.String()); got != tt.want {
|
|
||||||
t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.want)
|
|
||||||
}
|
|
||||||
buf.Reset()
|
|
||||||
enc.SetNilSafeCollection(true, true)
|
|
||||||
if err := enc.Encode(tt.v); err != nil {
|
|
||||||
t.Fatalf("SetNilSafeCollection(true) Encode(%s): %s", tt.name, err)
|
|
||||||
}
|
|
||||||
if got := strings.TrimSpace(buf.String()); got != tt.rescuedWant {
|
|
||||||
t.Errorf("SetNilSafeCollection(true) Encode(%s) = %#q, want %#q",
|
|
||||||
tt.name, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user