OSDN Git Service

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