OSDN Git Service

05c8a064a422c8bba383aa1683ebaa72a0ea4793
[pf3gnuchains/gcc-fork.git] / libgo / go / encoding / json / decode_test.go
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.
4
5 package json
6
7 import (
8         "bytes"
9         "fmt"
10         "reflect"
11         "strings"
12         "testing"
13 )
14
15 type T struct {
16         X string
17         Y int
18         Z int `json:"-"`
19 }
20
21 type tx struct {
22         x int
23 }
24
25 var txType = reflect.TypeOf((*tx)(nil)).Elem()
26
27 // A type that can unmarshal itself.
28
29 type unmarshaler struct {
30         T bool
31 }
32
33 func (u *unmarshaler) UnmarshalJSON(b []byte) error {
34         *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
35         return nil
36 }
37
38 type ustruct struct {
39         M unmarshaler
40 }
41
42 var (
43         um0, um1 unmarshaler // target2 of unmarshaling
44         ump      = &um1
45         umtrue   = unmarshaler{true}
46         umslice  = []unmarshaler{{true}}
47         umslicep = new([]unmarshaler)
48         umstruct = ustruct{unmarshaler{true}}
49 )
50
51 type unmarshalTest struct {
52         in  string
53         ptr interface{}
54         out interface{}
55         err error
56 }
57
58 var unmarshalTests = []unmarshalTest{
59         // basic types
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)}},
71
72         // Z has a "-" tag.
73         {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
74
75         // syntax errors
76         {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
77         {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
78
79         // array tests
80         {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
81         {`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
82         {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
83
84         // composite tests
85         {allValueIndent, new(All), allValue, nil},
86         {allValueCompact, new(All), allValue, nil},
87         {allValueIndent, new(*All), &allValue, nil},
88         {allValueCompact, new(*All), &allValue, nil},
89         {pallValueIndent, new(All), pallValue, nil},
90         {pallValueCompact, new(All), pallValue, nil},
91         {pallValueIndent, new(*All), &pallValue, nil},
92         {pallValueCompact, new(*All), &pallValue, nil},
93
94         // unmarshal interface test
95         {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
96         {`{"T":false}`, &ump, &umtrue, nil},
97         {`[{"T":false}]`, &umslice, umslice, nil},
98         {`[{"T":false}]`, &umslicep, &umslice, nil},
99         {`{"M":{"T":false}}`, &umstruct, umstruct, nil},
100 }
101
102 func TestMarshal(t *testing.T) {
103         b, err := Marshal(allValue)
104         if err != nil {
105                 t.Fatalf("Marshal allValue: %v", err)
106         }
107         if string(b) != allValueCompact {
108                 t.Errorf("Marshal allValueCompact")
109                 diff(t, b, []byte(allValueCompact))
110                 return
111         }
112
113         b, err = Marshal(pallValue)
114         if err != nil {
115                 t.Fatalf("Marshal pallValue: %v", err)
116         }
117         if string(b) != pallValueCompact {
118                 t.Errorf("Marshal pallValueCompact")
119                 diff(t, b, []byte(pallValueCompact))
120                 return
121         }
122 }
123
124 func TestMarshalBadUTF8(t *testing.T) {
125         s := "hello\xffworld"
126         b, err := Marshal(s)
127         if err == nil {
128                 t.Fatal("Marshal bad UTF8: no error")
129         }
130         if len(b) != 0 {
131                 t.Fatal("Marshal returned data")
132         }
133         if _, ok := err.(*InvalidUTF8Error); !ok {
134                 t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
135         }
136 }
137
138 func TestUnmarshal(t *testing.T) {
139         for i, tt := range unmarshalTests {
140                 var scan scanner
141                 in := []byte(tt.in)
142                 if err := checkValid(in, &scan); err != nil {
143                         if !reflect.DeepEqual(err, tt.err) {
144                                 t.Errorf("#%d: checkValid: %#v", i, err)
145                                 continue
146                         }
147                 }
148                 if tt.ptr == nil {
149                         continue
150                 }
151                 // v = new(right-type)
152                 v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
153                 if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
154                         t.Errorf("#%d: %v want %v", i, err, tt.err)
155                         continue
156                 }
157                 if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
158                         t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
159                         data, _ := Marshal(v.Elem().Interface())
160                         println(string(data))
161                         data, _ = Marshal(tt.out)
162                         println(string(data))
163                         continue
164                 }
165         }
166 }
167
168 func TestUnmarshalMarshal(t *testing.T) {
169         initBig()
170         var v interface{}
171         if err := Unmarshal(jsonBig, &v); err != nil {
172                 t.Fatalf("Unmarshal: %v", err)
173         }
174         b, err := Marshal(v)
175         if err != nil {
176                 t.Fatalf("Marshal: %v", err)
177         }
178         if bytes.Compare(jsonBig, b) != 0 {
179                 t.Errorf("Marshal jsonBig")
180                 diff(t, b, jsonBig)
181                 return
182         }
183 }
184
185 func TestLargeByteSlice(t *testing.T) {
186         s0 := make([]byte, 2000)
187         for i := range s0 {
188                 s0[i] = byte(i)
189         }
190         b, err := Marshal(s0)
191         if err != nil {
192                 t.Fatalf("Marshal: %v", err)
193         }
194         var s1 []byte
195         if err := Unmarshal(b, &s1); err != nil {
196                 t.Fatalf("Unmarshal: %v", err)
197         }
198         if bytes.Compare(s0, s1) != 0 {
199                 t.Errorf("Marshal large byte slice")
200                 diff(t, s0, s1)
201         }
202 }
203
204 type Xint struct {
205         X int
206 }
207
208 func TestUnmarshalInterface(t *testing.T) {
209         var xint Xint
210         var i interface{} = &xint
211         if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
212                 t.Fatalf("Unmarshal: %v", err)
213         }
214         if xint.X != 1 {
215                 t.Fatalf("Did not write to xint")
216         }
217 }
218
219 func TestUnmarshalPtrPtr(t *testing.T) {
220         var xint Xint
221         pxint := &xint
222         if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
223                 t.Fatalf("Unmarshal: %v", err)
224         }
225         if xint.X != 1 {
226                 t.Fatalf("Did not write to xint")
227         }
228 }
229
230 func TestEscape(t *testing.T) {
231         const input = `"foobar"<html>`
232         const expected = `"\"foobar\"\u003chtml\u003e"`
233         b, err := Marshal(input)
234         if err != nil {
235                 t.Fatalf("Marshal error: %v", err)
236         }
237         if s := string(b); s != expected {
238                 t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
239         }
240 }
241
242 func TestHTMLEscape(t *testing.T) {
243         b, err := MarshalForHTML("foobarbaz<>&quux")
244         if err != nil {
245                 t.Fatalf("MarshalForHTML error: %v", err)
246         }
247         if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
248                 t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
249         }
250 }
251
252 // WrongString is a struct that's misusing the ,string modifier.
253 type WrongString struct {
254         Message string `json:"result,string"`
255 }
256
257 type wrongStringTest struct {
258         in, err string
259 }
260
261 // TODO(bradfitz): as part of Issue 2331, fix these tests' expected
262 // error values to be helpful, rather than the confusing messages they
263 // are now.
264 var wrongStringTests = []wrongStringTest{
265         {`{"result":"x"}`, "JSON decoder out of sync - data changing underfoot?"},
266         {`{"result":"foo"}`, "json: cannot unmarshal bool into Go value of type string"},
267         {`{"result":"123"}`, "json: cannot unmarshal number into Go value of type string"},
268 }
269
270 // If people misuse the ,string modifier, the error message should be
271 // helpful, telling the user that they're doing it wrong.
272 func TestErrorMessageFromMisusedString(t *testing.T) {
273         for n, tt := range wrongStringTests {
274                 r := strings.NewReader(tt.in)
275                 var s WrongString
276                 err := NewDecoder(r).Decode(&s)
277                 got := fmt.Sprintf("%v", err)
278                 if got != tt.err {
279                         t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
280                 }
281         }
282 }
283
284 func noSpace(c rune) rune {
285         if isSpace(c) {
286                 return -1
287         }
288         return c
289 }
290
291 type All struct {
292         Bool    bool
293         Int     int
294         Int8    int8
295         Int16   int16
296         Int32   int32
297         Int64   int64
298         Uint    uint
299         Uint8   uint8
300         Uint16  uint16
301         Uint32  uint32
302         Uint64  uint64
303         Uintptr uintptr
304         Float32 float32
305         Float64 float64
306
307         Foo  string `json:"bar"`
308         Foo2 string `json:"bar2,dummyopt"`
309
310         IntStr int64 `json:",string"`
311
312         PBool    *bool
313         PInt     *int
314         PInt8    *int8
315         PInt16   *int16
316         PInt32   *int32
317         PInt64   *int64
318         PUint    *uint
319         PUint8   *uint8
320         PUint16  *uint16
321         PUint32  *uint32
322         PUint64  *uint64
323         PUintptr *uintptr
324         PFloat32 *float32
325         PFloat64 *float64
326
327         String  string
328         PString *string
329
330         Map   map[string]Small
331         MapP  map[string]*Small
332         PMap  *map[string]Small
333         PMapP *map[string]*Small
334
335         EmptyMap map[string]Small
336         NilMap   map[string]Small
337
338         Slice   []Small
339         SliceP  []*Small
340         PSlice  *[]Small
341         PSliceP *[]*Small
342
343         EmptySlice []Small
344         NilSlice   []Small
345
346         StringSlice []string
347         ByteSlice   []byte
348
349         Small   Small
350         PSmall  *Small
351         PPSmall **Small
352
353         Interface  interface{}
354         PInterface *interface{}
355
356         unexported int
357 }
358
359 type Small struct {
360         Tag string
361 }
362
363 var allValue = All{
364         Bool:    true,
365         Int:     2,
366         Int8:    3,
367         Int16:   4,
368         Int32:   5,
369         Int64:   6,
370         Uint:    7,
371         Uint8:   8,
372         Uint16:  9,
373         Uint32:  10,
374         Uint64:  11,
375         Uintptr: 12,
376         Float32: 14.1,
377         Float64: 15.1,
378         Foo:     "foo",
379         Foo2:    "foo2",
380         IntStr:  42,
381         String:  "16",
382         Map: map[string]Small{
383                 "17": {Tag: "tag17"},
384                 "18": {Tag: "tag18"},
385         },
386         MapP: map[string]*Small{
387                 "19": {Tag: "tag19"},
388                 "20": nil,
389         },
390         EmptyMap:    map[string]Small{},
391         Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
392         SliceP:      []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
393         EmptySlice:  []Small{},
394         StringSlice: []string{"str24", "str25", "str26"},
395         ByteSlice:   []byte{27, 28, 29},
396         Small:       Small{Tag: "tag30"},
397         PSmall:      &Small{Tag: "tag31"},
398         Interface:   5.2,
399 }
400
401 var pallValue = All{
402         PBool:      &allValue.Bool,
403         PInt:       &allValue.Int,
404         PInt8:      &allValue.Int8,
405         PInt16:     &allValue.Int16,
406         PInt32:     &allValue.Int32,
407         PInt64:     &allValue.Int64,
408         PUint:      &allValue.Uint,
409         PUint8:     &allValue.Uint8,
410         PUint16:    &allValue.Uint16,
411         PUint32:    &allValue.Uint32,
412         PUint64:    &allValue.Uint64,
413         PUintptr:   &allValue.Uintptr,
414         PFloat32:   &allValue.Float32,
415         PFloat64:   &allValue.Float64,
416         PString:    &allValue.String,
417         PMap:       &allValue.Map,
418         PMapP:      &allValue.MapP,
419         PSlice:     &allValue.Slice,
420         PSliceP:    &allValue.SliceP,
421         PPSmall:    &allValue.PSmall,
422         PInterface: &allValue.Interface,
423 }
424
425 var allValueIndent = `{
426         "Bool": true,
427         "Int": 2,
428         "Int8": 3,
429         "Int16": 4,
430         "Int32": 5,
431         "Int64": 6,
432         "Uint": 7,
433         "Uint8": 8,
434         "Uint16": 9,
435         "Uint32": 10,
436         "Uint64": 11,
437         "Uintptr": 12,
438         "Float32": 14.1,
439         "Float64": 15.1,
440         "bar": "foo",
441         "bar2": "foo2",
442         "IntStr": "42",
443         "PBool": null,
444         "PInt": null,
445         "PInt8": null,
446         "PInt16": null,
447         "PInt32": null,
448         "PInt64": null,
449         "PUint": null,
450         "PUint8": null,
451         "PUint16": null,
452         "PUint32": null,
453         "PUint64": null,
454         "PUintptr": null,
455         "PFloat32": null,
456         "PFloat64": null,
457         "String": "16",
458         "PString": null,
459         "Map": {
460                 "17": {
461                         "Tag": "tag17"
462                 },
463                 "18": {
464                         "Tag": "tag18"
465                 }
466         },
467         "MapP": {
468                 "19": {
469                         "Tag": "tag19"
470                 },
471                 "20": null
472         },
473         "PMap": null,
474         "PMapP": null,
475         "EmptyMap": {},
476         "NilMap": null,
477         "Slice": [
478                 {
479                         "Tag": "tag20"
480                 },
481                 {
482                         "Tag": "tag21"
483                 }
484         ],
485         "SliceP": [
486                 {
487                         "Tag": "tag22"
488                 },
489                 null,
490                 {
491                         "Tag": "tag23"
492                 }
493         ],
494         "PSlice": null,
495         "PSliceP": null,
496         "EmptySlice": [],
497         "NilSlice": null,
498         "StringSlice": [
499                 "str24",
500                 "str25",
501                 "str26"
502         ],
503         "ByteSlice": "Gxwd",
504         "Small": {
505                 "Tag": "tag30"
506         },
507         "PSmall": {
508                 "Tag": "tag31"
509         },
510         "PPSmall": null,
511         "Interface": 5.2,
512         "PInterface": null
513 }`
514
515 var allValueCompact = strings.Map(noSpace, allValueIndent)
516
517 var pallValueIndent = `{
518         "Bool": false,
519         "Int": 0,
520         "Int8": 0,
521         "Int16": 0,
522         "Int32": 0,
523         "Int64": 0,
524         "Uint": 0,
525         "Uint8": 0,
526         "Uint16": 0,
527         "Uint32": 0,
528         "Uint64": 0,
529         "Uintptr": 0,
530         "Float32": 0,
531         "Float64": 0,
532         "bar": "",
533         "bar2": "",
534         "IntStr": "0",
535         "PBool": true,
536         "PInt": 2,
537         "PInt8": 3,
538         "PInt16": 4,
539         "PInt32": 5,
540         "PInt64": 6,
541         "PUint": 7,
542         "PUint8": 8,
543         "PUint16": 9,
544         "PUint32": 10,
545         "PUint64": 11,
546         "PUintptr": 12,
547         "PFloat32": 14.1,
548         "PFloat64": 15.1,
549         "String": "",
550         "PString": "16",
551         "Map": null,
552         "MapP": null,
553         "PMap": {
554                 "17": {
555                         "Tag": "tag17"
556                 },
557                 "18": {
558                         "Tag": "tag18"
559                 }
560         },
561         "PMapP": {
562                 "19": {
563                         "Tag": "tag19"
564                 },
565                 "20": null
566         },
567         "EmptyMap": null,
568         "NilMap": null,
569         "Slice": null,
570         "SliceP": null,
571         "PSlice": [
572                 {
573                         "Tag": "tag20"
574                 },
575                 {
576                         "Tag": "tag21"
577                 }
578         ],
579         "PSliceP": [
580                 {
581                         "Tag": "tag22"
582                 },
583                 null,
584                 {
585                         "Tag": "tag23"
586                 }
587         ],
588         "EmptySlice": null,
589         "NilSlice": null,
590         "StringSlice": null,
591         "ByteSlice": null,
592         "Small": {
593                 "Tag": ""
594         },
595         "PSmall": null,
596         "PPSmall": {
597                 "Tag": "tag31"
598         },
599         "Interface": null,
600         "PInterface": 5.2
601 }`
602
603 var pallValueCompact = strings.Map(noSpace, pallValueIndent)