1
0
mirror of https://github.com/json-iterator/go.git synced 2025-06-15 22:50:24 +02:00

11 Commits
1.0.1 ... 1.0.2

Author SHA1 Message Date
6ed27152e0 Update README.md 2017-09-17 16:07:42 +08:00
3c298d8a76 Merge pull request #172 from olegshaldybin/more-stdlib-compat
Improve stdlib compatibility
2017-09-17 03:05:36 -05:00
9f6e5962a9 Improve stdlib compatibility
1. Null values for primitive types no longer clear the original value in
the destination object.

2. Dereference multiple levels of pointers in the destination interface{}
type before unmarshaling into it. This is needed to match stdlib
behavior when working with nested interface{} fields. If the destination
object is a pointer to interface{} then the incoming nil value should
nil out the destination object but keep the reference to that nil value
on its parent object. However if the destination object is an
interface{} value it should set the reference to nil but keep the
original object intact.

3. Correctly handle typed nil decode destinations.
2017-09-16 16:57:51 -07:00
c463aa12c4 Merge pull request #173 from toffaletti/more-nil-interface-fixes
More nil interface fixes
2017-09-16 18:36:43 -05:00
b5d2607a6d replace should.Equal(nil, err) with should.NoError(err) 2017-09-16 16:30:04 -07:00
48cc4d965a improve test 2017-09-16 16:27:32 -07:00
c59c42fda0 fix decoding of nil non-empty interface 2017-09-16 16:24:55 -07:00
8324374402 add tests for decoding nil interfaces 2017-09-16 16:24:27 -07:00
2017f3866b fix encoding of nil marshaler interface 2017-09-16 16:08:32 -07:00
ddc5af4512 fix encoding of nil non-empty interface 2017-09-16 16:04:36 -07:00
2f7e5c8dd7 add failing tests for nil non-empty interfaces 2017-09-16 16:00:48 -07:00
6 changed files with 304 additions and 73 deletions

View File

