package jsoniter import ( "bytes" "encoding/json" "github.com/json-iterator/go/require" "testing" ) func Test_empty_object(t *testing.T) { should := require.New(t) iter := ParseString(`{}`) field := iter.ReadObject() should.Equal("", field) iter = ParseString(`{}`) iter.ReadObjectCB(func(iter *Iterator, field string) bool { should.FailNow("should not call") return true }) } func Test_one_field(t *testing.T) { should := require.New(t) iter := ParseString(`{"a": "b"}`) field := iter.ReadObject() should.Equal("a", field) value := iter.ReadString() should.Equal("b", value) field = iter.ReadObject() should.Equal("", field) iter = ParseString(`{"a": "b"}`) should.True(iter.ReadObjectCB(func(iter *Iterator, field string) bool { should.Equal("a", field) return true })) } func Test_two_field(t *testing.T) { should := require.New(t) iter := ParseString(`{ "a": "b" , "c": "d" }`) field := iter.ReadObject() should.Equal("a", field) value := iter.ReadString() should.Equal("b", value) field = iter.ReadObject() should.Equal("c", field) value = iter.ReadString() should.Equal("d", value) field = iter.ReadObject() should.Equal("", field) iter = ParseString(`{"field1": "1", "field2": 2}`) for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { switch field { case "field1": iter.ReadString() case "field2": iter.ReadInt64() default: iter.reportError("bind object", "unexpected field") } } } func Test_read_object_as_any(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()) } func Test_object_any_lazy_iterator(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() // trigger full parse should.Equal(2, len(any.Keys())) k, v, hasNext = next() should.False(hasNext) vals[k] = v.ToString() 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() } } should.Equal(map[string]string{"a": "b", "c": "d"}, vals) } func Test_object_any_with_two_lazy_iterators(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()) should.True(hasNext2) k, v, hasNext2 = next2() should.True(hasNext2) should.Equal("a", k) should.Equal("b", v.ToString()) k, v, hasNext1 = next1() should.True(hasNext1) should.Equal("c", k) should.Equal("d", v.ToString()) k, v, hasNext2 = next2() should.True(hasNext2) should.Equal("c", k) should.Equal("d", v.ToString()) } func Test_object_lazy_any_get(t *testing.T) { should := require.New(t) any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`) should.Nil(err) should.Equal("d", any.Get("a", "b", "c").ToString()) } func Test_object_lazy_any_get_all(t *testing.T) { should := require.New(t) any, err := UnmarshalAnyFromString(`{"a":[0],"b":[1]}`) should.Nil(err) should.Contains(any.Get('*', 0).ToString(), `"a":0`) } func Test_object_lazy_any_get_invalid(t *testing.T) { should := require.New(t) any, err := UnmarshalAnyFromString(`{}`) should.Nil(err) should.Equal(Invalid, any.Get("a", "b", "c").ValueType()) should.Equal(Invalid, any.Get(1).ValueType()) } func Test_object_lazy_any_set(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) should.Nil(err) should.Equal(`{"a":1}`, str) } func Test_wrap_object(t *testing.T) { should := require.New(t) type TestObject struct { Field1 string field2 string } 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) } func Test_object_wrapper_any_get_all(t *testing.T) { should := require.New(t) 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_write_object(t *testing.T) { should := require.New(t) buf := &bytes.Buffer{} stream := NewStream(buf, 4096) stream.IndentionStep = 2 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()) } func Benchmark_jsoniter_object(b *testing.B) { type TestObj struct { Field1 string Field2 uint64 } for n := 0; n < b.N; n++ { iter := ParseString(`{"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") } } } } func Benchmark_json_object(b *testing.B) { type TestObj struct { Field1 string Field2 uint64 } for n := 0; n < b.N; n++ { result := TestObj{} json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result) } }