// 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 ( "bytes" "reflect" "strings" "testing" ) type unmarshalTest struct { in string ptr interface{} out interface{} } 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 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 } 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 } } 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)