OSDN Git Service

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