1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
25 var txType = reflect.TypeOf((*tx)(nil)).Elem()
27 // A type that can unmarshal itself.
29 type unmarshaler struct {
33 func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
34 *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
43 um0, um1 unmarshaler // target2 of unmarshaling
45 umtrue = unmarshaler{true}
46 umslice = []unmarshaler{{true}}
47 umslicep = new([]unmarshaler)
48 umstruct = ustruct{unmarshaler{true}}
51 type unmarshalTest struct {
58 var unmarshalTests = []unmarshalTest{
60 {`true`, new(bool), true, nil},
61 {`1`, new(int), 1, nil},
62 {`1.2`, new(float64), 1.2, nil},
63 {`-5`, new(int16), int16(-5), nil},
64 {`"a\u1234"`, new(string), "a\u1234", nil},
65 {`"http:\/\/"`, new(string), "http://", nil},
66 {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
67 {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
68 {"null", new(interface{}), nil, nil},
69 {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
70 {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
73 {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
76 {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
79 {allValueIndent, new(All), allValue, nil},
80 {allValueCompact, new(All), allValue, nil},
81 {allValueIndent, new(*All), &allValue, nil},
82 {allValueCompact, new(*All), &allValue, nil},
83 {pallValueIndent, new(All), pallValue, nil},
84 {pallValueCompact, new(All), pallValue, nil},
85 {pallValueIndent, new(*All), &pallValue, nil},
86 {pallValueCompact, new(*All), &pallValue, nil},
88 // unmarshal interface test
89 {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
90 {`{"T":false}`, &ump, &umtrue, nil},
91 {`[{"T":false}]`, &umslice, umslice, nil},
92 {`[{"T":false}]`, &umslicep, &umslice, nil},
93 {`{"M":{"T":false}}`, &umstruct, umstruct, nil},
96 func TestMarshal(t *testing.T) {
97 b, err := Marshal(allValue)
99 t.Fatalf("Marshal allValue: %v", err)
101 if string(b) != allValueCompact {
102 t.Errorf("Marshal allValueCompact")
103 diff(t, b, []byte(allValueCompact))
107 b, err = Marshal(pallValue)
109 t.Fatalf("Marshal pallValue: %v", err)
111 if string(b) != pallValueCompact {
112 t.Errorf("Marshal pallValueCompact")
113 diff(t, b, []byte(pallValueCompact))
118 func TestMarshalBadUTF8(t *testing.T) {
119 s := "hello\xffworld"
122 t.Fatal("Marshal bad UTF8: no error")
125 t.Fatal("Marshal returned data")
127 if _, ok := err.(*InvalidUTF8Error); !ok {
128 t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
132 func TestUnmarshal(t *testing.T) {
133 for i, tt := range unmarshalTests {
136 if err := checkValid(in, &scan); err != nil {
137 if !reflect.DeepEqual(err, tt.err) {
138 t.Errorf("#%d: checkValid: %#v", i, err)
145 // v = new(right-type)
146 v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
147 if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
148 t.Errorf("#%d: %v want %v", i, err, tt.err)
151 if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
152 t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
153 data, _ := Marshal(v.Elem().Interface())
154 println(string(data))
155 data, _ = Marshal(tt.out)
156 println(string(data))
162 func TestUnmarshalMarshal(t *testing.T) {
165 if err := Unmarshal(jsonBig, &v); err != nil {
166 t.Fatalf("Unmarshal: %v", err)
170 t.Fatalf("Marshal: %v", err)
172 if bytes.Compare(jsonBig, b) != 0 {
173 t.Errorf("Marshal jsonBig")
179 func TestLargeByteSlice(t *testing.T) {
180 s0 := make([]byte, 2000)
184 b, err := Marshal(s0)
186 t.Fatalf("Marshal: %v", err)
189 if err := Unmarshal(b, &s1); err != nil {
190 t.Fatalf("Unmarshal: %v", err)
192 if bytes.Compare(s0, s1) != 0 {
193 t.Errorf("Marshal large byte slice")
202 func TestUnmarshalInterface(t *testing.T) {
204 var i interface{} = &xint
205 if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
206 t.Fatalf("Unmarshal: %v", err)
209 t.Fatalf("Did not write to xint")
213 func TestUnmarshalPtrPtr(t *testing.T) {
216 if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
217 t.Fatalf("Unmarshal: %v", err)
220 t.Fatalf("Did not write to xint")
224 func TestEscape(t *testing.T) {
225 const input = `"foobar"<html>`
226 const expected = `"\"foobar\"\u003chtml\u003e"`
227 b, err := Marshal(input)
229 t.Fatalf("Marshal error: %v", err)
231 if s := string(b); s != expected {
232 t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
236 func TestHTMLEscape(t *testing.T) {
237 b, err := MarshalForHTML("foobarbaz<>&quux")
239 t.Fatalf("MarshalForHTML error: %v", err)
241 if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
242 t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
246 func noSpace(c int) int {
269 Foo string `json:"bar"`
270 Foo2 string `json:"bar2,dummyopt"`
272 IntStr int64 `json:",string"`
293 MapP map[string]*Small
294 PMap *map[string]Small
295 PMapP *map[string]*Small
297 EmptyMap map[string]Small
298 NilMap map[string]Small
315 Interface interface{}
316 PInterface *interface{}
344 Map: map[string]Small{
345 "17": {Tag: "tag17"},
346 "18": {Tag: "tag18"},
348 MapP: map[string]*Small{
349 "19": &Small{Tag: "tag19"},
352 EmptyMap: map[string]Small{},
353 Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
354 SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
355 EmptySlice: []Small{},
356 StringSlice: []string{"str24", "str25", "str26"},
357 ByteSlice: []byte{27, 28, 29},
358 Small: Small{Tag: "tag30"},
359 PSmall: &Small{Tag: "tag31"},
364 PBool: &allValue.Bool,
366 PInt8: &allValue.Int8,
367 PInt16: &allValue.Int16,
368 PInt32: &allValue.Int32,
369 PInt64: &allValue.Int64,
370 PUint: &allValue.Uint,
371 PUint8: &allValue.Uint8,
372 PUint16: &allValue.Uint16,
373 PUint32: &allValue.Uint32,
374 PUint64: &allValue.Uint64,
375 PUintptr: &allValue.Uintptr,
376 PFloat32: &allValue.Float32,
377 PFloat64: &allValue.Float64,
378 PString: &allValue.String,
380 PMapP: &allValue.MapP,
381 PSlice: &allValue.Slice,
382 PSliceP: &allValue.SliceP,
383 PPSmall: &allValue.PSmall,
384 PInterface: &allValue.Interface,
387 var allValueIndent = `{
477 var allValueCompact = strings.Map(noSpace, allValueIndent)
479 var pallValueIndent = `{
565 var pallValueCompact = strings.Map(noSpace, pallValueIndent)