@ -76,5 +76,7 @@ Contributors
* [thockin](https://github.com/thockin) * [thockin](https://github.com/thockin)
* [mattn](https://github.com/mattn) * [mattn](https://github.com/mattn)
* [cch123](https://github.com/cch123) * [cch123](https://github.com/cch123)
* [Oleg Shaldybin](https://github.com/olegshaldybin)
* [Jason Toffaletti](https://github.com/toffaletti)
Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)

View File

@ -32,12 +32,10 @@ type intCodec struct {
} }
func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*int)(ptr)) = 0
return
}
*((*int)(ptr)) = iter.ReadInt() *((*int)(ptr)) = iter.ReadInt()
} }
}
func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt(*((*int)(ptr))) stream.WriteInt(*((*int)(ptr)))
@ -55,12 +53,10 @@ type uintptrCodec struct {
} }
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uintptr)(ptr)) = 0
return
}
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64()) *((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
} }
}
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint64(uint64(*((*uintptr)(ptr)))) stream.WriteUint64(uint64(*((*uintptr)(ptr))))
@ -78,12 +74,10 @@ type int8Codec struct {
} }
func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint8)(ptr)) = 0
return
}
*((*int8)(ptr)) = iter.ReadInt8() *((*int8)(ptr)) = iter.ReadInt8()
} }
}
func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt8(*((*int8)(ptr))) stream.WriteInt8(*((*int8)(ptr)))
@ -101,12 +95,10 @@ type int16Codec struct {
} }
func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*int16)(ptr)) = 0
return
}
*((*int16)(ptr)) = iter.ReadInt16() *((*int16)(ptr)) = iter.ReadInt16()
} }
}
func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt16(*((*int16)(ptr))) stream.WriteInt16(*((*int16)(ptr)))
@ -124,12 +116,10 @@ type int32Codec struct {
} }
func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*int32)(ptr)) = 0
return
}
*((*int32)(ptr)) = iter.ReadInt32() *((*int32)(ptr)) = iter.ReadInt32()
} }
}
func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt32(*((*int32)(ptr))) stream.WriteInt32(*((*int32)(ptr)))
@ -147,12 +137,10 @@ type int64Codec struct {
} }
func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*int64)(ptr)) = 0
return
}
*((*int64)(ptr)) = iter.ReadInt64() *((*int64)(ptr)) = iter.ReadInt64()
} }
}
func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt64(*((*int64)(ptr))) stream.WriteInt64(*((*int64)(ptr)))
@ -170,11 +158,10 @@ type uintCodec struct {
} }
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint)(ptr)) = 0 *((*uint)(ptr)) = iter.ReadUint()
return return
} }
*((*uint)(ptr)) = iter.ReadUint()
} }
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -193,12 +180,10 @@ type uint8Codec struct {
} }
func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint8)(ptr)) = 0
return
}
*((*uint8)(ptr)) = iter.ReadUint8() *((*uint8)(ptr)) = iter.ReadUint8()
} }
}
func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint8(*((*uint8)(ptr))) stream.WriteUint8(*((*uint8)(ptr)))
@ -216,12 +201,10 @@ type uint16Codec struct {
} }
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint16)(ptr)) = 0
return
}
*((*uint16)(ptr)) = iter.ReadUint16() *((*uint16)(ptr)) = iter.ReadUint16()
} }
}
func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint16(*((*uint16)(ptr))) stream.WriteUint16(*((*uint16)(ptr)))
@ -239,12 +222,10 @@ type uint32Codec struct {
} }
func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint32)(ptr)) = 0
return
}
*((*uint32)(ptr)) = iter.ReadUint32() *((*uint32)(ptr)) = iter.ReadUint32()
} }
}
func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint32(*((*uint32)(ptr))) stream.WriteUint32(*((*uint32)(ptr)))
@ -262,12 +243,10 @@ type uint64Codec struct {
} }
func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*uint64)(ptr)) = 0
return
}
*((*uint64)(ptr)) = iter.ReadUint64() *((*uint64)(ptr)) = iter.ReadUint64()
} }
}
func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint64(*((*uint64)(ptr))) stream.WriteUint64(*((*uint64)(ptr)))
@ -285,12 +264,10 @@ type float32Codec struct {
} }
func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*float32)(ptr)) = 0
return
}
*((*float32)(ptr)) = iter.ReadFloat32() *((*float32)(ptr)) = iter.ReadFloat32()
} }
}
func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat32(*((*float32)(ptr))) stream.WriteFloat32(*((*float32)(ptr)))
@ -308,12 +285,10 @@ type float64Codec struct {
} }
func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if !iter.ReadNil() {
*((*float64)(ptr)) = 0
return
}
*((*float64)(ptr)) = iter.ReadFloat64() *((*float64)(ptr)) = iter.ReadFloat64()
} }
}
func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat64(*((*float64)(ptr))) stream.WriteFloat64(*((*float64)(ptr)))
@ -352,13 +327,39 @@ type emptyInterfaceCodec struct {
} }
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
existing := *((*interface{})(ptr))
// Checking for both typed and untyped nil pointers.
if existing != nil &&
reflect.TypeOf(existing).Kind() == reflect.Ptr &&
!reflect.ValueOf(existing).IsNil() {
var ptrToExisting interface{}
for {
elem := reflect.ValueOf(existing).Elem()
if elem.Kind() != reflect.Ptr || elem.IsNil() {
break
}
ptrToExisting = existing
existing = elem.Interface()
}
if iter.ReadNil() { if iter.ReadNil() {
if ptrToExisting != nil {
nilPtr := reflect.Zero(reflect.TypeOf(ptrToExisting).Elem())
reflect.ValueOf(ptrToExisting).Elem().Set(nilPtr)
} else {
*((*interface{})(ptr)) = nil *((*interface{})(ptr)) = nil
}
} else {
iter.ReadVal(existing)
}
return return
} }
existing := *((*interface{})(ptr))
if existing != nil && reflect.TypeOf(existing).Kind() == reflect.Ptr { if iter.ReadNil() {
iter.ReadVal(existing) *((*interface{})(ptr)) = nil
} else { } else {
*((*interface{})(ptr)) = iter.Read() *((*interface{})(ptr)) = iter.Read()
} }
@ -391,15 +392,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
iter.ReadVal(&i) iter.ReadVal(&i)
if e.word == nil {
nonEmptyInterface.itab = nil
}
nonEmptyInterface.word = e.word nonEmptyInterface.word = e.word
} }
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
nonEmptyInterface := (*nonEmptyInterface)(ptr) nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{} var i interface{}
if nonEmptyInterface.itab != nil {
e := (*emptyInterface)(unsafe.Pointer(&i)) e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
}
stream.WriteVal(i) stream.WriteVal(i)
} }
@ -660,7 +666,11 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface templateInterface := encoder.templateInterface
templateInterface.word = ptr templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(json.Marshaler) marshaler, ok := (*realInterface).(json.Marshaler)
if !ok {
stream.WriteVal(nil)
return
}
bytes, err := marshaler.MarshalJSON() bytes, err := marshaler.MarshalJSON()
if err != nil { if err != nil {

View File

@ -92,22 +92,22 @@ func Test_bool_can_be_null(t *testing.T) {
obj := TestData{} obj := TestData{}
data1 := []byte(`{"field": true}`) data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj) err := Unmarshal(data1, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj.Field) should.Equal(true, obj.Field)
data2 := []byte(`{"field": null}`) data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj) err = Unmarshal(data2, &obj)
should.Equal(nil, err) should.NoError(err)
// Same behavior as stdlib, not touching the existing value. // Same behavior as stdlib, not touching the existing value.
should.Equal(true, obj.Field) should.Equal(true, obj.Field)
// Checking stdlib behavior as well // Checking stdlib behavior as well
obj2 := TestData{} obj2 := TestData{}
err = json.Unmarshal(data1, &obj2) err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj2.Field) should.Equal(true, obj2.Field)
err = json.Unmarshal(data2, &obj2) err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, obj2.Field) should.Equal(true, obj2.Field)
} }

