forked from mirror/go-json
Merge pull request #187 from IncSW/zero-values-on-custom-types
This commit is contained in:
commit
cd300c9e56
|
@ -2,11 +2,20 @@ package json_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
stdjson "encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
type customBool bool
|
||||
|
||||
type customBoolWithMarshaler bool
|
||||
|
||||
func (b customBoolWithMarshaler) MarshalJSON() ([]byte, error) {
|
||||
return stdjson.Marshal(bool(b))
|
||||
}
|
||||
|
||||
func TestCoverBool(t *testing.T) {
|
||||
type structBool struct {
|
||||
A bool `json:"a"`
|
||||
|
@ -28,6 +37,24 @@ func TestCoverBool(t *testing.T) {
|
|||
A *bool `json:"a,string"`
|
||||
}
|
||||
|
||||
type structCustomBoolOmitEmpty struct {
|
||||
A customBool `json:"a,omitempty"`
|
||||
}
|
||||
|
||||
type structSecondFieldCustomBoolOmitEmpty struct {
|
||||
C bool `json:"c"`
|
||||
A customBool `json:"a,omitempty"`
|
||||
}
|
||||
|
||||
type structCustomBoolWithMarshalerOmitEmpty struct {
|
||||
A customBoolWithMarshaler `json:"a,omitempty"`
|
||||
}
|
||||
|
||||
type structSecondFieldCustomBoolWithMarshalerOmitEmpty struct {
|
||||
C bool `json:"c"`
|
||||
A customBoolWithMarshaler `json:"a,omitempty"`
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
data interface{}
|
||||
|
@ -1400,6 +1427,86 @@ func TestCoverBool(t *testing.T) {
|
|||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolOmitEmpty",
|
||||
data: struct {
|
||||
structCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolOmitEmpty: structCustomBoolOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolOmitEmptyFalse",
|
||||
data: struct {
|
||||
structCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolOmitEmpty: structCustomBoolOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolOmitEmpty",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: structSecondFieldCustomBoolOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolOmitEmptyFalse",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: structSecondFieldCustomBoolOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolWithMarshalerOmitEmpty",
|
||||
data: struct {
|
||||
structCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: structCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolWithMarshalerOmitEmptyFalse",
|
||||
data: struct {
|
||||
structCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: structCustomBoolWithMarshalerOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolWithMarshalerOmitEmpty",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: structSecondFieldCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolWithMarshalerOmitEmptyFalse",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: structSecondFieldCustomBoolWithMarshalerOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadBoolString",
|
||||
data: struct {
|
||||
|
@ -1432,6 +1539,86 @@ func TestCoverBool(t *testing.T) {
|
|||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolOmitEmpty: &structCustomBoolOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolOmitEmpty: &structCustomBoolOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolOmitEmpty",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: &structSecondFieldCustomBoolOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: &structSecondFieldCustomBoolOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolWithMarshalerOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: &structCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolWithMarshalerOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: &structCustomBoolWithMarshalerOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolWithMarshalerOmitEmpty",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: &structSecondFieldCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolWithMarshalerOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: &structSecondFieldCustomBoolWithMarshalerOmitEmpty{},
|
||||
B: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadBoolString",
|
||||
data: struct {
|
||||
|
@ -1464,6 +1651,26 @@ func TestCoverBool(t *testing.T) {
|
|||
B: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadCustomBoolOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolOmitEmpty: nil,
|
||||
B: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadCustomBoolWithMarshalerOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
B bool `json:"b,omitempty"`
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: nil,
|
||||
B: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadBoolString",
|
||||
data: struct {
|
||||
|
@ -1620,6 +1827,54 @@ func TestCoverBool(t *testing.T) {
|
|||
structBoolOmitEmpty: structBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolOnlyOmitEmpty",
|
||||
data: struct {
|
||||
structCustomBoolOmitEmpty
|
||||
}{
|
||||
structCustomBoolOmitEmpty: structCustomBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolOnlyOmitEmpty",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: structSecondFieldCustomBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolWithMarshalerOnlyOmitEmpty",
|
||||
data: struct {
|
||||
structCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: structCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadCustomBoolWithMarshalerOnlyOmitEmptyFalse",
|
||||
data: struct {
|
||||
structCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: structCustomBoolWithMarshalerOmitEmpty{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolWithMarshalerOnlyOmitEmpty",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: structSecondFieldCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadSecondFieldCustomBoolWithMarshalerOnlyOmitEmptyFalse",
|
||||
data: struct {
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: structSecondFieldCustomBoolWithMarshalerOmitEmpty{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AnonymousHeadBoolOnlyString",
|
||||
data: struct {
|
||||
|
@ -1646,6 +1901,54 @@ func TestCoverBool(t *testing.T) {
|
|||
structBoolOmitEmpty: &structBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolOmitEmpty
|
||||
}{
|
||||
structCustomBoolOmitEmpty: &structCustomBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolOmitEmpty: &structSecondFieldCustomBoolOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolWithMarshalerOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: &structCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadCustomBoolWithMarshalerOnlyOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: &structCustomBoolWithMarshalerOmitEmpty{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolWithMarshalerOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: &structSecondFieldCustomBoolWithMarshalerOmitEmpty{A: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadSecondFieldCustomBoolWithMarshalerOnlyOmitEmptyFalse",
|
||||
data: struct {
|
||||
*structSecondFieldCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structSecondFieldCustomBoolWithMarshalerOmitEmpty: &structSecondFieldCustomBoolWithMarshalerOmitEmpty{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PtrAnonymousHeadBoolOnlyString",
|
||||
data: struct {
|
||||
|
@ -1672,6 +1975,22 @@ func TestCoverBool(t *testing.T) {
|
|||
structBoolOmitEmpty: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadCustomBoolOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolOmitEmpty
|
||||
}{
|
||||
structCustomBoolOmitEmpty: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadCustomBoolWithMarshalerOnlyOmitEmpty",
|
||||
data: struct {
|
||||
*structCustomBoolWithMarshalerOmitEmpty
|
||||
}{
|
||||
structCustomBoolWithMarshalerOmitEmpty: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NilPtrAnonymousHeadBoolOnlyString",
|
||||
data: struct {
|
||||
|
|
|
@ -560,6 +560,14 @@ func AppendIndent(ctx *RuntimeContext, b []byte, indent int) []byte {
|
|||
func IsNilForMarshaler(v interface{}) bool {
|
||||
rv := reflect.ValueOf(v)
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return rv.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return rv.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return math.Float64bits(rv.Float()) == 0
|
||||
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func:
|
||||
return rv.IsNil()
|
||||
case reflect.Slice:
|
||||
|
|
|
@ -3646,8 +3646,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
break
|
||||
}
|
||||
iface := ptrToInterface(code, p)
|
||||
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||
code = code.NextField
|
||||
break
|
||||
}
|
||||
b = append(b, code.Key...)
|
||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false)
|
||||
bb, err := appendMarshalJSON(code, b, iface, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3659,8 +3659,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
break
|
||||
}
|
||||
iface := ptrToInterface(code, p)
|
||||
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||
code = code.NextField
|
||||
break
|
||||
}
|
||||
b = append(b, code.Key...)
|
||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false)
|
||||
bb, err := appendMarshalJSON(code, b, iface, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3646,8 +3646,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
break
|
||||
}
|
||||
iface := ptrToInterface(code, p)
|
||||
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||
code = code.NextField
|
||||
break
|
||||
}
|
||||
b = append(b, code.EscapedKey...)
|
||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true)
|
||||
bb, err := appendMarshalJSON(code, b, iface, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3901,10 +3901,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
break
|
||||
}
|
||||
iface := ptrToInterface(code, p)
|
||||
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||
code = code.NextField
|
||||
break
|
||||
}
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, code.EscapedKey...)
|
||||
b = append(b, ' ')
|
||||
bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent+1, true)
|
||||
bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent+1, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3901,10 +3901,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
break
|
||||
}
|
||||
iface := ptrToInterface(code, p)
|
||||
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||
code = code.NextField
|
||||
break
|
||||
}
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, code.Key...)
|
||||
b = append(b, ' ')
|
||||
bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent+1, false)
|
||||
bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent+1, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue