LEFT | RIGHT |
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package json | 5 package json |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "errors" | |
10 "fmt" | 9 "fmt" |
11 "reflect" | 10 "reflect" |
12 "strings" | 11 "strings" |
13 "testing" | 12 "testing" |
14 ) | 13 ) |
15 | 14 |
16 type T struct { | 15 type T struct { |
17 X string | 16 X string |
18 Y int | 17 Y int |
19 Z int `json:"-"` | 18 Z int `json:"-"` |
20 } | 19 } |
21 | 20 |
22 type U struct { | 21 type U struct { |
23 Alphabet string `json:"alpha"` | 22 Alphabet string `json:"alpha"` |
| 23 } |
| 24 |
| 25 type V struct { |
| 26 F1 interface{} |
| 27 F2 int32 |
| 28 F3 Number |
| 29 } |
| 30 |
| 31 // ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshalling with and |
| 32 // without UseNumber |
| 33 var ifaceNumAsFloat64 = map[string]interface{}{ |
| 34 "k1": float64(1), |
| 35 "k2": "s", |
| 36 "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)}, |
| 37 "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, |
| 38 } |
| 39 |
| 40 var ifaceNumAsNumber = map[string]interface{}{ |
| 41 "k1": Number("1"), |
| 42 "k2": "s", |
| 43 "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")}, |
| 44 "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")}, |
24 } | 45 } |
25 | 46 |
26 type tx struct { | 47 type tx struct { |
27 x int | 48 x int |
28 } | 49 } |
29 | 50 |
30 var txType = reflect.TypeOf((*tx)(nil)).Elem() | 51 var txType = reflect.TypeOf((*tx)(nil)).Elem() |
31 | 52 |
32 // A type that can unmarshal itself. | 53 // A type that can unmarshal itself. |
33 | 54 |
(...skipping 13 matching lines...) Expand all Loading... |
47 var ( | 68 var ( |
48 um0, um1 unmarshaler // target2 of unmarshaling | 69 um0, um1 unmarshaler // target2 of unmarshaling |
49 ump = &um1 | 70 ump = &um1 |
50 umtrue = unmarshaler{true} | 71 umtrue = unmarshaler{true} |
51 umslice = []unmarshaler{{true}} | 72 umslice = []unmarshaler{{true}} |
52 umslicep = new([]unmarshaler) | 73 umslicep = new([]unmarshaler) |
53 umstruct = ustruct{unmarshaler{true}} | 74 umstruct = ustruct{unmarshaler{true}} |
54 ) | 75 ) |
55 | 76 |
56 type unmarshalTest struct { | 77 type unmarshalTest struct { |
57 » in string | 78 » in string |
58 » ptr interface{} | 79 » ptr interface{} |
59 » out interface{} | 80 » out interface{} |
60 » err error | 81 » err error |
| 82 » useNumber bool |
61 } | 83 } |
62 | 84 |
63 var unmarshalTests = []unmarshalTest{ | 85 var unmarshalTests = []unmarshalTest{ |
64 // basic types | 86 // basic types |
65 » {`true`, new(bool), true, nil}, | 87 » {in: `true`, ptr: new(bool), out: true}, |
66 » {`1`, new(int), 1, nil}, | 88 » {in: `1`, ptr: new(int), out: 1}, |
67 » {`1.2`, new(float64), 1.2, nil}, | 89 » {in: `1.2`, ptr: new(float64), out: 1.2}, |
68 » {`-5`, new(int16), int16(-5), nil}, | 90 » {in: `-5`, ptr: new(int16), out: int16(-5)}, |
69 » {`"a\u1234"`, new(string), "a\u1234", nil}, | 91 » {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, |
70 » {`"http:\/\/"`, new(string), "http://", nil}, | 92 » {in: `2`, ptr: new(Number), out: Number("2")}, |
71 » {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil}, | 93 » {in: `2`, ptr: new(interface{}), out: float64(2.0)}, |
72 » {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil}
, | 94 » {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true}, |
73 » {"null", new(interface{}), nil, nil}, | 95 » {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, |
74 » {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array",
reflect.TypeOf("")}}, | 96 » {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, |
75 » {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Fie
ld(0)}}, | 97 » {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11
E"}, |
| 98 » {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFD
x\uFFFD"}, |
| 99 » {in: "null", ptr: new(interface{}), out: nil}, |
| 100 » {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &Unmarsha
lTypeError{"array", reflect.TypeOf("")}}, |
| 101 » {in: `{"x": 1}`, ptr: new(tx), out: tx{}, err: &UnmarshalFieldError{"x",
txType, txType.Field(0)}}, |
| 102 » {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: i
nt32(2), F3: Number("3")}}, |
| 103 » {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2:
int32(2), F3: Number("3")}, useNumber: true}, |
| 104 » {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr
: new(interface{}), out: ifaceNumAsFloat64}, |
| 105 » {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr
: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, |
76 | 106 |
77 // Z has a "-" tag. | 107 // Z has a "-" tag. |
78 » {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil}, | 108 » {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, |
79 | 109 |
80 » {`{"alpha": "abc", "alphabet": "xyz"}`, new(U), U{Alphabet: "abc"}, nil}
, | 110 » {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet
: "abc"}}, |
81 » {`{"alpha": "abc"}`, new(U), U{Alphabet: "abc"}, nil}, | 111 » {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, |
82 » {`{"alphabet": "xyz"}`, new(U), U{}, nil}, | 112 » {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, |
83 | 113 |
84 // syntax errors | 114 // syntax errors |
85 » {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' afte
r object key", 17}}, | 115 » {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after
object key", 17}}, |
86 » {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array
element", 9}}, | 116 » {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array
element", 9}}, |
| 117 » {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object
key:value pair", 8}, useNumber: true}, |
87 | 118 |
88 // array tests | 119 // array tests |
89 » {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil}, | 120 » {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, |
90 » {`[1, 2, 3]`, new([1]int), [1]int{1}, nil}, | 121 » {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, |
91 » {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil}, | 122 » {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, |
92 | 123 |
93 // composite tests | 124 // composite tests |
94 » {allValueIndent, new(All), allValue, nil}, | 125 » {in: allValueIndent, ptr: new(All), out: allValue}, |
95 » {allValueCompact, new(All), allValue, nil}, | 126 » {in: allValueCompact, ptr: new(All), out: allValue}, |
96 » {allValueIndent, new(*All), &allValue, nil}, | 127 » {in: allValueIndent, ptr: new(*All), out: &allValue}, |
97 » {allValueCompact, new(*All), &allValue, nil}, | 128 » {in: allValueCompact, ptr: new(*All), out: &allValue}, |
98 » {pallValueIndent, new(All), pallValue, nil}, | 129 » {in: pallValueIndent, ptr: new(All), out: pallValue}, |
99 » {pallValueCompact, new(All), pallValue, nil}, | 130 » {in: pallValueCompact, ptr: new(All), out: pallValue}, |
100 » {pallValueIndent, new(*All), &pallValue, nil}, | 131 » {in: pallValueIndent, ptr: new(*All), out: &pallValue}, |
101 » {pallValueCompact, new(*All), &pallValue, nil}, | 132 » {in: pallValueCompact, ptr: new(*All), out: &pallValue}, |
102 | 133 |
103 // unmarshal interface test | 134 // unmarshal interface test |
104 » {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if
custom unmarshaler is not called | 135 » {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will
fail if custom unmarshaler is not called |
105 » {`{"T":false}`, &ump, &umtrue, nil}, | 136 » {in: `{"T":false}`, ptr: &ump, out: &umtrue}, |
106 » {`[{"T":false}]`, &umslice, umslice, nil}, | 137 » {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, |
107 » {`[{"T":false}]`, &umslicep, &umslice, nil}, | 138 » {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, |
108 » {`{"M":{"T":false}}`, &umstruct, umstruct, nil}, | 139 » {in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct}, |
109 } | 140 } |
110 | 141 |
111 func TestMarshal(t *testing.T) { | 142 func TestMarshal(t *testing.T) { |
112 b, err := Marshal(allValue) | 143 b, err := Marshal(allValue) |
113 if err != nil { | 144 if err != nil { |
114 t.Fatalf("Marshal allValue: %v", err) | 145 t.Fatalf("Marshal allValue: %v", err) |
115 } | 146 } |
116 if string(b) != allValueCompact { | 147 if string(b) != allValueCompact { |
117 t.Errorf("Marshal allValueCompact") | 148 t.Errorf("Marshal allValueCompact") |
118 diff(t, b, []byte(allValueCompact)) | 149 diff(t, b, []byte(allValueCompact)) |
(...skipping 15 matching lines...) Expand all Loading... |
134 s := "hello\xffworld" | 165 s := "hello\xffworld" |
135 b, err := Marshal(s) | 166 b, err := Marshal(s) |
136 if err == nil { | 167 if err == nil { |
137 t.Fatal("Marshal bad UTF8: no error") | 168 t.Fatal("Marshal bad UTF8: no error") |
138 } | 169 } |
139 if len(b) != 0 { | 170 if len(b) != 0 { |
140 t.Fatal("Marshal returned data") | 171 t.Fatal("Marshal returned data") |
141 } | 172 } |
142 if _, ok := err.(*InvalidUTF8Error); !ok { | 173 if _, ok := err.(*InvalidUTF8Error); !ok { |
143 t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err,
err) | 174 t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err,
err) |
| 175 } |
| 176 } |
| 177 |
| 178 func TestMarshalNumberZeroVal(t *testing.T) { |
| 179 var n Number |
| 180 out, err := Marshal(n) |
| 181 if err != nil { |
| 182 t.Fatal(err) |
| 183 } |
| 184 outStr := string(out) |
| 185 if outStr != "0" { |
| 186 t.Fatalf("Invalid zero val for Number: %q", outStr) |
144 } | 187 } |
145 } | 188 } |
146 | 189 |
147 func TestUnmarshal(t *testing.T) { | 190 func TestUnmarshal(t *testing.T) { |
148 for i, tt := range unmarshalTests { | 191 for i, tt := range unmarshalTests { |
149 var scan scanner | 192 var scan scanner |
150 in := []byte(tt.in) | 193 in := []byte(tt.in) |
151 if err := checkValid(in, &scan); err != nil { | 194 if err := checkValid(in, &scan); err != nil { |
152 if !reflect.DeepEqual(err, tt.err) { | 195 if !reflect.DeepEqual(err, tt.err) { |
153 t.Errorf("#%d: checkValid: %#v", i, err) | 196 t.Errorf("#%d: checkValid: %#v", i, err) |
154 continue | 197 continue |
155 } | 198 } |
156 } | 199 } |
157 if tt.ptr == nil { | 200 if tt.ptr == nil { |
158 continue | 201 continue |
159 } | 202 } |
160 // v = new(right-type) | 203 // v = new(right-type) |
161 v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) | 204 v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) |
162 » » if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqu
al(err, tt.err) { | 205 » » dec := NewDecoder(bytes.NewBuffer(in)) |
| 206 » » if tt.useNumber { |
| 207 » » » dec.UseNumber() |
| 208 » » } |
| 209 » » if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.
err) { |
163 t.Errorf("#%d: %v want %v", i, err, tt.err) | 210 t.Errorf("#%d: %v want %v", i, err, tt.err) |
164 continue | 211 continue |
165 } | 212 } |
166 if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { | 213 if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { |
167 t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.E
lem().Interface(), tt.out) | 214 t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.E
lem().Interface(), tt.out) |
168 data, _ := Marshal(v.Elem().Interface()) | 215 data, _ := Marshal(v.Elem().Interface()) |
169 println(string(data)) | 216 println(string(data)) |
170 data, _ = Marshal(tt.out) | 217 data, _ = Marshal(tt.out) |
171 println(string(data)) | 218 println(string(data)) |
172 continue | 219 continue |
173 } | 220 } |
| 221 |
| 222 // Check round trip. |
| 223 if tt.err == nil { |
| 224 enc, err := Marshal(v.Interface()) |
| 225 if err != nil { |
| 226 t.Errorf("#%d: error re-marshaling: %v", i, err) |
| 227 continue |
| 228 } |
| 229 vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) |
| 230 dec = NewDecoder(bytes.NewBuffer(enc)) |
| 231 if tt.useNumber { |
| 232 dec.UseNumber() |
| 233 } |
| 234 if err := dec.Decode(vv.Interface()); err != nil { |
| 235 t.Errorf("#%d: error re-unmarshaling: %v", i, er
r) |
| 236 continue |
| 237 } |
| 238 if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().In
terface()) { |
| 239 t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v"
, i, v.Elem().Interface(), vv.Elem().Interface()) |
| 240 continue |
| 241 } |
| 242 } |
174 } | 243 } |
175 } | 244 } |
176 | 245 |
177 func TestUnmarshalMarshal(t *testing.T) { | 246 func TestUnmarshalMarshal(t *testing.T) { |
178 initBig() | 247 initBig() |
179 var v interface{} | 248 var v interface{} |
180 if err := Unmarshal(jsonBig, &v); err != nil { | 249 if err := Unmarshal(jsonBig, &v); err != nil { |
181 t.Fatalf("Unmarshal: %v", err) | 250 t.Fatalf("Unmarshal: %v", err) |
182 } | 251 } |
183 b, err := Marshal(v) | 252 b, err := Marshal(v) |
184 if err != nil { | 253 if err != nil { |
185 t.Fatalf("Marshal: %v", err) | 254 t.Fatalf("Marshal: %v", err) |
186 } | 255 } |
187 if bytes.Compare(jsonBig, b) != 0 { | 256 if bytes.Compare(jsonBig, b) != 0 { |
188 t.Errorf("Marshal jsonBig") | 257 t.Errorf("Marshal jsonBig") |
189 diff(t, b, jsonBig) | 258 diff(t, b, jsonBig) |
190 return | 259 return |
191 } | 260 } |
192 } | 261 } |
193 | 262 |
194 // A custom numeric type (for testing, just wraps the underlying numeric string) | 263 var numberTests = []struct { |
195 type customNum string | 264 » in string |
196 | 265 » i int64 |
197 // An implementation of NumberConverter which converts the string "1" to its | 266 » intErr string |
198 // customNum form; any other string is treated as an invalid number | 267 » f float64 |
199 type numConvImpl struct{} | 268 » floatErr string |
200 | 269 }{ |
201 func (i *numConvImpl) ConvertNumber(s string) (interface{}, error) { | 270 » {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid
syntax", f: -1.23e1}, |
202 » if s == "1" { | 271 » {in: "-12", i: -12, f: -12.0}, |
203 » » return customNum(s), nil | 272 » {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid sy
ntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, |
204 » } | 273 } |
205 » return nil, errors.New(s) | 274 |
206 } | 275 // Independent of Decode, basic coverage of the accessors in Number |
207 | 276 func TestNumberAccessors(t *testing.T) { |
208 // test struct to hold an unmarshal, providing sufficient fields for us to test | 277 » for _, tt := range numberTests { |
209 // that an interface{} leads to invocation of a NumberConverter handler for | 278 » » n := Number(tt.in) |
210 // simple named fields (F1), that it is not invoked for more strongly typed | 279 » » if s := n.String(); s != tt.in { |
211 // fields (F2,F4), and that it is invoked deep in map[string]interface{} and in | 280 » » » t.Errorf("Number(%q).String() is %q", tt.in, s) |
212 // []interface{} (F3) | 281 » » } |
213 type numConvHolder struct { | 282 » » if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt
.i { |
214 » F1 interface{} | 283 » » » t.Errorf("Number(%q).Int64() is %d", tt.in, i) |
215 » F2 int32 | 284 » » } else if (err == nil && tt.intErr != "") || (err != nil && err.
Error() != tt.intErr) { |
216 » F3 interface{} | 285 » » » t.Errorf("Number(%q).Int64() wanted error %q but got: %v
", tt.in, tt.intErr, err) |
217 » F4 []int32 | 286 » » } |
218 } | 287 » » if f, err := n.Float64(); err == nil && tt.floatErr == "" && f !
= tt.f { |
219 | 288 » » » t.Errorf("Number(%q).Float64() is %g", tt.in, f) |
220 // 2 passes: first covers our various success cases; second ensures that errors | 289 » » } else if (err == nil && tt.floatErr != "") || (err != nil && er
r.Error() != tt.floatErr) { |
221 // from a NumberConverter are propagated out and messaged meaningfully· | 290 » » » t.Errorf("Number(%q).Float64() wanted error %q but got:
%v", tt.in, tt.floatErr, err) |
222 func TestUnmarshalWithNumConverter(t *testing.T) { | |
223 » in := `{"F1":1,"F2":2,"F3":{"f1":1,"f2":[1]},"F4":[1,2,3]}` | |
224 » dec := NewDecoder(bytes.NewBufferString(in)) | |
225 » dec.SetNumberConverter(&numConvImpl{}) | |
226 » act := new(numConvHolder) | |
227 » if err := dec.Decode(act); err == nil { | |
228 » » expct := &numConvHolder{F1: customNum("1"), F2: 2, F4: []int32{1
, 2, 3}} | |
229 » » m := make(map[string]interface{}) | |
230 » » m["f1"] = customNum("1") | |
231 » » m["f2"] = []interface{}{customNum("1")} | |
232 » » expct.F3 = m | |
233 » » if !reflect.DeepEqual(expct, act) { | |
234 » » » t.Fatalf("%#v != %#v", act, expct) | |
235 » » } | |
236 » } else { | |
237 » » t.Fatal(err) | |
238 » } | |
239 » // now check that error from a NumberConverter causes decode to fail in
the | |
240 » // same way as an error from strconv.ParseFloat() would, either as a | |
241 » // top-level field or in some generic composite type: | |
242 » errTxts := []string{`{"F1":2}`, `{"F3":[2]}`, `{"F3":{"i":2}}`} | |
243 » for _, errTxt := range errTxts { | |
244 » » dec = NewDecoder(bytes.NewBufferString(errTxt)) | |
245 » » dec.SetNumberConverter(&numConvImpl{}) | |
246 » » act = new(numConvHolder) | |
247 » » if err := dec.Decode(act); err == nil { | |
248 » » » t.Fatalf("no decode error") | |
249 » » } else { | |
250 » » » if err.Error() != "json: cannot unmarshal number 2 into
Go value of type *json.numConvImpl" { | |
251 » » » » t.Fatal(err) | |
252 » » » } | |
253 } | 291 } |
254 } | 292 } |
255 } | 293 } |
256 | 294 |
257 func TestLargeByteSlice(t *testing.T) { | 295 func TestLargeByteSlice(t *testing.T) { |
258 s0 := make([]byte, 2000) | 296 s0 := make([]byte, 2000) |
259 for i := range s0 { | 297 for i := range s0 { |
260 s0[i] = byte(i) | 298 s0[i] = byte(i) |
261 } | 299 } |
262 b, err := Marshal(s0) | 300 b, err := Marshal(s0) |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 dec := NewDecoder(strings.NewReader(data)) | 760 dec := NewDecoder(strings.NewReader(data)) |
723 var t2 T2 | 761 var t2 T2 |
724 err := dec.Decode(&t2) | 762 err := dec.Decode(&t2) |
725 if err == nil { | 763 if err == nil { |
726 t.Fatal("Decode: did not return error") | 764 t.Fatal("Decode: did not return error") |
727 } | 765 } |
728 if t2.Number1 != 1 { | 766 if t2.Number1 != 1 { |
729 t.Fatal("Decode: did not set Number1") | 767 t.Fatal("Decode: did not set Number1") |
730 } | 768 } |
731 } | 769 } |
| 770 |
| 771 func intp(x int) *int { |
| 772 p := new(int) |
| 773 *p = x |
| 774 return p |
| 775 } |
| 776 |
| 777 func intpp(x *int) **int { |
| 778 pp := new(*int) |
| 779 *pp = x |
| 780 return pp |
| 781 } |
| 782 |
| 783 var interfaceSetTests = []struct { |
| 784 pre interface{} |
| 785 json string |
| 786 post interface{} |
| 787 }{ |
| 788 {"foo", `"bar"`, "bar"}, |
| 789 {"foo", `2`, 2.0}, |
| 790 {"foo", `true`, true}, |
| 791 {"foo", `null`, nil}, |
| 792 |
| 793 {nil, `null`, nil}, |
| 794 {new(int), `null`, nil}, |
| 795 {(*int)(nil), `null`, nil}, |
| 796 {new(*int), `null`, new(*int)}, |
| 797 {(**int)(nil), `null`, nil}, |
| 798 {intp(1), `null`, nil}, |
| 799 {intpp(nil), `null`, intpp(nil)}, |
| 800 {intpp(intp(1)), `null`, intpp(nil)}, |
| 801 } |
| 802 |
| 803 func TestInterfaceSet(t *testing.T) { |
| 804 for _, tt := range interfaceSetTests { |
| 805 b := struct{ X interface{} }{tt.pre} |
| 806 blob := `{"X":` + tt.json + `}` |
| 807 if err := Unmarshal([]byte(blob), &b); err != nil { |
| 808 t.Errorf("Unmarshal %#q: %v", blob, err) |
| 809 continue |
| 810 } |
| 811 if !reflect.DeepEqual(b.X, tt.post) { |
| 812 t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob
, tt.pre, b.X, tt.post) |
| 813 } |
| 814 } |
| 815 } |
LEFT | RIGHT |