Browse Source

consolidate more tests

Tao Wen 7 năm trước cách đây
mục cha
commit
477be43d00

+ 37 - 36
jsoniter_wrap_test.go → any_tests/jsoniter_wrap_test.go

@@ -1,116 +1,117 @@
-package jsoniter
+package any_tests
 
 import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	"github.com/json-iterator/go"
 )
 
 func Test_wrap_and_valuetype_everything(t *testing.T) {
 	should := require.New(t)
 	var i interface{}
-	any := Get([]byte("123"))
+	any := jsoniter.Get([]byte("123"))
 	// default of number type is float64
 	i = float64(123)
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(int8(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(int8(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	//  get interface is not int8 interface
 	// i = int8(10)
 	// should.Equal(i, any.GetInterface())
 
-	any = Wrap(int16(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(int16(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	//i = int16(10)
 	//should.Equal(i, any.GetInterface())
 
-	any = Wrap(int32(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(int32(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	i = int32(10)
 	should.Equal(i, any.GetInterface())
-	any = Wrap(int64(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(int64(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	i = int64(10)
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(uint(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(uint(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	// not equal
 	//i = uint(10)
 	//should.Equal(i, any.GetInterface())
-	any = Wrap(uint8(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(uint8(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	// not equal
 	// i = uint8(10)
 	// should.Equal(i, any.GetInterface())
-	any = Wrap(uint16(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(uint16(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
-	any = Wrap(uint32(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(uint32(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	i = uint32(10)
 	should.Equal(i, any.GetInterface())
-	any = Wrap(uint64(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(uint64(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	i = uint64(10)
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(float32(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(float32(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	// not equal
 	//i = float32(10)
 	//should.Equal(i, any.GetInterface())
-	any = Wrap(float64(10))
-	should.Equal(any.ValueType(), NumberValue)
+	any = jsoniter.Wrap(float64(10))
+	should.Equal(any.ValueType(), jsoniter.NumberValue)
 	should.Equal(any.LastError(), nil)
 	i = float64(10)
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(true)
-	should.Equal(any.ValueType(), BoolValue)
+	any = jsoniter.Wrap(true)
+	should.Equal(any.ValueType(), jsoniter.BoolValue)
 	should.Equal(any.LastError(), nil)
 	i = true
 	should.Equal(i, any.GetInterface())
-	any = Wrap(false)
-	should.Equal(any.ValueType(), BoolValue)
+	any = jsoniter.Wrap(false)
+	should.Equal(any.ValueType(), jsoniter.BoolValue)
 	should.Equal(any.LastError(), nil)
 	i = false
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(nil)
-	should.Equal(any.ValueType(), NilValue)
+	any = jsoniter.Wrap(nil)
+	should.Equal(any.ValueType(), jsoniter.NilValue)
 	should.Equal(any.LastError(), nil)
 	i = nil
 	should.Equal(i, any.GetInterface())
 
-	stream := NewStream(ConfigDefault, nil, 32)
+	stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 32)
 	any.WriteTo(stream)
 	should.Equal("null", string(stream.Buffer()))
 	should.Equal(any.LastError(), nil)
 
-	any = Wrap(struct{ age int }{age: 1})
-	should.Equal(any.ValueType(), ObjectValue)
+	any = jsoniter.Wrap(struct{ age int }{age: 1})
+	should.Equal(any.ValueType(), jsoniter.ObjectValue)
 	should.Equal(any.LastError(), nil)
 	i = struct{ age int }{age: 1}
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap(map[string]interface{}{"abc": 1})
-	should.Equal(any.ValueType(), ObjectValue)
+	any = jsoniter.Wrap(map[string]interface{}{"abc": 1})
+	should.Equal(any.ValueType(), jsoniter.ObjectValue)
 	should.Equal(any.LastError(), nil)
 	i = map[string]interface{}{"abc": 1}
 	should.Equal(i, any.GetInterface())
 
-	any = Wrap("abc")
+	any = jsoniter.Wrap("abc")
 	i = "abc"
 	should.Equal(i, any.GetInterface())
 	should.Equal(nil, any.LastError())

+ 1 - 1
jsoniter_sloppy_test.go → feature_iter_skip_sloppy_test.go

@@ -1,4 +1,4 @@
-//+build jsoniter-sloppy
+//+build jsoniter_sloppy
 
 package jsoniter
 

+ 0 - 0
jsoniter_stream_test.go → feature_stream_test.go


+ 0 - 57
jsoniter_reader_test.go

@@ -1,57 +0,0 @@
-package jsoniter
-
-import (
-	"github.com/stretchr/testify/require"
-	"strings"
-	"testing"
-	"time"
-)
-
-func Test_reader_and_load_more(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		CreatedAt time.Time
-	}
-	reader := strings.NewReader(`
-{
-	"agency": null,
-	"candidateId": 0,
-	"candidate": "Blah Blah",
-	"bookingId": 0,
-	"shiftId": 1,
-	"shiftTypeId": 0,
-	"shift": "Standard",
-	"bonus": 0,
-	"bonusNI": 0,
-	"days": [],
-	"totalHours": 27,
-	"expenses": [],
-	"weekEndingDateSystem": "2016-10-09",
-	"weekEndingDateClient": "2016-10-09",
-	"submittedAt": null,
-	"submittedById": null,
-	"approvedAt": "2016-10-10T18:38:04Z",
-	"approvedById": 0,
-	"authorisedAt": "2016-10-10T18:38:04Z",
-	"authorisedById": 0,
-	"invoicedAt": "2016-10-10T20:00:00Z",
-	"revokedAt": null,
-	"revokedById": null,
-	"revokeReason": null,
-	"rejectedAt": null,
-	"rejectedById": null,
-	"rejectReasonCode": null,
-	"rejectReason": null,
-	"createdAt": "2016-10-03T00:00:00Z",
-	"updatedAt": "2016-11-09T10:26:13Z",
-	"updatedById": null,
-	"overrides": [],
-	"bookingApproverId": null,
-	"bookingApprover": null,
-	"status": "approved"
-}
-	`)
-	decoder := ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
-	obj := TestObject{}
-	should.Nil(decoder.Decode(&obj))
-}

+ 0 - 154
jsoniter_reflect_native_test.go

@@ -1,154 +0,0 @@
-package jsoniter
-
-import (
-	"fmt"
-	"testing"
-)
-
-func Test_reflect_str(t *testing.T) {
-	iter := ParseString(ConfigDefault, `"hello"`)
-	str := ""
-	iter.ReadVal(&str)
-	if str != "hello" {
-		fmt.Println(iter.Error)
-		t.Fatal(str)
-	}
-}
-
-func Test_reflect_ptr_str(t *testing.T) {
-	iter := ParseString(ConfigDefault, `"hello"`)
-	var str *string
-	iter.ReadVal(&str)
-	if *str != "hello" {
-		t.Fatal(str)
-	}
-}
-
-func Test_reflect_int(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := int(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_int8(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := int8(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_int16(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := int16(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_int32(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := int32(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_int64(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := int64(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_uint(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := uint(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_uint8(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := uint8(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_uint16(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := uint16(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_uint32(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := uint32(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_uint64(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := uint64(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_byte(t *testing.T) {
-	iter := ParseString(ConfigDefault, `123`)
-	val := byte(0)
-	iter.ReadVal(&val)
-	if val != 123 {
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_float32(t *testing.T) {
-	iter := ParseString(ConfigDefault, `1.23`)
-	val := float32(0)
-	iter.ReadVal(&val)
-	if val != 1.23 {
-		fmt.Println(iter.Error)
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_float64(t *testing.T) {
-	iter := ParseString(ConfigDefault, `1.23`)
-	val := float64(0)
-	iter.ReadVal(&val)
-	if val != 1.23 {
-		fmt.Println(iter.Error)
-		t.Fatal(val)
-	}
-}
-
-func Test_reflect_bool(t *testing.T) {
-	iter := ParseString(ConfigDefault, `true`)
-	val := false
-	iter.ReadVal(&val)
-	if val != true {
-		fmt.Println(iter.Error)
-		t.Fatal(val)
-	}
-}

+ 0 - 261
jsoniter_string_test.go

@@ -1,261 +0,0 @@
-// +build go1.8
-
-package jsoniter
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"testing"
-	"unicode/utf8"
-
-	"github.com/stretchr/testify/require"
-)
-
-func Test_read_string(t *testing.T) {
-	badInputs := []string{
-		``,
-		`"`,
-		`"\"`,
-		`"\\\"`,
-		"\"\n\"",
-		`"\U0001f64f"`,
-		`"\uD83D\u00"`,
-	}
-	for i := 0; i < 32; i++ {
-		// control characters are invalid
-		badInputs = append(badInputs, string([]byte{'"', byte(i), '"'}))
-	}
-
-	for _, input := range badInputs {
-		testReadString(t, input, "", true, "json.Unmarshal", json.Unmarshal)
-		testReadString(t, input, "", true, "jsoniter.Unmarshal", Unmarshal)
-		testReadString(t, input, "", true, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", ConfigCompatibleWithStandardLibrary.Unmarshal)
-	}
-
-	goodInputs := []struct {
-		input       string
-		expectValue string
-	}{
-		{`""`, ""},
-		{`"a"`, "a"},
-		{`null`, ""},
-		{`"Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"`, "Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"},
-		{`"\uD83D"`, string([]byte{239, 191, 189})},
-		{`"\uD83D\\"`, string([]byte{239, 191, 189, '\\'})},
-		{`"\uD83D\ub000"`, string([]byte{239, 191, 189, 235, 128, 128})},
-		{`"\uD83D\ude04"`, "😄"},
-		{`"\uDEADBEEF"`, string([]byte{239, 191, 189, 66, 69, 69, 70})},
-	}
-
-	for _, tc := range goodInputs {
-		testReadString(t, tc.input, tc.expectValue, false, "json.Unmarshal", json.Unmarshal)
-		testReadString(t, tc.input, tc.expectValue, false, "jsoniter.Unmarshal", Unmarshal)
-		testReadString(t, tc.input, tc.expectValue, false, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", ConfigCompatibleWithStandardLibrary.Unmarshal)
-	}
-}
-
-func testReadString(t *testing.T, input string, expectValue string, expectError bool, marshalerName string, marshaler func([]byte, interface{}) error) {
-	var value string
-	err := marshaler([]byte(input), &value)
-	if expectError != (err != nil) {
-		t.Errorf("%q: %s: expected error %v, got %v", input, marshalerName, expectError, err)
-		return
-	}
-	if value != expectValue {
-		t.Errorf("%q: %s: expected %q, got %q", input, marshalerName, expectValue, value)
-		return
-	}
-}
-
-func Test_read_normal_string(t *testing.T) {
-	cases := map[string]string{
-		`"0123456789012345678901234567890123456789"`: `0123456789012345678901234567890123456789`,
-		`""`:      ``,
-		`"hello"`: `hello`,
-	}
-	for input, output := range cases {
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := ParseString(ConfigDefault, input)
-			should.Equal(output, iter.ReadString())
-		})
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2)
-			should.Equal(output, iter.ReadString())
-		})
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := ParseString(ConfigDefault, input)
-			should.Equal(output, string(iter.ReadStringAsSlice()))
-		})
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2)
-			should.Equal(output, string(iter.ReadStringAsSlice()))
-		})
-	}
-}
-
-func Test_read_exotic_string(t *testing.T) {
-	cases := map[string]string{
-		`"hel\"lo"`:      `hel"lo`,
-		`"hel\\\/lo"`:    `hel\/lo`,
-		`"hel\\blo"`:     `hel\blo`,
-		`"hel\\\blo"`:    "hel\\\blo",
-		`"hel\\nlo"`:     `hel\nlo`,
-		`"hel\\\nlo"`:    "hel\\\nlo",
-		`"hel\\tlo"`:     `hel\tlo`,
-		`"hel\\flo"`:     `hel\flo`,
-		`"hel\\\flo"`:    "hel\\\flo",
-		`"hel\\\rlo"`:    "hel\\\rlo",
-		`"hel\\\tlo"`:    "hel\\\tlo",
-		`"\u4e2d\u6587"`: "中文",
-		`"\ud83d\udc4a"`: "\xf0\x9f\x91\x8a", // surrogate
-	}
-	for input, output := range cases {
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := ParseString(ConfigDefault, input)
-			var v string
-			should.Nil(json.Unmarshal([]byte(input), &v))
-			should.Equal(v, iter.ReadString())
-		})
-		t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
-			should := require.New(t)
-			iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2)
-			should.Equal(output, iter.ReadString())
-		})
-	}
-}
-
-func Test_read_string_as_interface(t *testing.T) {
-	should := require.New(t)
-	iter := ParseString(ConfigDefault, `"hello"`)
-	should.Equal("hello", iter.Read())
-}
-
-func Test_write_string(t *testing.T) {
-	should := require.New(t)
-	str, err := MarshalToString("hello")
-	should.Equal(`"hello"`, str)
-	should.Nil(err)
-	str, err = MarshalToString(`hel"lo`)
-	should.Equal(`"hel\"lo"`, str)
-	should.Nil(err)
-}
-
-func Test_write_val_string(t *testing.T) {
-	should := require.New(t)
-	buf := &bytes.Buffer{}
-	stream := NewStream(ConfigDefault, buf, 4096)
-	stream.WriteVal("hello")
-	stream.Flush()
-	should.Nil(stream.Error)
-	should.Equal(`"hello"`, buf.String())
-}
-
-func Test_decode_slash(t *testing.T) {
-	should := require.New(t)
-	var obj interface{}
-	should.NotNil(json.Unmarshal([]byte("\\"), &obj))
-	should.NotNil(UnmarshalFromString("\\", &obj))
-}
-
-func Test_html_escape(t *testing.T) {
-	should := require.New(t)
-	output, err := json.Marshal(`>`)
-	should.Nil(err)
-	should.Equal(`"\u003e"`, string(output))
-	output, err = ConfigCompatibleWithStandardLibrary.Marshal(`>`)
-	should.Nil(err)
-	should.Equal(`"\u003e"`, string(output))
-	type MyString string
-	output, err = ConfigCompatibleWithStandardLibrary.Marshal(MyString(`>`))
-	should.Nil(err)
-	should.Equal(`"\u003e"`, string(output))
-}
-
-func Test_string_encode_with_std(t *testing.T) {
-	should := require.New(t)
-	for i := 0; i < utf8.RuneSelf; i++ {
-		input := string([]byte{byte(i)})
-		stdOutputBytes, err := json.Marshal(input)
-		should.Nil(err)
-		stdOutput := string(stdOutputBytes)
-		jsoniterOutputBytes, err := ConfigCompatibleWithStandardLibrary.Marshal(input)
-		should.Nil(err)
-		jsoniterOutput := string(jsoniterOutputBytes)
-		should.Equal(stdOutput, jsoniterOutput)
-	}
-}
-
-func Test_unicode(t *testing.T) {
-	should := require.New(t)
-	output, _ := MarshalToString(map[string]interface{}{"a": "数字山谷"})
-	should.Equal(`{"a":"数字山谷"}`, output)
-	output, _ = Config{EscapeHTML: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"})
-	should.Equal(`{"a":"数字山谷"}`, output)
-}
-
-func Test_unicode_and_escape(t *testing.T) {
-	should := require.New(t)
-	output, err := MarshalToString(`"数字山谷"`)
-	should.Nil(err)
-	should.Equal(`"\"数字山谷\""`, output)
-	output, err = ConfigFastest.MarshalToString(`"数字山谷"`)
-	should.Nil(err)
-	should.Equal(`"\"数字山谷\""`, output)
-}
-
-func Test_unsafe_unicode(t *testing.T) {
-	ConfigDefault.(*frozenConfig).cleanEncoders()
-	should := require.New(t)
-	output, err := ConfigDefault.MarshalToString("he\u2029\u2028he")
-	should.Nil(err)
-	should.Equal(`"he\u2029\u2028he"`, output)
-	output, err = ConfigFastest.MarshalToString("he\u2029\u2028he")
-	should.Nil(err)
-	should.Equal("\"he\u2029\u2028he\"", output)
-}
-
-func Benchmark_jsoniter_unicode(b *testing.B) {
-	for n := 0; n < b.N; n++ {
-		iter := ParseString(ConfigDefault, `"\ud83d\udc4a"`)
-		iter.ReadString()
-	}
-}
-
-func Benchmark_jsoniter_ascii(b *testing.B) {
-	iter := NewIterator(ConfigDefault)
-	input := []byte(`"hello, world! hello, world!"`)
-	b.ResetTimer()
-	for n := 0; n < b.N; n++ {
-		iter.ResetBytes(input)
-		iter.ReadString()
-	}
-}
-
-func Benchmark_jsoniter_string_as_bytes(b *testing.B) {
-	iter := ParseString(ConfigDefault, `"hello, world!"`)
-	b.ResetTimer()
-	for n := 0; n < b.N; n++ {
-		iter.ResetBytes(iter.buf)
-		iter.ReadStringAsSlice()
-	}
-}
-
-func Benchmark_json_unicode(b *testing.B) {
-	for n := 0; n < b.N; n++ {
-		result := ""
-		json.Unmarshal([]byte(`"\ud83d\udc4a"`), &result)
-	}
-}
-
-func Benchmark_json_ascii(b *testing.B) {
-	for n := 0; n < b.N; n++ {
-		result := ""
-		json.Unmarshal([]byte(`"hello"`), &result)
-	}
-}

+ 0 - 267
jsoniter_struct_decoder_test.go

@@ -1,267 +0,0 @@
-package jsoniter
-
-import (
-	"github.com/stretchr/testify/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": "stream"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", 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": "stream", "Field3": "c"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", 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": "stream", "Field3": "c", "Field4": "d"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", 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": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-}
-
-func Test_decode_six_fields_struct(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		Field1 string
-		Field2 string
-		Field3 string
-		Field4 string
-		Field5 string
-		Field6 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.Field1)
-	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal("x", obj.Field6)
-}
-
-func Test_decode_seven_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
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.Field1)
-	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x", "Field7":"y"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal("x", obj.Field6)
-	should.Equal("y", obj.Field7)
-}
-
-func Test_decode_eight_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
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.Field1)
-	should.Nil(UnmarshalFromString(`{"Field8":"1", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x", "Field7":"y"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal("x", obj.Field6)
-	should.Equal("y", obj.Field7)
-	should.Equal("1", obj.Field8)
-}
-
-func Test_decode_nine_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
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.Field1)
-	should.Nil(UnmarshalFromString(`{"Field8" : "zzzzzzzzzzz", "Field7": "zz", "Field6" : "xx", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field9":"f"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal("xx", obj.Field6)
-	should.Equal("zz", obj.Field7)
-	should.Equal("zzzzzzzzzzz", obj.Field8)
-	should.Equal("f", obj.Field9)
-}
-
-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(`{"Field10":"x", "Field9": "x", "Field8":"x", "Field7":"x", "Field6":"x", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal("x", obj.Field6)
-	should.Equal("x", obj.Field7)
-	should.Equal("x", obj.Field8)
-	should.Equal("x", obj.Field9)
-	should.Equal("x", obj.Field10)
-}
-
-func Test_decode_more_than_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
-		Field11 int
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.Field1)
-	should.Nil(UnmarshalFromString(`{"field11":1, "field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
-	should.Equal("a", obj.Field1)
-	should.Equal("stream", obj.Field2)
-	should.Equal("c", obj.Field3)
-	should.Equal("d", obj.Field4)
-	should.Equal("e", obj.Field5)
-	should.Equal(1, obj.Field11)
-}
-
-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_decode_struct_field_with_tag_string(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		Field1 int `json:",string"`
-	}
-	obj := TestObject{Field1: 100}
-	should.Nil(UnmarshalFromString(`{"Field1": "100"}`, &obj))
-	should.Equal(100, obj.Field1)
-}

+ 0 - 52
jsoniter_struct_encoder_test.go

@@ -1,52 +0,0 @@
-package jsoniter
-
-import (
-	"encoding/json"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/require"
-)
-
-func Test_encode_unexported_field(t *testing.T) {
-	type TestData struct {
-		a int
-		b <-chan int
-		C int
-		d *time.Timer
-	}
-
-	should := require.New(t)
-
-	testChan := make(<-chan int, 10)
-	testTimer := time.NewTimer(10 * time.Second)
-
-	obj := &TestData{
-		a: 42,
-		b: testChan,
-		C: 21,
-		d: testTimer,
-	}
-
-	jb, err := json.Marshal(obj)
-	should.NoError(err)
-	should.Equal([]byte(`{"C":21}`), jb)
-
-	err = json.Unmarshal([]byte(`{"a": 444, "b":"bad", "C":55, "d":{"not": "a timer"}}`), obj)
-	should.NoError(err)
-	should.Equal(42, obj.a)
-	should.Equal(testChan, obj.b)
-	should.Equal(55, obj.C)
-	should.Equal(testTimer, obj.d)
-
-	jb, err = Marshal(obj)
-	should.NoError(err)
-	should.Equal(jb, []byte(`{"C":55}`))
-
-	err = Unmarshal([]byte(`{"a": 444, "b":"bad", "C":256, "d":{"not":"a timer"}}`), obj)
-	should.NoError(err)
-	should.Equal(42, obj.a)
-	should.Equal(testChan, obj.b)
-	should.Equal(256, obj.C)
-	should.Equal(testTimer, obj.d)
-}

+ 51 - 0
misc_tests/jsoniter_object_test.go

@@ -6,6 +6,8 @@ import (
 
 	"github.com/stretchr/testify/require"
 	"github.com/json-iterator/go"
+	"time"
+	"strings"
 )
 
 func Test_empty_object(t *testing.T) {
@@ -78,4 +80,53 @@ func Test_write_object(t *testing.T) {
 	stream.Flush()
 	should.Nil(stream.Error)
 	should.Equal("{\n  \"hello\": 1,\n  \"world\": 2\n}", buf.String())
+}
+
+func Test_reader_and_load_more(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		CreatedAt time.Time
+	}
+	reader := strings.NewReader(`
+{
+	"agency": null,
+	"candidateId": 0,
+	"candidate": "Blah Blah",
+	"bookingId": 0,
+	"shiftId": 1,
+	"shiftTypeId": 0,
+	"shift": "Standard",
+	"bonus": 0,
+	"bonusNI": 0,
+	"days": [],
+	"totalHours": 27,
+	"expenses": [],
+	"weekEndingDateSystem": "2016-10-09",
+	"weekEndingDateClient": "2016-10-09",
+	"submittedAt": null,
+	"submittedById": null,
+	"approvedAt": "2016-10-10T18:38:04Z",
+	"approvedById": 0,
+	"authorisedAt": "2016-10-10T18:38:04Z",
+	"authorisedById": 0,
+	"invoicedAt": "2016-10-10T20:00:00Z",
+	"revokedAt": null,
+	"revokedById": null,
+	"revokeReason": null,
+	"rejectedAt": null,
+	"rejectedById": null,
+	"rejectReasonCode": null,
+	"rejectReason": null,
+	"createdAt": "2016-10-03T00:00:00Z",
+	"updatedAt": "2016-11-09T10:26:13Z",
+	"updatedById": null,
+	"overrides": [],
+	"bookingApproverId": null,
+	"bookingApprover": null,
+	"status": "approved"
+}
+	`)
+	decoder := jsoniter.ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
+	obj := TestObject{}
+	should.Nil(decoder.Decode(&obj))
 }

+ 14 - 13
jsoniter_skip_test.go → skip_tests/jsoniter_skip_test.go

@@ -1,4 +1,4 @@
-package jsoniter
+package skip_tests
 
 import (
 	"bytes"
@@ -6,11 +6,12 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	"github.com/json-iterator/go"
 )
 
 func Test_skip_number_in_array(t *testing.T) {
 	should := require.New(t)
-	iter := ParseString(ConfigDefault, `[-0.12, "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[-0.12, "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -20,7 +21,7 @@ func Test_skip_number_in_array(t *testing.T) {
 
 func Test_skip_string_in_array(t *testing.T) {
 	should := require.New(t)
-	iter := ParseString(ConfigDefault, `["hello", "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `["hello", "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -29,7 +30,7 @@ func Test_skip_string_in_array(t *testing.T) {
 }
 
 func Test_skip_null(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[null , "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null , "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -39,7 +40,7 @@ func Test_skip_null(t *testing.T) {
 }
 
 func Test_skip_true(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[true , "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[true , "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -49,7 +50,7 @@ func Test_skip_true(t *testing.T) {
 }
 
 func Test_skip_false(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[false , "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[false , "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -59,7 +60,7 @@ func Test_skip_false(t *testing.T) {
 }
 
 func Test_skip_array(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[[1, [2, [3], 4]], "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[[1, [2, [3], 4]], "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -69,7 +70,7 @@ func Test_skip_array(t *testing.T) {
 }
 
 func Test_skip_empty_array(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[ [ ], "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ [ ], "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -79,7 +80,7 @@ func Test_skip_empty_array(t *testing.T) {
 }
 
 func Test_skip_nested(t *testing.T) {
-	iter := ParseString(ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
 	iter.ReadArray()
 	iter.Skip()
 	iter.ReadArray()
@@ -90,7 +91,7 @@ func Test_skip_nested(t *testing.T) {
 
 func Test_skip_and_return_bytes(t *testing.T) {
 	should := require.New(t)
-	iter := ParseString(ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
+	iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
 	iter.ReadArray()
 	skipped := iter.SkipAndReturnBytes()
 	should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
@@ -98,7 +99,7 @@ func Test_skip_and_return_bytes(t *testing.T) {
 
 func Test_skip_and_return_bytes_with_reader(t *testing.T) {
 	should := require.New(t)
-	iter := Parse(ConfigDefault, bytes.NewBufferString(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`), 4)
+	iter := jsoniter.Parse(jsoniter.ConfigDefault, bytes.NewBufferString(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`), 4)
 	iter.ReadArray()
 	skipped := iter.SkipAndReturnBytes()
 	should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
@@ -106,7 +107,7 @@ func Test_skip_and_return_bytes_with_reader(t *testing.T) {
 
 func Test_skip_empty(t *testing.T) {
 	should := require.New(t)
-	should.NotNil(Get([]byte("")).LastError())
+	should.NotNil(jsoniter.Get([]byte("")).LastError())
 }
 
 type TestResp struct {
@@ -140,7 +141,7 @@ func Benchmark_jsoniter_skip(b *testing.B) {
 }`)
 	for n := 0; n < b.N; n++ {
 		result := TestResp{}
-		iter := ParseBytes(ConfigDefault, input)
+		iter := jsoniter.ParseBytes(jsoniter.ConfigDefault, input)
 		for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
 			switch field {
 			case "code":

+ 94 - 0
type_tests/struct_test.go

@@ -3,6 +3,7 @@ package test
 import "time"
 
 func init() {
+	structFields1To11()
 	testCases = append(testCases,
 		(*struct1Alias)(nil),
 		(*struct {
@@ -258,6 +259,99 @@ func init() {
 	)
 }
 
+func structFields1To11() {
+	testCases = append(testCases,
+		(*struct {
+			Field1 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+			Field7 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+			Field7 string
+			Field8 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+			Field7 string
+			Field8 string
+			Field9 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+			Field7 string
+			Field8 string
+			Field9 string
+			Field10 string
+		})(nil),
+		(*struct {
+			Field1 string
+			Field2 string
+			Field3 string
+			Field4 string
+			Field5 string
+			Field6 string
+			Field7 string
+			Field8 string
+			Field9 string
+			Field10 string
+			Field11 string
+		})(nil),
+	)
+}
+
 type struct1 struct {
 	Byte1   byte
 	Byte2   byte

+ 0 - 72
unmarshal_input_test.go

@@ -1,72 +0,0 @@
-package jsoniter
-
-import (
-	"encoding/json"
-	"reflect"
-	"testing"
-
-	fuzz "github.com/google/gofuzz"
-)
-
-func Test_NilInput(t *testing.T) {
-	var jb []byte // nil
-	var out string
-	err := Unmarshal(jb, &out)
-	if err == nil {
-		t.Errorf("Expected error")
-	}
-}
-
-func Test_EmptyInput(t *testing.T) {
-	jb := []byte("")
-	var out string
-	err := Unmarshal(jb, &out)
-	if err == nil {
-		t.Errorf("Expected error")
-	}
-}
-
-func Test_RandomInput_Bytes(t *testing.T) {
-	fz := fuzz.New().NilChance(0)
-	for i := 0; i < 10000; i++ {
-		var jb []byte
-		fz.Fuzz(&jb)
-		testRandomInput(t, jb)
-	}
-}
-
-func Test_RandomInput_String(t *testing.T) {
-	fz := fuzz.New().NilChance(0)
-	for i := 0; i < 10000; i++ {
-		var js string
-		fz.Fuzz(&js)
-		jb := []byte(js)
-		testRandomInput(t, jb)
-	}
-}
-
-func testRandomInput(t *testing.T, jb []byte) {
-	var outString string
-	testRandomInputTo(t, jb, &outString)
-
-	var outInt int
-	testRandomInputTo(t, jb, &outInt)
-
-	var outStruct struct{}
-	testRandomInputTo(t, jb, &outStruct)
-
-	var outSlice []string
-	testRandomInputTo(t, jb, &outSlice)
-}
-
-func testRandomInputTo(t *testing.T, jb []byte, out interface{}) {
-	err := Unmarshal(jb, out)
-	if err == nil {
-		// Cross-check stdlib to see if we just happened to fuzz a legit value.
-		err := json.Unmarshal(jb, out)
-		if err != nil {
-			t.Fatalf("Expected error unmarshaling as %s:\nas string: %q\nas bytes: %v",
-				reflect.TypeOf(out).Elem().Kind(), string(jb), jb)
-		}
-	}
-}

+ 25 - 0
value_tests/invalid_test.go

@@ -199,3 +199,28 @@ func TestDecodeErrorType(t *testing.T) {
 	should.Nil(jsoniter.Unmarshal([]byte("null"), &err))
 	should.NotNil(jsoniter.Unmarshal([]byte("123"), &err))
 }
+
+func Test_decode_slash(t *testing.T) {
+	should := require.New(t)
+	var obj interface{}
+	should.NotNil(json.Unmarshal([]byte("\\"), &obj))
+	should.NotNil(jsoniter.UnmarshalFromString("\\", &obj))
+}
+
+func Test_NilInput(t *testing.T) {
+	var jb []byte // nil
+	var out string
+	err := jsoniter.Unmarshal(jb, &out)
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+}
+
+func Test_EmptyInput(t *testing.T) {
+	jb := []byte("")
+	var out string
+	err := jsoniter.Unmarshal(jb, &out)
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+}

+ 88 - 0
value_tests/string_test.go

@@ -0,0 +1,88 @@
+package test
+
+import (
+	"testing"
+	"github.com/json-iterator/go"
+	"encoding/json"
+	"unicode/utf8"
+)
+
+func init() {
+	marshalCases = append(marshalCases,
+		`>`,
+		`"数字山谷"`,
+		"he\u2029\u2028he",
+	)
+	for i := 0; i < utf8.RuneSelf; i++ {
+		marshalCases = append(marshalCases, string([]byte{byte(i)}))
+	}
+}
+
+func Test_read_string(t *testing.T) {
+	badInputs := []string{
+		``,
+		`"`,
+		`"\"`,
+		`"\\\"`,
+		"\"\n\"",
+		`"\U0001f64f"`,
+		`"\uD83D\u00"`,
+	}
+	for i := 0; i < 32; i++ {
+		// control characters are invalid
+		badInputs = append(badInputs, string([]byte{'"', byte(i), '"'}))
+	}
+
+	for _, input := range badInputs {
+		testReadString(t, input, "", true, "json.Unmarshal", json.Unmarshal)
+		testReadString(t, input, "", true, "jsoniter.Unmarshal", jsoniter.Unmarshal)
+		testReadString(t, input, "", true, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
+	}
+
+	goodInputs := []struct {
+		input       string
+		expectValue string
+	}{
+		{`""`, ""},
+		{`"a"`, "a"},
+		{`null`, ""},
+		{`"Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"`, "Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"},
+		{`"\uD83D"`, string([]byte{239, 191, 189})},
+		{`"\uD83D\\"`, string([]byte{239, 191, 189, '\\'})},
+		{`"\uD83D\ub000"`, string([]byte{239, 191, 189, 235, 128, 128})},
+		{`"\uD83D\ude04"`, "😄"},
+		{`"\uDEADBEEF"`, string([]byte{239, 191, 189, 66, 69, 69, 70})},
+		{`"hel\"lo"`, `hel"lo`},
+		{`"hel\\\/lo"`, `hel\/lo`},
+		{`"hel\\blo"`, `hel\blo`},
+		{`"hel\\\blo"`, "hel\\\blo"},
+		{`"hel\\nlo"`, `hel\nlo`},
+		{`"hel\\\nlo"`, "hel\\\nlo"},
+		{`"hel\\tlo"`, `hel\tlo`},
+		{`"hel\\flo"`, `hel\flo`},
+		{`"hel\\\flo"`, "hel\\\flo"},
+		{`"hel\\\rlo"`, "hel\\\rlo"},
+		{`"hel\\\tlo"`, "hel\\\tlo"},
+		{`"\u4e2d\u6587"`, "中文"},
+		{`"\ud83d\udc4a"`, "\xf0\x9f\x91\x8a"},
+	}
+
+	for _, tc := range goodInputs {
+		testReadString(t, tc.input, tc.expectValue, false, "json.Unmarshal", json.Unmarshal)
+		testReadString(t, tc.input, tc.expectValue, false, "jsoniter.Unmarshal", jsoniter.Unmarshal)
+		testReadString(t, tc.input, tc.expectValue, false, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
+	}
+}
+
+func testReadString(t *testing.T, input string, expectValue string, expectError bool, marshalerName string, marshaler func([]byte, interface{}) error) {
+	var value string
+	err := marshaler([]byte(input), &value)
+	if expectError != (err != nil) {
+		t.Errorf("%q: %s: expected error %v, got %v", input, marshalerName, expectError, err)
+		return
+	}
+	if value != expectValue {
+		t.Errorf("%q: %s: expected %q, got %q", input, marshalerName, expectValue, value)
+		return
+	}
+}

+ 19 - 0
value_tests/struct_test.go

@@ -49,6 +49,14 @@ func init() {
 			Field2 json.RawMessage
 		})(nil),
 		input: `{"field1": "hello", "field2":[1,2,3]}`,
+	}, unmarshalCase{
+		ptr: (*struct {
+			a int
+			b <-chan int
+			C int
+			d *time.Timer
+		})(nil),
+		input: `{"a": 444, "b":"bad", "C":256, "d":{"not":"a timer"}}`,
 	})
 	marshalCases = append(marshalCases,
 		struct {
@@ -135,6 +143,17 @@ func init() {
 			Field1 *string
 			Field2 *string
 		}{Field2: pString("world")},
+		struct {
+			a int
+			b <-chan int
+			C int
+			d *time.Timer
+		}{
+			a: 42,
+			b: make(<-chan int, 10),
+			C: 21,
+			d: time.NewTimer(10 * time.Second),
+		},
 	)
 }