View File

@ -40,11 +40,11 @@ func Test_custom_marshaler_on_enum(t *testing.T) {
w := Wrapper{Payload: MyEnumB} w := Wrapper{Payload: MyEnumB}
jb, err := Marshal(w) jb, err := Marshal(w)
should.Equal(nil, err) should.NoError(err)
should.Equal(`{"Payload":"foo-1"}`, string(jb)) should.Equal(`{"Payload":"foo-1"}`, string(jb))
var w2 Wrapper2 var w2 Wrapper2
err = Unmarshal(jb, &w2) err = Unmarshal(jb, &w2)
should.Equal(nil, err) should.NoError(err)
should.Equal(MyEnumB, w2.Payload) should.Equal(MyEnumB, w2.Payload)
} }

View File

@ -329,13 +329,13 @@ func Test_nil_out_null_interface(t *testing.T) {
data1 := []byte(`{"field": true}`) data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj) err := Unmarshal(data1, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, *(obj.Field.(*bool))) should.Equal(true, *(obj.Field.(*bool)))
data2 := []byte(`{"field": null}`) data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj) err = Unmarshal(data2, &obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(nil, obj.Field) should.Equal(nil, obj.Field)
// Checking stdlib behavior matches. // Checking stdlib behavior matches.
@ -344,11 +344,11 @@ func Test_nil_out_null_interface(t *testing.T) {
} }
err = json.Unmarshal(data1, &obj2) err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(true, *(obj2.Field.(*bool))) should.Equal(true, *(obj2.Field.(*bool)))
err = json.Unmarshal(data2, &obj2) err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err) should.NoError(err)
should.Equal(nil, obj2.Field) should.Equal(nil, obj2.Field)
} }
@ -363,10 +363,198 @@ func Test_omitempty_nil_interface(t *testing.T) {
} }
js, err := json.Marshal(obj) js, err := json.Marshal(obj)
should.Equal(nil, err) should.NoError(err)
should.Equal("{}", string(js)) should.Equal("{}", string(js))
str, err := MarshalToString(obj) str, err := MarshalToString(obj)
should.Equal(nil, err) should.NoError(err)
should.Equal(string(js), str) should.Equal(string(js), str)
} }
func Test_omitempty_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field,omitempty"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal("{}", string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = UnmarshalFromString(`{"field":null}`, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}
func Test_marshal_nil_marshaler_interface(t *testing.T) {
type TestData struct {
Field json.Marshaler `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
}
func Test_marshal_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = Unmarshal(js, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}
func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
type Payload struct {
Value int `json:"val,omitempty"`
}
should := require.New(t)
payload := &Payload{}
wrapper := &Wrapper{
Payload: &payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal((*Payload)(nil), payload)
payload = &Payload{}
wrapper = &Wrapper{
Payload: &payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal((*Payload)(nil), payload)
}
func Test_overwrite_interface_value_with_nil(t *testing.T) {
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
type Payload struct {
Value int `json:"val,omitempty"`
}
should := require.New(t)
payload := &Payload{}
wrapper := &Wrapper{
Payload: payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(nil, wrapper.Payload)
should.Equal(42, payload.Value)
payload = &Payload{}
wrapper = &Wrapper{
Payload: payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(nil, wrapper.Payload)
should.Equal(42, payload.Value)
}
func Test_unmarshal_into_nil(t *testing.T) {
type Payload struct {
Value int `json:"val,omitempty"`
}
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
should := require.New(t)
var payload *Payload
wrapper := &Wrapper{
Payload: payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Nil(err)
should.NotNil(wrapper.Payload)
should.Nil(payload)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Nil(err)
should.Nil(wrapper.Payload)
should.Nil(payload)
payload = nil
wrapper = &Wrapper{
Payload: payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Nil(err)
should.NotNil(wrapper.Payload)
should.Nil(payload)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Nil(err)
should.Nil(wrapper.Payload)
should.Nil(payload)
}

View File

@ -3,9 +3,10 @@ package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require"
"io" "io"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_read_null(t *testing.T) { func Test_read_null(t *testing.T) {
@ -135,3 +136,33 @@ func Test_encode_nil_array(t *testing.T) {
should.Nil(err) should.Nil(err)
should.Equal("null", string(output)) should.Equal("null", string(output))
} }
func Test_decode_nil_num(t *testing.T) {
type TestData struct {
Field int `json:"field"`
}
should := require.New(t)
data1 := []byte(`{"field": 42}`)
data2 := []byte(`{"field": null}`)
// Checking stdlib behavior as well
obj2 := TestData{}
err := json.Unmarshal(data1, &obj2)
should.Equal(nil, err)
should.Equal(42, obj2.Field)
err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err)
should.Equal(42, obj2.Field)
obj := TestData{}
err = Unmarshal(data1, &obj)
should.Equal(nil, err)
should.Equal(42, obj.Field)
err = Unmarshal(data2, &obj)
should.Equal(nil, err)
should.Equal(42, obj.Field)
}