mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
json: Marshal, Unmarshal using new scanner
R=r CC=golang-dev https://golang.org/cl/953041
This commit is contained in:
parent
214a55b06a
commit
dba9d62bc2
11 changed files with 1570 additions and 1053 deletions
|
|
@ -1,133 +1,427 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"container/vector"
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeInt64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Int64(-15)
|
||||
assertResult(t, nb.Data(), float64(-15))
|
||||
type unmarshalTest struct {
|
||||
in string
|
||||
ptr interface{}
|
||||
out interface{}
|
||||
}
|
||||
|
||||
func TestDecodeUint64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Uint64(15)
|
||||
assertResult(t, nb.Data(), float64(15))
|
||||
var unmarshalTests = []unmarshalTest{
|
||||
// basic types
|
||||
unmarshalTest{`true`, new(bool), true},
|
||||
unmarshalTest{`1`, new(int), 1},
|
||||
unmarshalTest{`1.2`, new(float), 1.2},
|
||||
unmarshalTest{`-5`, new(int16), int16(-5)},
|
||||
unmarshalTest{`"a\u1234"`, new(string), "a\u1234"},
|
||||
unmarshalTest{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E"},
|
||||
unmarshalTest{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD"},
|
||||
unmarshalTest{"null", new(interface{}), nil},
|
||||
|
||||
// composite tests
|
||||
unmarshalTest{allValueIndent, new(All), allValue},
|
||||
unmarshalTest{allValueCompact, new(All), allValue},
|
||||
unmarshalTest{allValueIndent, new(*All), &allValue},
|
||||
unmarshalTest{allValueCompact, new(*All), &allValue},
|
||||
unmarshalTest{pallValueIndent, new(All), pallValue},
|
||||
unmarshalTest{pallValueCompact, new(All), pallValue},
|
||||
unmarshalTest{pallValueIndent, new(*All), &pallValue},
|
||||
unmarshalTest{pallValueCompact, new(*All), &pallValue},
|
||||
}
|
||||
|
||||
func TestDecodeFloat64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Float64(3.14159)
|
||||
assertResult(t, nb.Data(), float64(3.14159))
|
||||
}
|
||||
func TestMarshal(t *testing.T) {
|
||||
b, err := Marshal(allValue)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal allValue: %v", err)
|
||||
}
|
||||
if string(b) != allValueCompact {
|
||||
t.Errorf("Marshal allValueCompact")
|
||||
diff(t, b, []byte(allValueCompact))
|
||||
return
|
||||
}
|
||||
|
||||
func TestDecodeString(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.String("Some string")
|
||||
assertResult(t, nb.Data(), "Some string")
|
||||
}
|
||||
|
||||
func TestDecodeBool(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Bool(true)
|
||||
assertResult(t, nb.Data(), true)
|
||||
}
|
||||
|
||||
func TestDecodeNull(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Null()
|
||||
assertResult(t, nb.Data(), nil)
|
||||
}
|
||||
|
||||
func TestDecodeEmptyArray(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Array()
|
||||
assertResult(t, nb.Data(), []interface{}{})
|
||||
}
|
||||
|
||||
func TestDecodeEmptyMap(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Map()
|
||||
assertResult(t, nb.Data(), map[string]interface{}{})
|
||||
}
|
||||
|
||||
func TestDecodeFlushElem(t *testing.T) {
|
||||
testVec := new(vector.Vector).Resize(2, 2)
|
||||
nb := newDecoder(testVec, 1)
|
||||
nb.Float64(3.14159)
|
||||
nb.Flush()
|
||||
assertResult(t, testVec.Data(), []interface{}{nil, float64(3.14159)})
|
||||
}
|
||||
|
||||
func TestDecodeFlushKey(t *testing.T) {
|
||||
testMap := make(map[string]interface{})
|
||||
nb := newDecoder(testMap, "key")
|
||||
nb.Float64(3.14159)
|
||||
nb.Flush()
|
||||
assertResult(t, testMap, map[string]interface{}{"key": float64(3.14159)})
|
||||
}
|
||||
|
||||
// Elem() and Key() are hard to test in isolation because all they do
|
||||
// is create a new, properly initialized, decoder, and modify state of
|
||||
// the underlying decoder. I'm testing them through already tested
|
||||
// Array(), String(), and Flush().
|
||||
|
||||
func TestDecodeElem(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Array()
|
||||
var b Builder = nb.Elem(0)
|
||||
b.String("0")
|
||||
b.Flush()
|
||||
assertResult(t, nb.Data(), []interface{}{"0"})
|
||||
}
|
||||
|
||||
func TestDecodeKey(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Map()
|
||||
var b Builder = nb.Key("a")
|
||||
b.String("0")
|
||||
b.Flush()
|
||||
assertResult(t, nb.Data(), map[string]interface{}{"a": "0"})
|
||||
}
|
||||
|
||||
func assertResult(t *testing.T, results, expected interface{}) {
|
||||
if !reflect.DeepEqual(results, expected) {
|
||||
t.Fatalf("have %T(%#v) want %T(%#v)", results, results, expected, expected)
|
||||
b, err = Marshal(pallValue)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal pallValue: %v", err)
|
||||
}
|
||||
if string(b) != pallValueCompact {
|
||||
t.Errorf("Marshal pallValueCompact")
|
||||
diff(t, b, []byte(pallValueCompact))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type decodeTest struct {
|
||||
s string
|
||||
r interface{}
|
||||
}
|
||||
|
||||
var tests = []decodeTest{
|
||||
decodeTest{`null`, nil},
|
||||
decodeTest{`true`, true},
|
||||
decodeTest{`false`, false},
|
||||
decodeTest{`"abc"`, "abc"},
|
||||
decodeTest{`123`, float64(123)},
|
||||
decodeTest{`0.1`, float64(0.1)},
|
||||
decodeTest{`1e-10`, float64(1e-10)},
|
||||
decodeTest{`[]`, []interface{}{}},
|
||||
decodeTest{`[1,2,3,4]`, []interface{}{float64(1), float64(2), float64(3), float64(4)}},
|
||||
decodeTest{`[1,2,"abc",null,true,false]`, []interface{}{float64(1), float64(2), "abc", nil, true, false}},
|
||||
decodeTest{`{}`, map[string]interface{}{}},
|
||||
decodeTest{`{"a":1}`, map[string]interface{}{"a": float64(1)}},
|
||||
decodeTest{`"q\u0302"`, "q\u0302"},
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
if val, err := Decode(test.s); err != nil || !reflect.DeepEqual(val, test.r) {
|
||||
t.Errorf("Decode(%#q) = %v, %v want %v, nil", test.s, val, err, test.r)
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
var scan scanner
|
||||
for i, tt := range unmarshalTests {
|
||||
in := []byte(tt.in)
|
||||
if err := checkValid(in, &scan); err != nil {
|
||||
t.Errorf("#%d: checkValid: %v", i, err)
|
||||
continue
|
||||
}
|
||||
// v = new(right-type)
|
||||
v := reflect.NewValue(tt.ptr).(*reflect.PtrValue)
|
||||
v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
|
||||
if err := Unmarshal([]byte(in), v.Interface()); err != nil {
|
||||
t.Errorf("#%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
|
||||
t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
|
||||
data, _ := Marshal(v.Elem().Interface())
|
||||
println(string(data))
|
||||
data, _ = Marshal(tt.out)
|
||||
println(string(data))
|
||||
return
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalMarshal(t *testing.T) {
|
||||
var v interface{}
|
||||
if err := Unmarshal(jsonBig, &v); err != nil {
|
||||
t.Fatalf("Unmarshal: %v", err)
|
||||
}
|
||||
b, err := Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal: %v", err)
|
||||
}
|
||||
if bytes.Compare(jsonBig, b) != 0 {
|
||||
t.Errorf("Marshal jsonBig")
|
||||
diff(t, b, jsonBig)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func noSpace(c int) int {
|
||||
if isSpace(c) {
|
||||
return -1
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type All struct {
|
||||
Bool bool
|
||||
Int int
|
||||
Int8 int8
|
||||
Int16 int16
|
||||
Int32 int32
|
||||
Int64 int64
|
||||
Uint uint
|
||||
Uint8 uint8
|
||||
Uint16 uint16
|
||||
Uint32 uint32
|
||||
Uint64 uint64
|
||||
Uintptr uintptr
|
||||
Float float
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
|
||||
Foo string "bar"
|
||||
|
||||
PBool *bool
|
||||
PInt *int
|
||||
PInt8 *int8
|
||||
PInt16 *int16
|
||||
PInt32 *int32
|
||||
PInt64 *int64
|
||||
PUint *uint
|
||||
PUint8 *uint8
|
||||
PUint16 *uint16
|
||||
PUint32 *uint32
|
||||
PUint64 *uint64
|
||||
PUintptr *uintptr
|
||||
PFloat *float
|
||||
PFloat32 *float32
|
||||
PFloat64 *float64
|
||||
|
||||
String string
|
||||
PString *string
|
||||
|
||||
Map map[string]Small
|
||||
MapP map[string]*Small
|
||||
PMap *map[string]Small
|
||||
PMapP *map[string]*Small
|
||||
|
||||
EmptyMap map[string]Small
|
||||
NilMap map[string]Small
|
||||
|
||||
Slice []Small
|
||||
SliceP []*Small
|
||||
PSlice *[]Small
|
||||
PSliceP *[]*Small
|
||||
|
||||
EmptySlice []Small
|
||||
NilSlice []Small
|
||||
|
||||
StringSlice []string
|
||||
ByteSlice []byte
|
||||
|
||||
Small Small
|
||||
PSmall *Small
|
||||
PPSmall **Small
|
||||
|
||||
Interface interface{}
|
||||
PInterface *interface{}
|
||||
}
|
||||
|
||||
type Small struct {
|
||||
Tag string
|
||||
}
|
||||
|
||||
var allValue = All{
|
||||
Bool: true,
|
||||
Int: 2,
|
||||
Int8: 3,
|
||||
Int16: 4,
|
||||
Int32: 5,
|
||||
Int64: 6,
|
||||
Uint: 7,
|
||||
Uint8: 8,
|
||||
Uint16: 9,
|
||||
Uint32: 10,
|
||||
Uint64: 11,
|
||||
Uintptr: 12,
|
||||
Float: 13.1,
|
||||
Float32: 14.1,
|
||||
Float64: 15.1,
|
||||
Foo: "foo",
|
||||
String: "16",
|
||||
Map: map[string]Small{
|
||||
"17": Small{Tag: "tag17"},
|
||||
"18": Small{Tag: "tag18"},
|
||||
},
|
||||
MapP: map[string]*Small{
|
||||
"19": &Small{Tag: "tag19"},
|
||||
"20": nil,
|
||||
},
|
||||
EmptyMap: map[string]Small{},
|
||||
Slice: []Small{Small{Tag: "tag20"}, Small{Tag: "tag21"}},
|
||||
SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
|
||||
EmptySlice: []Small{},
|
||||
StringSlice: []string{"str24", "str25", "str26"},
|
||||
ByteSlice: []byte{27, 28, 29},
|
||||
Small: Small{Tag: "tag30"},
|
||||
PSmall: &Small{Tag: "tag31"},
|
||||
Interface: float64(5.2),
|
||||
}
|
||||
|
||||
var pallValue = All{
|
||||
PBool: &allValue.Bool,
|
||||
PInt: &allValue.Int,
|
||||
PInt8: &allValue.Int8,
|
||||
PInt16: &allValue.Int16,
|
||||
PInt32: &allValue.Int32,
|
||||
PInt64: &allValue.Int64,
|
||||
PUint: &allValue.Uint,
|
||||
PUint8: &allValue.Uint8,
|
||||
PUint16: &allValue.Uint16,
|
||||
PUint32: &allValue.Uint32,
|
||||
PUint64: &allValue.Uint64,
|
||||
PUintptr: &allValue.Uintptr,
|
||||
PFloat: &allValue.Float,
|
||||
PFloat32: &allValue.Float32,
|
||||
PFloat64: &allValue.Float64,
|
||||
PString: &allValue.String,
|
||||
PMap: &allValue.Map,
|
||||
PMapP: &allValue.MapP,
|
||||
PSlice: &allValue.Slice,
|
||||
PSliceP: &allValue.SliceP,
|
||||
PPSmall: &allValue.PSmall,
|
||||
PInterface: &allValue.Interface,
|
||||
}
|
||||
|
||||
var allValueIndent = `{
|
||||
"bool": true,
|
||||
"int": 2,
|
||||
"int8": 3,
|
||||
"int16": 4,
|
||||
"int32": 5,
|
||||
"int64": 6,
|
||||
"uint": 7,
|
||||
"uint8": 8,
|
||||
"uint16": 9,
|
||||
"uint32": 10,
|
||||
"uint64": 11,
|
||||
"uintptr": 12,
|
||||
"float": 13.1,
|
||||
"float32": 14.1,
|
||||
"float64": 15.1,
|
||||
"bar": "foo",
|
||||
"pbool": null,
|
||||
"pint": null,
|
||||
"pint8": null,
|
||||
"pint16": null,
|
||||
"pint32": null,
|
||||
"pint64": null,
|
||||
"puint": null,
|
||||
"puint8": null,
|
||||
"puint16": null,
|
||||
"puint32": null,
|
||||
"puint64": null,
|
||||
"puintptr": null,
|
||||
"pfloat": null,
|
||||
"pfloat32": null,
|
||||
"pfloat64": null,
|
||||
"string": "16",
|
||||
"pstring": null,
|
||||
"map": {
|
||||
"17": {
|
||||
"tag": "tag17"
|
||||
},
|
||||
"18": {
|
||||
"tag": "tag18"
|
||||
}
|
||||
},
|
||||
"mapp": {
|
||||
"19": {
|
||||
"tag": "tag19"
|
||||
},
|
||||
"20": null
|
||||
},
|
||||
"pmap": null,
|
||||
"pmapp": null,
|
||||
"emptymap": {},
|
||||
"nilmap": null,
|
||||
"slice": [
|
||||
{
|
||||
"tag": "tag20"
|
||||
},
|
||||
{
|
||||
"tag": "tag21"
|
||||
}
|
||||
],
|
||||
"slicep": [
|
||||
{
|
||||
"tag": "tag22"
|
||||
},
|
||||
null,
|
||||
{
|
||||
"tag": "tag23"
|
||||
}
|
||||
],
|
||||
"pslice": null,
|
||||
"pslicep": null,
|
||||
"emptyslice": [],
|
||||
"nilslice": [],
|
||||
"stringslice": [
|
||||
"str24",
|
||||
"str25",
|
||||
"str26"
|
||||
],
|
||||
"byteslice": [
|
||||
27,
|
||||
28,
|
||||
29
|
||||
],
|
||||
"small": {
|
||||
"tag": "tag30"
|
||||
},
|
||||
"psmall": {
|
||||
"tag": "tag31"
|
||||
},
|
||||
"ppsmall": null,
|
||||
"interface": 5.2,
|
||||
"pinterface": null
|
||||
}`
|
||||
|
||||
var allValueCompact = strings.Map(noSpace, allValueIndent)
|
||||
|
||||
var pallValueIndent = `{
|
||||
"bool": false,
|
||||
"int": 0,
|
||||
"int8": 0,
|
||||
"int16": 0,
|
||||
"int32": 0,
|
||||
"int64": 0,
|
||||
"uint": 0,
|
||||
"uint8": 0,
|
||||
"uint16": 0,
|
||||
"uint32": 0,
|
||||
"uint64": 0,
|
||||
"uintptr": 0,
|
||||
"float": 0,
|
||||
"float32": 0,
|
||||
"float64": 0,
|
||||
"bar": "",
|
||||
"pbool": true,
|
||||
"pint": 2,
|
||||
"pint8": 3,
|
||||
"pint16": 4,
|
||||
"pint32": 5,
|
||||
"pint64": 6,
|
||||
"puint": 7,
|
||||
"puint8": 8,
|
||||
"puint16": 9,
|
||||
"puint32": 10,
|
||||
"puint64": 11,
|
||||
"puintptr": 12,
|
||||
"pfloat": 13.1,
|
||||
"pfloat32": 14.1,
|
||||
"pfloat64": 15.1,
|
||||
"string": "",
|
||||
"pstring": "16",
|
||||
"map": null,
|
||||
"mapp": null,
|
||||
"pmap": {
|
||||
"17": {
|
||||
"tag": "tag17"
|
||||
},
|
||||
"18": {
|
||||
"tag": "tag18"
|
||||
}
|
||||
},
|
||||
"pmapp": {
|
||||
"19": {
|
||||
"tag": "tag19"
|
||||
},
|
||||
"20": null
|
||||
},
|
||||
"emptymap": null,
|
||||
"nilmap": null,
|
||||
"slice": [],
|
||||
"slicep": [],
|
||||
"pslice": [
|
||||
{
|
||||
"tag": "tag20"
|
||||
},
|
||||
{
|
||||
"tag": "tag21"
|
||||
}
|
||||
],
|
||||
"pslicep": [
|
||||
{
|
||||
"tag": "tag22"
|
||||
},
|
||||
null,
|
||||
{
|
||||
"tag": "tag23"
|
||||
}
|
||||
],
|
||||
"emptyslice": [],
|
||||
"nilslice": [],
|
||||
"stringslice": [],
|
||||
"byteslice": [],
|
||||
"small": {
|
||||
"tag": ""
|
||||
},
|
||||
"psmall": null,
|
||||
"ppsmall": {
|
||||
"tag": "tag31"
|
||||
},
|
||||
"interface": null,
|
||||
"pinterface": 5.2
|
||||
}`
|
||||
|
||||
var pallValueCompact = strings.Map(noSpace, pallValueIndent)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue