| 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) |
| } |
| } |