| // 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" | |
| "os" | |
| "reflect" | |
| "strings" | |
| "testing" | |
| ) | |
| type T struct { | |
| X string | |
| Y int | |
| } | |
| type unmarshalTest struct { | |
| in string | |
| ptr interface{} | |
| out interface{} | |
| err os.Error | |
| } | |
| var unmarshalTests = []unmarshalTest{ | |
| // basic types | |
| unmarshalTest{`true`, new(bool), true, nil}, | |
| unmarshalTest{`1`, new(int), 1, nil}, | |
| unmarshalTest{`1.2`, new(float), 1.2, nil}, | |
| unmarshalTest{`-5`, new(int16), int16(-5), nil}, | |
| unmarshalTest{`"a\u1234"`, new(string), "a\u1234", nil}, | |
| unmarshalTest{`"http:\/\/"`, new(string), "http://", nil}, | |
| unmarshalTest{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil}, | |
| unmarshalTest{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil}, | |
| unmarshalTest{"null", new(interface{}), nil, nil}, | |
| unmarshalTest{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.Typeof("")}}, | |
| // composite tests | |
| unmarshalTest{allValueIndent, new(All), allValue, nil}, | |
| unmarshalTest{allValueCompact, new(All), allValue, nil}, | |
| unmarshalTest{allValueIndent, new(*All), &allValue, nil}, | |
| unmarshalTest{allValueCompact, new(*All), &allValue, nil}, | |
| unmarshalTest{pallValueIndent, new(All), pallValue, nil}, | |
| unmarshalTest{pallValueCompact, new(All), pallValue, nil}, | |
| unmarshalTest{pallValueIndent, new(*All), &pallValue, nil}, | |
| unmarshalTest{pallValueCompact, new(*All), &pallValue, nil}, | |
| } | |
| 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()); !reflect.DeepEqual(err, tt.err) { | |
| t.Errorf("#%d: %v want %v", i, err, tt.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 | |
| } | |
| } | |
| type Xint struct { | |
| X int | |
| } | |
| func TestUnmarshalInterface(t *testing.T) { | |
| var xint Xint | |
| var i interface{} = &xint | |
| if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { | |
| t.Fatalf("Unmarshal: %v", err) | |
| } | |
| if xint.X != 1 { | |
| t.Fatalf("Did not write to xint") | |
| } | |
| } | |
| func TestUnmarshalPtrPtr(t *testing.T) { | |
| var xint Xint | |
| pxint := &xint | |
| if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { | |
| t.Fatalf("Unmarshal: %v", err) | |
| } | |
| if xint.X != 1 { | |
| t.Fatalf("Did not write to xint") | |
| } | |
| } | |
| 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) |