diff --git a/feature_iter.go b/feature_iter.go index 85e6275..6b921d8 100644 --- a/feature_iter.go +++ b/feature_iter.go @@ -7,7 +7,6 @@ package jsoniter import ( - "encoding/base64" "fmt" "io" ) @@ -270,19 +269,3 @@ func (iter *Iterator) Read() interface{} { return nil } } - -// ReadBase64 reads a json object as Base64 in byte slice -func (iter *Iterator) ReadBase64() (ret []byte) { - src := iter.ReadStringAsSlice() - if iter.Error != nil { - return - } - b64 := base64.StdEncoding - ret = make([]byte, b64.DecodedLen(len(src))) - n, err := b64.Decode(ret, src) - if err != nil { - iter.Error = err - return - } - return ret[:n] -} diff --git a/jsoniter_any_array_test.go b/jsoniter_any_array_test.go new file mode 100644 index 0000000..733d9b8 --- /dev/null +++ b/jsoniter_any_array_test.go @@ -0,0 +1,113 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" + "io" +) + +func Test_read_empty_array_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[]") + should.Nil(err) + should.Equal(0, any.Size()) +} + +func Test_read_one_element_array_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1]") + should.Nil(err) + should.Equal(1, any.Size()) +} + +func Test_read_two_element_array_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1,2]") + should.Nil(err) + should.Equal(1, any.Get(0).ToInt()) + should.Equal(2, any.Size()) + should.True(any.ToBool()) + should.Equal(1, any.ToInt()) +} + +func Test_read_array_with_any_iterator(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1,2]") + should.Nil(err) + var element Any + var elements []int + for next, hasNext := any.IterateArray(); hasNext; { + element, hasNext = next() + elements = append(elements, element.ToInt()) + } + should.Equal([]int{1, 2}, elements) +} + +func Test_wrap_array(t *testing.T) { + should := require.New(t) + any := Wrap([]int{1, 2, 3}) + should.Equal("[1,2,3]", any.ToString()) + var element Any + var elements []int + for next, hasNext := any.IterateArray(); hasNext; { + element, hasNext = next() + elements = append(elements, element.ToInt()) + } + should.Equal([]int{1, 2, 3}, elements) + any = Wrap([]int{1, 2, 3}) + should.Equal(3, any.Size()) + any = Wrap([]int{1, 2, 3}) + should.Equal(2, any.Get(1).ToInt()) +} + +func Test_array_lazy_any_get(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1,[2,3],4]") + should.Nil(err) + should.Equal(3, any.Get(1, 1).ToInt()) + should.Equal("[1,[2,3],4]", any.ToString()) +} + +func Test_array_lazy_any_get_all(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[[1],[2],[3,4]]") + should.Nil(err) + should.Equal("[1,2,3]", any.Get('*', 0).ToString()) +} + +func Test_array_wrapper_any_get_all(t *testing.T) { + should := require.New(t) + any := wrapArray([][]int{ + {1, 2}, + {3, 4}, + {5, 6}, + }) + should.Equal("[1,3,5]", any.Get('*', 0).ToString()) +} + +func Test_array_lazy_any_get_invalid(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[]") + should.Nil(err) + should.Equal(Invalid, any.Get(1, 1).ValueType()) + should.NotNil(any.Get(1, 1).LastError()) + should.Equal(Invalid, any.Get("1").ValueType()) + should.NotNil(any.Get("1").LastError()) +} + +func Test_array_lazy_any_set(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1,[2,3],4]") + should.Nil(err) + any.GetArray()[0] = WrapInt64(2) + str, err := MarshalToString(any) + should.Nil(err) + should.Equal("[2,[2,3],4]", str) +} + +func Test_invalid_array(t *testing.T) { + _, err := UnmarshalAnyFromString("[") + if err == nil || err == io.EOF { + t.FailNow() + } +} \ No newline at end of file diff --git a/jsoniter_any_bool_test.go b/jsoniter_any_bool_test.go new file mode 100644 index 0000000..469cd0d --- /dev/null +++ b/jsoniter_any_bool_test.go @@ -0,0 +1,13 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +func Test_read_bool_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("true") + should.Nil(err) + should.True(any.ToBool()) +} diff --git a/jsoniter_any_float_test.go b/jsoniter_any_float_test.go new file mode 100644 index 0000000..9c8f7ca --- /dev/null +++ b/jsoniter_any_float_test.go @@ -0,0 +1,15 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +func Test_read_float_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("12.3") + should.Nil(err) + should.Equal(float64(12.3), any.ToFloat64()) + should.Equal("12.3", any.ToString()) + should.True(any.ToBool()) +} diff --git a/jsoniter_any_int_test.go b/jsoniter_any_int_test.go new file mode 100644 index 0000000..dd71896 --- /dev/null +++ b/jsoniter_any_int_test.go @@ -0,0 +1,24 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" + "io" +) + +func Test_read_int64_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("1234") + should.Nil(err) + should.Equal(1234, any.ToInt()) + should.Equal(io.EOF, any.LastError()) + should.Equal("1234", any.ToString()) + should.True(any.ToBool()) +} + +func Test_int_lazy_any_get(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("1234") + should.Nil(err) + should.Equal(Invalid, any.Get(1, "2").ValueType()) +} diff --git a/jsoniter_any_map_test.go b/jsoniter_any_map_test.go new file mode 100644 index 0000000..c65553a --- /dev/null +++ b/jsoniter_any_map_test.go @@ -0,0 +1,25 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +func Test_wrap_map(t *testing.T) { + should := require.New(t) + any := Wrap(map[string]string{"Field1": "hello"}) + should.Equal("hello", any.Get("Field1").ToString()) + any = Wrap(map[string]string{"Field1": "hello"}) + should.Equal(1, any.Size()) + any = Wrap(map[string]string{"Field1": "hello"}) + 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) +} diff --git a/jsoniter_any_null_test.go b/jsoniter_any_null_test.go new file mode 100644 index 0000000..6f5d2b9 --- /dev/null +++ b/jsoniter_any_null_test.go @@ -0,0 +1,16 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +func Test_read_null_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString(`null`) + should.Nil(err) + should.Equal(0, any.ToInt()) + should.Equal(float64(0), any.ToFloat64()) + should.Equal("", any.ToString()) + should.False(any.ToBool()) +} diff --git a/jsoniter_any_object_test.go b/jsoniter_any_object_test.go new file mode 100644 index 0000000..df0302a --- /dev/null +++ b/jsoniter_any_object_test.go @@ -0,0 +1,155 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +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_any_within_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { + Field1 Any + Field2 Any + } + obj := TestObject{} + err := UnmarshalFromString(`{"Field1": "hello", "Field2": [1,2,3]}`, &obj) + should.Nil(err) + should.Equal("hello", obj.Field1.ToString()) + should.Equal("[1,2,3]", obj.Field2.ToString()) +} diff --git a/jsoniter_any_string_test.go b/jsoniter_any_string_test.go new file mode 100644 index 0000000..f6a49b6 --- /dev/null +++ b/jsoniter_any_string_test.go @@ -0,0 +1,26 @@ +package jsoniter + +import ( + "testing" + "github.com/json-iterator/go/require" +) + +func Test_read_string_as_any(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString(`"hello"`) + should.Nil(err) + should.Equal("hello", any.ToString()) + should.True(any.ToBool()) + any, err = UnmarshalAnyFromString(`" "`) + should.False(any.ToBool()) + any, err = UnmarshalAnyFromString(`"false"`) + should.False(any.ToBool()) + any, err = UnmarshalAnyFromString(`"123"`) + should.Equal(123, any.ToInt()) +} + +func Test_wrap_string(t *testing.T) { + should := require.New(t) + any := WrapString("123") + should.Equal(123, any.ToInt()) +} \ No newline at end of file diff --git a/jsoniter_array_test.go b/jsoniter_array_test.go index 962e458..c4b18e2 100644 --- a/jsoniter_array_test.go +++ b/jsoniter_array_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "github.com/json-iterator/go/require" - "io" "testing" ) @@ -45,112 +44,6 @@ func Test_two_elements(t *testing.T) { should.Equal([]interface{}{float64(1), float64(2)}, iter.Read()) } -func Test_read_empty_array_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[]") - should.Nil(err) - should.Equal(0, any.Size()) -} - -func Test_read_one_element_array_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[1]") - should.Nil(err) - should.Equal(1, any.Size()) -} - -func Test_read_two_element_array_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[1,2]") - should.Nil(err) - should.Equal(1, any.Get(0).ToInt()) - should.Equal(2, any.Size()) - should.True(any.ToBool()) - should.Equal(1, any.ToInt()) -} - -func Test_read_array_with_any_iterator(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[1,2]") - should.Nil(err) - var element Any - var elements []int - for next, hasNext := any.IterateArray(); hasNext; { - element, hasNext = next() - elements = append(elements, element.ToInt()) - } - should.Equal([]int{1, 2}, elements) -} - -func Test_wrap_array(t *testing.T) { - should := require.New(t) - any := Wrap([]int{1, 2, 3}) - should.Equal("[1,2,3]", any.ToString()) - var element Any - var elements []int - for next, hasNext := any.IterateArray(); hasNext; { - element, hasNext = next() - elements = append(elements, element.ToInt()) - } - should.Equal([]int{1, 2, 3}, elements) - any = Wrap([]int{1, 2, 3}) - should.Equal(3, any.Size()) - any = Wrap([]int{1, 2, 3}) - should.Equal(2, any.Get(1).ToInt()) -} - -func Test_array_lazy_any_get(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[1,[2,3],4]") - should.Nil(err) - should.Equal(3, any.Get(1, 1).ToInt()) - should.Equal("[1,[2,3],4]", any.ToString()) -} - -func Test_array_lazy_any_get_all(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[[1],[2],[3,4]]") - should.Nil(err) - should.Equal("[1,2,3]", any.Get('*', 0).ToString()) -} - -func Test_array_wrapper_any_get_all(t *testing.T) { - should := require.New(t) - any := wrapArray([][]int{ - {1, 2}, - {3, 4}, - {5, 6}, - }) - should.Equal("[1,3,5]", any.Get('*', 0).ToString()) -} - -func Test_array_lazy_any_get_invalid(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[]") - should.Nil(err) - should.Equal(Invalid, any.Get(1, 1).ValueType()) - should.NotNil(any.Get(1, 1).LastError()) - should.Equal(Invalid, any.Get("1").ValueType()) - should.NotNil(any.Get("1").LastError()) -} - -func Test_array_lazy_any_set(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("[1,[2,3],4]") - should.Nil(err) - any.GetArray()[0] = WrapInt64(2) - str, err := MarshalToString(any) - should.Nil(err) - should.Equal("[2,[2,3],4]", str) -} - -func Test_invalid_array(t *testing.T) { - _, err := UnmarshalAnyFromString("[") - if err == nil || err == io.EOF { - t.FailNow() - } -} - func Test_whitespace_in_head(t *testing.T) { iter := ParseString(ConfigDefault, ` [1]`) cont := iter.ReadArray() @@ -284,6 +177,20 @@ func Test_decode_byte_array(t *testing.T) { should.Equal([]byte{1, 2, 3}, data) } +func Test_decode_slice(t *testing.T) { + should := require.New(t) + slice := make([]string, 0, 5) + UnmarshalFromString(`["hello", "world"]`, &slice) + should.Equal([]string{"hello", "world"}, slice) +} + +func Test_decode_large_slice(t *testing.T) { + should := require.New(t) + slice := make([]int, 0, 1) + UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice) + should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice) +} + func Benchmark_jsoniter_array(b *testing.B) { b.ReportAllocs() input := []byte(`[1,2,3,4,5,6,7,8,9]`) diff --git a/jsoniter_bool_test.go b/jsoniter_bool_test.go index 61267e0..41d4a3a 100644 --- a/jsoniter_bool_test.go +++ b/jsoniter_bool_test.go @@ -21,13 +21,6 @@ func Test_false(t *testing.T) { should.False(iter.ReadBool()) } -func Test_read_bool_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("true") - should.Nil(err) - should.True(any.ToBool()) -} - func Test_write_true_false(t *testing.T) { should := require.New(t) buf := &bytes.Buffer{} diff --git a/jsoniter_float_test.go b/jsoniter_float_test.go index 5261f53..8ad0ea7 100644 --- a/jsoniter_float_test.go +++ b/jsoniter_float_test.go @@ -67,15 +67,6 @@ func Test_read_float_as_interface(t *testing.T) { should.Equal(float64(12.3), iter.Read()) } -func Test_read_float_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("12.3") - should.Nil(err) - should.Equal(float64(12.3), any.ToFloat64()) - should.Equal("12.3", any.ToString()) - should.True(any.ToBool()) -} - func Test_wrap_float(t *testing.T) { should := require.New(t) str, err := MarshalToString(WrapFloat64(12.3)) diff --git a/jsoniter_int_test.go b/jsoniter_int_test.go index 681358b..a547d45 100644 --- a/jsoniter_int_test.go +++ b/jsoniter_int_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "github.com/json-iterator/go/require" - "io" "io/ioutil" "strconv" "testing" @@ -116,23 +115,6 @@ func Test_read_int64_overflow(t *testing.T) { should.NotNil(iter.Error) } -func Test_read_int64_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("1234") - should.Nil(err) - should.Equal(1234, any.ToInt()) - should.Equal(io.EOF, any.LastError()) - should.Equal("1234", any.ToString()) - should.True(any.ToBool()) -} - -func Test_int_lazy_any_get(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString("1234") - should.Nil(err) - should.Equal(Invalid, any.Get(1, "2").ValueType()) -} - func Test_wrap_int(t *testing.T) { should := require.New(t) str, err := MarshalToString(WrapInt64(100)) diff --git a/jsoniter_base64_test.go b/jsoniter_iterator_test.go similarity index 99% rename from jsoniter_base64_test.go rename to jsoniter_iterator_test.go index 24167ae..7c356aa 100644 --- a/jsoniter_base64_test.go +++ b/jsoniter_iterator_test.go @@ -5,13 +5,6 @@ import ( "testing" ) -func Test_read_base64(t *testing.T) { - iter := ParseString(ConfigDefault, `"YWJj"`) - if !bytes.Equal(iter.ReadBase64(), []byte("abc")) { - t.FailNow() - } -} - func Test_bad_case(t *testing.T) { // field := *(*string)(unsafe.Pointer(&str)) // caused this issue @@ -22,7 +15,7 @@ func Test_bad_case(t *testing.T) { for iter.ReadArray() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { if field == "Bit" { - iter.ReadBase64() + iter.ReadStringAsSlice() } else { if field != "Size" && field != "EndIndex" && field != "EndMask" && field != "Good" && field != "Flush" { t.Fatal(field) diff --git a/jsoniter_map_test.go b/jsoniter_map_test.go index fda33e3..794bcb1 100644 --- a/jsoniter_map_test.go +++ b/jsoniter_map_test.go @@ -26,25 +26,6 @@ func Test_read_map_of_interface(t *testing.T) { should.Equal(map[string]interface{}{"hello": "world"}, iter.Read()) } -func Test_wrap_map(t *testing.T) { - should := require.New(t) - any := Wrap(map[string]string{"Field1": "hello"}) - should.Equal("hello", any.Get("Field1").ToString()) - any = Wrap(map[string]string{"Field1": "hello"}) - should.Equal(1, any.Size()) - any = Wrap(map[string]string{"Field1": "hello"}) - 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_map_wrapper_any_get_all(t *testing.T) { should := require.New(t) any := Wrap(map[string][]int{"Field1": {1, 2}}) diff --git a/jsoniter_null_test.go b/jsoniter_null_test.go index dcefeef..3302ba1 100644 --- a/jsoniter_null_test.go +++ b/jsoniter_null_test.go @@ -13,13 +13,6 @@ func Test_read_null(t *testing.T) { should.True(iter.ReadNil()) iter = ParseString(ConfigDefault, `null`) should.Nil(iter.Read()) - iter = ParseString(ConfigDefault, `null`) - any, err := UnmarshalAnyFromString(`null`) - should.Nil(err) - should.Equal(0, any.ToInt()) - should.Equal(float64(0), any.ToFloat64()) - should.Equal("", any.ToString()) - should.False(any.ToBool()) } func Test_write_null(t *testing.T) { diff --git a/jsoniter_object_test.go b/jsoniter_object_test.go index a2c2286..0774bc8 100644 --- a/jsoniter_object_test.go +++ b/jsoniter_object_test.go @@ -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,142 +61,6 @@ func Test_two_field(t *testing.T) { } } -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 { @@ -223,34 +87,249 @@ func Test_write_object(t *testing.T) { should.Equal("{\n \"hello\":1,\n \"world\":2\n}", buf.String()) } -func Benchmark_jsoniter_object(b *testing.B) { - type TestObj struct { +func Test_decode_one_field_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { Field1 string - Field2 uint64 - } - 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") - } - } } + obj := TestObject{} + should.Nil(UnmarshalFromString(`{}`, &obj)) + should.Equal("", obj.Field1) + should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj)) + should.Equal("hello", obj.Field1) } -func Benchmark_json_object(b *testing.B) { - type TestObj struct { +func Test_decode_two_fields_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { Field1 string - Field2 uint64 + Field2 string } - for n := 0; n < b.N; n++ { - result := TestObj{} - json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result) + 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) +} + +func Test_decode_three_fields_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { + Field1 string + Field2 string + Field3 string + } + 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_decode_four_fields_struct(t *testing.T) { + should := require.New(t) + 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) +} + +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) +} + +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) +} + +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_write_val_zero_field_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { + } + obj := TestObject{} + str, err := MarshalToString(obj) + should.Nil(err) + should.Equal(`{}`, str) +} + +func Test_write_val_one_field_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { + Field1 string `json:"field-1"` + } + obj := TestObject{"hello"} + str, err := MarshalToString(obj) + should.Nil(err) + should.Equal(`{"field-1":"hello"}`, str) +} + +func Test_mixed(t *testing.T) { + should := require.New(t) + 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(1, aa.ID) + should.Equal("123", aa.Payload["account"]) +} + +func Test_omit_empty(t *testing.T) { + should := require.New(t) + 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(`{"field-2":"hello"}`, str) +} + +func Test_recursive_struct(t *testing.T) { + should := require.New(t) + type TestObject struct { + Field1 string + Me *TestObject + } + 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_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 { + Me *AnotherObject + } + 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_anonymous_struct_marshal(t *testing.T) { + should := require.New(t) + type TestObject struct { + Field string + } + str, err := MarshalToString(struct { + TestObject + Field int + }{ + Field: 100, + }) + should.Nil(err) + should.Equal(`{"Field":100}`, str) +} + +func Test_decode_nested(t *testing.T) { + type StructOfString struct { + Field1 string + Field2 string + } + 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)) + } + 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]) + } + if slice[2].Field2 != "world" { + fmt.Println(iter.Error) + t.Fatal(slice[2]) } } diff --git a/jsoniter_reflect_struct_test.go b/jsoniter_reflect_struct_test.go deleted file mode 100644 index f00a705..0000000 --- a/jsoniter_reflect_struct_test.go +++ /dev/null @@ -1,241 +0,0 @@ -package jsoniter - -import ( - "bytes" - "github.com/json-iterator/go/require" - "testing" -) - -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) -} - -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) -} - -func Test_decode_three_fields_struct(t *testing.T) { - should := require.New(t) - type TestObject struct { - Field1 string - Field2 string - Field3 string - } - 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_decode_four_fields_struct(t *testing.T) { - should := require.New(t) - 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) -} - -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) -} - -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) -} - -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_write_val_zero_field_struct(t *testing.T) { - should := require.New(t) - type TestObject struct { - } - obj := TestObject{} - str, err := MarshalToString(obj) - should.Nil(err) - should.Equal(`{}`, str) -} - -func Test_write_val_one_field_struct(t *testing.T) { - should := require.New(t) - type TestObject struct { - Field1 string `json:"field-1"` - } - obj := TestObject{"hello"} - str, err := MarshalToString(obj) - should.Nil(err) - should.Equal(`{"field-1":"hello"}`, str) -} - -func Test_mixed(t *testing.T) { - should := require.New(t) - 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(1, aa.ID) - should.Equal("123", aa.Payload["account"]) -} - -func Test_omit_empty(t *testing.T) { - should := require.New(t) - 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(`{"field-2":"hello"}`, str) -} - -func Test_any_within_struct(t *testing.T) { - should := require.New(t) - type TestObject struct { - Field1 Any - Field2 Any - } - obj := TestObject{} - err := UnmarshalFromString(`{"Field1": "hello", "Field2": [1,2,3]}`, &obj) - should.Nil(err) - should.Equal("hello", obj.Field1.ToString()) - should.Equal("[1,2,3]", obj.Field2.ToString()) -} - -func Test_recursive_struct(t *testing.T) { - should := require.New(t) - type TestObject struct { - Field1 string - Me *TestObject - } - 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_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 { - Me *AnotherObject - } - 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_anonymous_struct_marshal(t *testing.T) { - should := require.New(t) - type TestObject struct { - Field string - } - str, err := MarshalToString(struct { - TestObject - Field int - }{ - Field: 100, - }) - should.Nil(err) - should.Equal(`{"Field":100}`, str) -} diff --git a/jsoniter_reflect_test.go b/jsoniter_reflect_test.go deleted file mode 100644 index 548aa9d..0000000 --- a/jsoniter_reflect_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "fmt" - "github.com/json-iterator/go/require" - "testing" - "unsafe" -) - -func Test_decode_slice(t *testing.T) { - should := require.New(t) - slice := make([]string, 0, 5) - UnmarshalFromString(`["hello", "world"]`, &slice) - should.Equal([]string{"hello", "world"}, slice) -} - -func Test_decode_large_slice(t *testing.T) { - should := require.New(t) - slice := make([]int, 0, 1) - UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice) - should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice) -} - -func Test_decode_nested(t *testing.T) { - type StructOfString struct { - Field1 string - Field2 string - } - 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)) - } - 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]) - } - if slice[2].Field2 != "world" { - fmt.Println(iter.Error) - t.Fatal(slice[2]) - } -} - -func Test_decode_base64(t *testing.T) { - iter := ParseString(ConfigDefault, `"YWJj"`) - val := []byte{} - RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) { - *((*[]byte)(ptr)) = iter.ReadBase64() - }) - defer ConfigDefault.CleanDecoders() - iter.ReadVal(&val) - if "abc" != string(val) { - t.Fatal(string(val)) - } -} - -type StructOfTagOne struct { - Field1 string `json:"field1"` - Field2 string `json:"field2"` - Field3 int `json:"field3,string"` - Field4 int `json:"field4,string"` -} - -func Benchmark_jsoniter_reflect(b *testing.B) { - b.ReportAllocs() - iter := NewIterator(ConfigDefault) - Struct := &StructOfTagOne{} - //var Struct *StructOfTagOne - input := []byte(`{"field3": "100", "field4": "100"}`) - //input := []byte(`null`) - for n := 0; n < b.N; n++ { - iter.ResetBytes(input) - iter.ReadVal(&Struct) - } -} - -func Benchmark_jsoniter_direct(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - //iter := ParseString(`{"field1": "hello", "field2": "world"}`) - //struct_ := StructOfString{} - //for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { - // switch field { - // case "field1": - // struct_.Field1 = iter.ReadString() - // case "field2": - // struct_.Field2 = iter.ReadString() - // default: - // iter.Skip() - // } - //} - iter := ParseString(ConfigDefault, `["hello", "world"]`) - array := make([]string, 0, 2) - for iter.ReadArray() { - array = append(array, iter.ReadString()) - } - } -} - -func Benchmark_json_reflect(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Struct := StructOfTagOne{} - json.Unmarshal([]byte(`{"field3": "100"}`), &Struct) - //array := make([]string, 0, 2) - //json.Unmarshal([]byte(`["hello", "world"]`), &array) - } -} diff --git a/jsoniter_string_test.go b/jsoniter_string_test.go index 6ac88d4..da84b9f 100644 --- a/jsoniter_string_test.go +++ b/jsoniter_string_test.go @@ -66,26 +66,6 @@ func Test_read_string_as_interface(t *testing.T) { should.Equal("hello", iter.Read()) } -func Test_read_string_as_any(t *testing.T) { - should := require.New(t) - any, err := UnmarshalAnyFromString(`"hello"`) - should.Nil(err) - should.Equal("hello", any.ToString()) - should.True(any.ToBool()) - any, err = UnmarshalAnyFromString(`" "`) - should.False(any.ToBool()) - any, err = UnmarshalAnyFromString(`"false"`) - should.False(any.ToBool()) - any, err = UnmarshalAnyFromString(`"123"`) - should.Equal(123, any.ToInt()) -} - -func Test_wrap_string(t *testing.T) { - should := require.New(t) - any := WrapString("123") - should.Equal(123, any.ToInt()) -} - func Test_write_string(t *testing.T) { should := require.New(t) str, err := MarshalToString("hello")