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.
24 var txType = reflect.TypeOf((*tx)(nil)).Elem()
26 // A type that can unmarshal itself.
28 type unmarshaler struct {
32 func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
33 *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
42 um0, um1 unmarshaler // target2 of unmarshaling
44 umtrue = unmarshaler{true}
45 umslice = []unmarshaler{unmarshaler{true}}
46 umslicep = new([]unmarshaler)
47 umstruct = ustruct{unmarshaler{true}}
50 type unmarshalTest struct {
57 var unmarshalTests = []unmarshalTest{
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)}},
72 {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
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},
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},
92 func TestMarshal(t *testing.T) {
93 b, err := Marshal(allValue)
95 t.Fatalf("Marshal allValue: %v", err)
97 if string(b) != allValueCompact {
98 t.Errorf("Marshal allValueCompact")
99 diff(t, b, []byte(allValueCompact))
103 b, err = Marshal(pallValue)
105 t.Fatalf("Marshal pallValue: %v", err)
107 if string(b) != pallValueCompact {
108 t.Errorf("Marshal pallValueCompact")
109 diff(t, b, []byte(pallValueCompact))
114 func TestMarshalBadUTF8(t *testing.T) {
115 s := "hello\xffworld"
118 t.Fatal("Marshal bad UTF8: no error")
121 t.Fatal("Marshal returned data")
123 if _, ok := err.(*InvalidUTF8Error); !ok {
124 t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
128 func TestUnmarshal(t *testing.T) {
129 for i, tt := range unmarshalTests {
132 if err := checkValid(in, &scan); err != nil {
133 if !reflect.DeepEqual(err, tt.err) {
134 t.Errorf("#%d: checkValid: %#v", i, err)
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)
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))
158 func TestUnmarshalMarshal(t *testing.T) {
161 if err := Unmarshal(jsonBig, &v); err != nil {
162 t.Fatalf("Unmarshal: %v", err)
166 t.Fatalf("Marshal: %v", err)
168 if bytes.Compare(jsonBig, b) != 0 {
169 t.Errorf("Marshal jsonBig")
175 func TestLargeByteSlice(t *testing.T) {
176 s0 := make([]byte, 2000)
180 b, err := Marshal(s0)
182 t.Fatalf("Marshal: %v", err)
185 if err := Unmarshal(b, &s1); err != nil {
186 t.Fatalf("Unmarshal: %v", err)
188 if bytes.Compare(s0, s1) != 0 {
189 t.Errorf("Marshal large byte slice")
198 func TestUnmarshalInterface(t *testing.T) {
200 var i interface{} = &xint
201 if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
202 t.Fatalf("Unmarshal: %v", err)
205 t.Fatalf("Did not write to xint")
209 func TestUnmarshalPtrPtr(t *testing.T) {
212 if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
213 t.Fatalf("Unmarshal: %v", err)
216 t.Fatalf("Did not write to xint")
220 func TestEscape(t *testing.T) {
221 const input = `"foobar"<html>`
222 const expected = `"\"foobar\"\u003chtml\u003e"`
223 b, err := Marshal(input)
225 t.Fatalf("Marshal error: %v", err)
227 if s := string(b); s != expected {
228 t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
232 func TestHTMLEscape(t *testing.T) {
233 b, err := MarshalForHTML("foobarbaz<>&quux")
235 t.Fatalf("MarshalForHTML error: %v", err)
237 if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
238 t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
242 func noSpace(c int) int {
265 Foo string `json:"bar"`
266 Foo2 string `json:"bar2,dummyopt"`
268 IntStr int64 `json:",string"`
289 MapP map[string]*Small
290 PMap *map[string]Small
291 PMapP *map[string]*Small
293 EmptyMap map[string]Small
294 NilMap map[string]Small
311 Interface interface{}
312 PInterface *interface{}
340 Map: map[string]Small{
341 "17": {Tag: "tag17"},
342 "18": {Tag: "tag18"},
344 MapP: map[string]*Small{
345 "19": &Small{Tag: "tag19"},
348 EmptyMap: map[string]Small{},
349 Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
350 SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
351 EmptySlice: []Small{},
352 StringSlice: []string{"str24", "str25", "str26"},
353 ByteSlice: []byte{27, 28, 29},
354 Small: Small{Tag: "tag30"},
355 PSmall: &Small{Tag: "tag31"},
360 PBool: &allValue.Bool,
362 PInt8: &allValue.Int8,
363 PInt16: &allValue.Int16,
364 PInt32: &allValue.Int32,
365 PInt64: &allValue.Int64,
366 PUint: &allValue.Uint,
367 PUint8: &allValue.Uint8,
368 PUint16: &allValue.Uint16,
369 PUint32: &allValue.Uint32,
370 PUint64: &allValue.Uint64,
371 PUintptr: &allValue.Uintptr,
372 PFloat32: &allValue.Float32,
373 PFloat64: &allValue.Float64,
374 PString: &allValue.String,
376 PMapP: &allValue.MapP,
377 PSlice: &allValue.Slice,
378 PSliceP: &allValue.SliceP,
379 PPSmall: &allValue.PSmall,
380 PInterface: &allValue.Interface,
383 var allValueIndent = `{
473 var allValueCompact = strings.Map(noSpace, allValueIndent)
475 var pallValueIndent = `{
561 var pallValueCompact = strings.Map(noSpace, pallValueIndent)