|
|
@@ -2,9 +2,9 @@ package jsoniter
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
- "encoding/json"
|
|
|
"github.com/json-iterator/go/require"
|
|
|
"testing"
|
|
|
+ "fmt"
|
|
|
)
|
|
|
|
|
|
func Test_empty_object(t *testing.T) {
|
|
|
@@ -61,196 +61,275 @@ func Test_two_field(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func Test_read_object_as_any(t *testing.T) {
|
|
|
+func Test_object_wrapper_any_get_all(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
|
|
|
- should.Nil(err)
|
|
|
- should.Equal(`{"a":"b","c":"d"}`, any.ToString())
|
|
|
- // partial parse
|
|
|
- should.Equal("b", any.Get("a").ToString())
|
|
|
- should.Equal("d", any.Get("c").ToString())
|
|
|
- should.Equal(2, len(any.Keys()))
|
|
|
- any, err = UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
|
|
|
- // full parse
|
|
|
- should.Equal(2, len(any.Keys()))
|
|
|
- should.Equal(2, any.Size())
|
|
|
- should.True(any.ToBool())
|
|
|
- should.Equal(1, any.ToInt())
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 []int
|
|
|
+ Field2 []int
|
|
|
+ }
|
|
|
+ any := Wrap(TestObject{[]int{1, 2}, []int{3, 4}})
|
|
|
+ should.Contains(any.Get('*', 0).ToString(), `"Field2":3`)
|
|
|
}
|
|
|
|
|
|
-func Test_object_any_lazy_iterator(t *testing.T) {
|
|
|
+func Test_write_object(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
|
|
|
- should.Nil(err)
|
|
|
- // iterator parse
|
|
|
- vals := map[string]string{}
|
|
|
- var k string
|
|
|
- var v Any
|
|
|
- next, hasNext := any.IterateObject()
|
|
|
- should.True(hasNext)
|
|
|
-
|
|
|
- k, v, hasNext = next()
|
|
|
- should.True(hasNext)
|
|
|
- vals[k] = v.ToString()
|
|
|
+ buf := &bytes.Buffer{}
|
|
|
+ stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
|
|
|
+ stream.WriteObjectStart()
|
|
|
+ stream.WriteObjectField("hello")
|
|
|
+ stream.WriteInt(1)
|
|
|
+ stream.WriteMore()
|
|
|
+ stream.WriteObjectField("world")
|
|
|
+ stream.WriteInt(2)
|
|
|
+ stream.WriteObjectEnd()
|
|
|
+ stream.Flush()
|
|
|
+ should.Nil(stream.Error)
|
|
|
+ should.Equal("{\n \"hello\":1,\n \"world\":2\n}", buf.String())
|
|
|
+}
|
|
|
|
|
|
- // trigger full parse
|
|
|
- should.Equal(2, len(any.Keys()))
|
|
|
+func Test_decode_one_field_struct(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
|
|
|
+ should.Equal("hello", obj.Field1)
|
|
|
+}
|
|
|
|
|
|
- k, v, hasNext = next()
|
|
|
- should.False(hasNext)
|
|
|
- vals[k] = v.ToString()
|
|
|
+func Test_decode_two_fields_struct(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ Field2 string
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b"}`, &obj))
|
|
|
+ should.Equal("a", obj.Field1)
|
|
|
+ should.Equal("b", obj.Field2)
|
|
|
+}
|
|
|
|
|
|
- should.Equal(map[string]string{"a": "b", "c": "d"}, vals)
|
|
|
- vals = map[string]string{}
|
|
|
- for next, hasNext := any.IterateObject(); hasNext; {
|
|
|
- k, v, hasNext = next()
|
|
|
- if v.ValueType() == String {
|
|
|
- vals[k] = v.ToString()
|
|
|
- }
|
|
|
+func Test_decode_three_fields_struct(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ Field2 string
|
|
|
+ Field3 string
|
|
|
}
|
|
|
- should.Equal(map[string]string{"a": "b", "c": "d"}, vals)
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c"}`, &obj))
|
|
|
+ should.Equal("a", obj.Field1)
|
|
|
+ should.Equal("b", obj.Field2)
|
|
|
+ should.Equal("c", obj.Field3)
|
|
|
}
|
|
|
|
|
|
-func Test_object_any_with_two_lazy_iterators(t *testing.T) {
|
|
|
+func Test_decode_four_fields_struct(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":"b","c":"d","e":"f"}`)
|
|
|
- should.Nil(err)
|
|
|
- var k string
|
|
|
- var v Any
|
|
|
- next1, hasNext1 := any.IterateObject()
|
|
|
- next2, hasNext2 := any.IterateObject()
|
|
|
- should.True(hasNext1)
|
|
|
- k, v, hasNext1 = next1()
|
|
|
- should.True(hasNext1)
|
|
|
- should.Equal("a", k)
|
|
|
- should.Equal("b", v.ToString())
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ Field2 string
|
|
|
+ Field3 string
|
|
|
+ Field4 string
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d"}`, &obj))
|
|
|
+ should.Equal("a", obj.Field1)
|
|
|
+ should.Equal("b", obj.Field2)
|
|
|
+ should.Equal("c", obj.Field3)
|
|
|
+ should.Equal("d", obj.Field4)
|
|
|
+}
|
|
|
|
|
|
- should.True(hasNext2)
|
|
|
- k, v, hasNext2 = next2()
|
|
|
- should.True(hasNext2)
|
|
|
- should.Equal("a", k)
|
|
|
- should.Equal("b", v.ToString())
|
|
|
+func Test_decode_five_fields_struct(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ Field2 string
|
|
|
+ Field3 string
|
|
|
+ Field4 string
|
|
|
+ Field5 string
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
|
|
|
+ should.Equal("a", obj.Field1)
|
|
|
+ should.Equal("b", obj.Field2)
|
|
|
+ should.Equal("c", obj.Field3)
|
|
|
+ should.Equal("d", obj.Field4)
|
|
|
+ should.Equal("e", obj.Field5)
|
|
|
+}
|
|
|
|
|
|
- k, v, hasNext1 = next1()
|
|
|
- should.True(hasNext1)
|
|
|
- should.Equal("c", k)
|
|
|
- should.Equal("d", v.ToString())
|
|
|
+func Test_decode_ten_fields_struct(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string
|
|
|
+ Field2 string
|
|
|
+ Field3 string
|
|
|
+ Field4 string
|
|
|
+ Field5 string
|
|
|
+ Field6 string
|
|
|
+ Field7 string
|
|
|
+ Field8 string
|
|
|
+ Field9 string
|
|
|
+ Field10 string
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ should.Nil(UnmarshalFromString(`{}`, &obj))
|
|
|
+ should.Equal("", obj.Field1)
|
|
|
+ should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
|
|
|
+ should.Equal("a", obj.Field1)
|
|
|
+ should.Equal("b", obj.Field2)
|
|
|
+ should.Equal("c", obj.Field3)
|
|
|
+ should.Equal("d", obj.Field4)
|
|
|
+ should.Equal("e", obj.Field5)
|
|
|
+}
|
|
|
|
|
|
- k, v, hasNext2 = next2()
|
|
|
- should.True(hasNext2)
|
|
|
- should.Equal("c", k)
|
|
|
- should.Equal("d", v.ToString())
|
|
|
+func Test_decode_struct_field_with_tag(t *testing.T) {
|
|
|
+ should := require.New(t)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string `json:"field-1"`
|
|
|
+ Field2 string `json:"-"`
|
|
|
+ Field3 int `json:",string"`
|
|
|
+ }
|
|
|
+ obj := TestObject{Field2: "world"}
|
|
|
+ UnmarshalFromString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
|
|
|
+ should.Equal("hello", obj.Field1)
|
|
|
+ should.Equal("world", obj.Field2)
|
|
|
+ should.Equal(100, obj.Field3)
|
|
|
}
|
|
|
|
|
|
-func Test_object_lazy_any_get(t *testing.T) {
|
|
|
+func Test_write_val_zero_field_struct(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
|
|
|
+ type TestObject struct {
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ str, err := MarshalToString(obj)
|
|
|
should.Nil(err)
|
|
|
- should.Equal("d", any.Get("a", "b", "c").ToString())
|
|
|
+ should.Equal(`{}`, str)
|
|
|
}
|
|
|
|
|
|
-func Test_object_lazy_any_get_all(t *testing.T) {
|
|
|
+func Test_write_val_one_field_struct(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":[0],"b":[1]}`)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string `json:"field-1"`
|
|
|
+ }
|
|
|
+ obj := TestObject{"hello"}
|
|
|
+ str, err := MarshalToString(obj)
|
|
|
should.Nil(err)
|
|
|
- should.Contains(any.Get('*', 0).ToString(), `"a":0`)
|
|
|
+ should.Equal(`{"field-1":"hello"}`, str)
|
|
|
}
|
|
|
|
|
|
-func Test_object_lazy_any_get_invalid(t *testing.T) {
|
|
|
+func Test_mixed(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{}`)
|
|
|
+ type AA struct {
|
|
|
+ ID int `json:"id"`
|
|
|
+ Payload map[string]interface{} `json:"payload"`
|
|
|
+ buf *bytes.Buffer `json:"-"`
|
|
|
+ }
|
|
|
+ aa := AA{}
|
|
|
+ err := UnmarshalFromString(` {"id":1, "payload":{"account":"123","password":"456"}}`, &aa)
|
|
|
should.Nil(err)
|
|
|
- should.Equal(Invalid, any.Get("a", "b", "c").ValueType())
|
|
|
- should.Equal(Invalid, any.Get(1).ValueType())
|
|
|
+ should.Equal(1, aa.ID)
|
|
|
+ should.Equal("123", aa.Payload["account"])
|
|
|
}
|
|
|
|
|
|
-func Test_object_lazy_any_set(t *testing.T) {
|
|
|
+func Test_omit_empty(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
|
|
|
- should.Nil(err)
|
|
|
- any.GetObject()["a"] = WrapInt64(1)
|
|
|
- str, err := MarshalToString(any)
|
|
|
+ type TestObject struct {
|
|
|
+ Field1 string `json:"field-1,omitempty"`
|
|
|
+ Field2 string `json:"field-2,omitempty"`
|
|
|
+ Field3 string `json:"field-3,omitempty"`
|
|
|
+ }
|
|
|
+ obj := TestObject{}
|
|
|
+ obj.Field2 = "hello"
|
|
|
+ str, err := MarshalToString(&obj)
|
|
|
should.Nil(err)
|
|
|
- should.Equal(`{"a":1}`, str)
|
|
|
+ should.Equal(`{"field-2":"hello"}`, str)
|
|
|
}
|
|
|
|
|
|
-func Test_wrap_object(t *testing.T) {
|
|
|
+func Test_recursive_struct(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
type TestObject struct {
|
|
|
Field1 string
|
|
|
- field2 string
|
|
|
+ Me *TestObject
|
|
|
}
|
|
|
- any := Wrap(TestObject{"hello", "world"})
|
|
|
- should.Equal("hello", any.Get("Field1").ToString())
|
|
|
- any = Wrap(TestObject{"hello", "world"})
|
|
|
- should.Equal(2, any.Size())
|
|
|
- any = Wrap(TestObject{"hello", "world"})
|
|
|
- vals := map[string]string{}
|
|
|
- var k string
|
|
|
- var v Any
|
|
|
- for next, hasNext := any.IterateObject(); hasNext; {
|
|
|
- k, v, hasNext = next()
|
|
|
- if v.ValueType() == String {
|
|
|
- vals[k] = v.ToString()
|
|
|
- }
|
|
|
- }
|
|
|
- should.Equal(map[string]string{"Field1": "hello"}, vals)
|
|
|
+ obj := TestObject{}
|
|
|
+ str, err := MarshalToString(obj)
|
|
|
+ should.Nil(err)
|
|
|
+ should.Contains(str, `"Field1":""`)
|
|
|
+ should.Contains(str, `"Me":null`)
|
|
|
+ err = UnmarshalFromString(str, &obj)
|
|
|
+ should.Nil(err)
|
|
|
}
|
|
|
|
|
|
-func Test_object_wrapper_any_get_all(t *testing.T) {
|
|
|
+func Test_one_field_struct(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
+ type YetYetAnotherObject struct {
|
|
|
+ Field string
|
|
|
+ }
|
|
|
+ type YetAnotherObject struct {
|
|
|
+ Field *YetYetAnotherObject
|
|
|
+ }
|
|
|
+ type AnotherObject struct {
|
|
|
+ Field *YetAnotherObject
|
|
|
+ }
|
|
|
type TestObject struct {
|
|
|
- Field1 []int
|
|
|
- Field2 []int
|
|
|
+ Me *AnotherObject
|
|
|
}
|
|
|
- any := Wrap(TestObject{[]int{1, 2}, []int{3, 4}})
|
|
|
- should.Contains(any.Get('*', 0).ToString(), `"Field2":3`)
|
|
|
+ obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
|
|
|
+ str, err := MarshalToString(obj)
|
|
|
+ should.Nil(err)
|
|
|
+ should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
|
|
|
+ str, err = MarshalToString(&obj)
|
|
|
+ should.Nil(err)
|
|
|
+ should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
|
|
|
}
|
|
|
|
|
|
-func Test_write_object(t *testing.T) {
|
|
|
+func Test_anonymous_struct_marshal(t *testing.T) {
|
|
|
should := require.New(t)
|
|
|
- buf := &bytes.Buffer{}
|
|
|
- stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096)
|
|
|
- stream.WriteObjectStart()
|
|
|
- stream.WriteObjectField("hello")
|
|
|
- stream.WriteInt(1)
|
|
|
- stream.WriteMore()
|
|
|
- stream.WriteObjectField("world")
|
|
|
- stream.WriteInt(2)
|
|
|
- stream.WriteObjectEnd()
|
|
|
- stream.Flush()
|
|
|
- should.Nil(stream.Error)
|
|
|
- should.Equal("{\n \"hello\":1,\n \"world\":2\n}", buf.String())
|
|
|
+ type TestObject struct {
|
|
|
+ Field string
|
|
|
+ }
|
|
|
+ str, err := MarshalToString(struct {
|
|
|
+ TestObject
|
|
|
+ Field int
|
|
|
+ }{
|
|
|
+ Field: 100,
|
|
|
+ })
|
|
|
+ should.Nil(err)
|
|
|
+ should.Equal(`{"Field":100}`, str)
|
|
|
}
|
|
|
|
|
|
-func Benchmark_jsoniter_object(b *testing.B) {
|
|
|
- type TestObj struct {
|
|
|
+func Test_decode_nested(t *testing.T) {
|
|
|
+ type StructOfString struct {
|
|
|
Field1 string
|
|
|
- Field2 uint64
|
|
|
+ Field2 string
|
|
|
}
|
|
|
- for n := 0; n < b.N; n++ {
|
|
|
- iter := ParseString(ConfigDefault, `{"field1": "1", "field2": 2}`)
|
|
|
- obj := TestObj{}
|
|
|
- for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
|
|
|
- switch field {
|
|
|
- case "field1":
|
|
|
- obj.Field1 = iter.ReadString()
|
|
|
- case "field2":
|
|
|
- obj.Field2 = iter.ReadUint64()
|
|
|
- default:
|
|
|
- iter.reportError("bind object", "unexpected field")
|
|
|
- }
|
|
|
- }
|
|
|
+ iter := ParseString(ConfigDefault, `[{"field1": "hello"}, null, {"field2": "world"}]`)
|
|
|
+ slice := []*StructOfString{}
|
|
|
+ iter.ReadVal(&slice)
|
|
|
+ if len(slice) != 3 {
|
|
|
+ fmt.Println(iter.Error)
|
|
|
+ t.Fatal(len(slice))
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-func Benchmark_json_object(b *testing.B) {
|
|
|
- type TestObj struct {
|
|
|
- Field1 string
|
|
|
- Field2 uint64
|
|
|
+ if slice[0].Field1 != "hello" {
|
|
|
+ fmt.Println(iter.Error)
|
|
|
+ t.Fatal(slice[0])
|
|
|
+ }
|
|
|
+ if slice[1] != nil {
|
|
|
+ fmt.Println(iter.Error)
|
|
|
+ t.Fatal(slice[1])
|
|
|
}
|
|
|
- for n := 0; n < b.N; n++ {
|
|
|
- result := TestObj{}
|
|
|
- json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result)
|
|
|
+ if slice[2].Field2 != "world" {
|
|
|
+ fmt.Println(iter.Error)
|
|
|
+ t.Fatal(slice[2])
|
|
|
}
|
|
|
}
|