Ver Fonte

Merge pull request #173 from toffaletti/more-nil-interface-fixes

More nil interface fixes
Tao Wen há 8 anos atrás
pai
commit
c463aa12c4

+ 13 - 4
feature_reflect_native.go

@@ -391,15 +391,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
 	e.typ = nonEmptyInterface.itab.typ
 	e.word = nonEmptyInterface.word
 	iter.ReadVal(&i)
+	if e.word == nil {
+		nonEmptyInterface.itab = nil
+	}
 	nonEmptyInterface.word = e.word
 }
 
 func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 	nonEmptyInterface := (*nonEmptyInterface)(ptr)
 	var i interface{}
-	e := (*emptyInterface)(unsafe.Pointer(&i))
-	e.typ = nonEmptyInterface.itab.typ
-	e.word = nonEmptyInterface.word
+	if nonEmptyInterface.itab != nil {
+		e := (*emptyInterface)(unsafe.Pointer(&i))
+		e.typ = nonEmptyInterface.itab.typ
+		e.word = nonEmptyInterface.word
+	}
 	stream.WriteVal(i)
 }
 
@@ -660,7 +665,11 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 	templateInterface := encoder.templateInterface
 	templateInterface.word = ptr
 	realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
-	marshaler := (*realInterface).(json.Marshaler)
+	marshaler, ok := (*realInterface).(json.Marshaler)
+	if !ok {
+		stream.WriteVal(nil)
+		return
+	}
 
 	bytes, err := marshaler.MarshalJSON()
 	if err != nil {

+ 4 - 4
jsoniter_bool_test.go

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

+ 2 - 2
jsoniter_enum_marshaler_test.go

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

+ 73 - 6
jsoniter_interface_test.go

@@ -329,13 +329,13 @@ func Test_nil_out_null_interface(t *testing.T) {
 	data1 := []byte(`{"field": true}`)
 
 	err := Unmarshal(data1, &obj)
-	should.Equal(nil, err)
+	should.NoError(err)
 	should.Equal(true, *(obj.Field.(*bool)))
 
 	data2 := []byte(`{"field": null}`)
 
 	err = Unmarshal(data2, &obj)
-	should.Equal(nil, err)
+	should.NoError(err)
 	should.Equal(nil, obj.Field)
 
 	// Checking stdlib behavior matches.
@@ -344,11 +344,11 @@ func Test_nil_out_null_interface(t *testing.T) {
 	}
 
 	err = json.Unmarshal(data1, &obj2)
-	should.Equal(nil, err)
+	should.NoError(err)
 	should.Equal(true, *(obj2.Field.(*bool)))
 
 	err = json.Unmarshal(data2, &obj2)
-	should.Equal(nil, err)
+	should.NoError(err)
 	should.Equal(nil, obj2.Field)
 }
 
@@ -363,10 +363,77 @@ func Test_omitempty_nil_interface(t *testing.T) {
 	}
 
 	js, err := json.Marshal(obj)
-	should.Equal(nil, err)
+	should.NoError(err)
 	should.Equal("{}", string(js))
 
 	str, err := MarshalToString(obj)
-	should.Equal(nil, err)
+	should.NoError(err)
 	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)
+}