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 5package json 6 7import ( 8 "bytes" 9 "io" 10 "io/ioutil" 11 "log" 12 "net" 13 "net/http" 14 "net/http/httptest" 15 "reflect" 16 "strings" 17 "testing" 18) 19 20// Test values for the stream test. 21// One of each JSON kind. 22var streamTest = []interface{}{ 23 0.1, 24 "hello", 25 nil, 26 true, 27 false, 28 []interface{}{"a", "b", "c"}, 29 map[string]interface{}{"K": "Kelvin", "ß": "long s"}, 30 3.14, // another value to make sure something can follow map 31} 32 33var streamEncoded = `0.1 34"hello" 35null 36true 37false 38["a","b","c"] 39{"ß":"long s","K":"Kelvin"} 403.14 41` 42 43func TestEncoder(t *testing.T) { 44 for i := 0; i <= len(streamTest); i++ { 45 var buf bytes.Buffer 46 enc := NewEncoder(&buf) 47 for j, v := range streamTest[0:i] { 48 if err := enc.Encode(v); err != nil { 49 t.Fatalf("encode #%d: %v", j, err) 50 } 51 } 52 if have, want := buf.String(), nlines(streamEncoded, i); have != want { 53 t.Errorf("encoding %d items: mismatch", i) 54 diff(t, []byte(have), []byte(want)) 55 break 56 } 57 } 58} 59 60func TestDecoder(t *testing.T) { 61 for i := 0; i <= len(streamTest); i++ { 62 // Use stream without newlines as input, 63 // just to stress the decoder even more. 64 // Our test input does not include back-to-back numbers. 65 // Otherwise stripping the newlines would 66 // merge two adjacent JSON values. 67 var buf bytes.Buffer 68 for _, c := range nlines(streamEncoded, i) { 69 if c != '\n' { 70 buf.WriteRune(c) 71 } 72 } 73 out := make([]interface{}, i) 74 dec := NewDecoder(&buf) 75 for j := range out { 76 if err := dec.Decode(&out[j]); err != nil { 77 t.Fatalf("decode #%d/%d: %v", j, i, err) 78 } 79 } 80 if !reflect.DeepEqual(out, streamTest[0:i]) { 81 t.Errorf("decoding %d items: mismatch", i) 82 for j := range out { 83 if !reflect.DeepEqual(out[j], streamTest[j]) { 84 t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j]) 85 } 86 } 87 break 88 } 89 } 90} 91 92func TestDecoderBuffered(t *testing.T) { 93 r := strings.NewReader(`{"Name": "Gopher"} extra `) 94 var m struct { 95 Name string 96 } 97 d := NewDecoder(r) 98 err := d.Decode(&m) 99 if err != nil { 100 t.Fatal(err) 101 } 102 if m.Name != "Gopher" { 103 t.Errorf("Name = %q; want Gopher", m.Name) 104 } 105 rest, err := ioutil.ReadAll(d.Buffered()) 106 if err != nil { 107 t.Fatal(err) 108 } 109 if g, w := string(rest), " extra "; g != w { 110 t.Errorf("Remaining = %q; want %q", g, w) 111 } 112} 113 114func nlines(s string, n int) string { 115 if n <= 0 { 116 return "" 117 } 118 for i, c := range s { 119 if c == '\n' { 120 if n--; n == 0 { 121 return s[0 : i+1] 122 } 123 } 124 } 125 return s 126} 127 128func TestRawMessage(t *testing.T) { 129 // TODO(rsc): Should not need the * in *RawMessage 130 var data struct { 131 X float64 132 Id *RawMessage 133 Y float32 134 } 135 const raw = `["\u0056",null]` 136 const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}` 137 err := Unmarshal([]byte(msg), &data) 138 if err != nil { 139 t.Fatalf("Unmarshal: %v", err) 140 } 141 if string([]byte(*data.Id)) != raw { 142 t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw) 143 } 144 b, err := Marshal(&data) 145 if err != nil { 146 t.Fatalf("Marshal: %v", err) 147 } 148 if string(b) != msg { 149 t.Fatalf("Marshal: have %#q want %#q", b, msg) 150 } 151} 152 153func TestNullRawMessage(t *testing.T) { 154 // TODO(rsc): Should not need the * in *RawMessage 155 var data struct { 156 X float64 157 Id *RawMessage 158 Y float32 159 } 160 data.Id = new(RawMessage) 161 const msg = `{"X":0.1,"Id":null,"Y":0.2}` 162 err := Unmarshal([]byte(msg), &data) 163 if err != nil { 164 t.Fatalf("Unmarshal: %v", err) 165 } 166 if data.Id != nil { 167 t.Fatalf("Raw mismatch: have non-nil, want nil") 168 } 169 b, err := Marshal(&data) 170 if err != nil { 171 t.Fatalf("Marshal: %v", err) 172 } 173 if string(b) != msg { 174 t.Fatalf("Marshal: have %#q want %#q", b, msg) 175 } 176} 177 178var blockingTests = []string{ 179 `{"x": 1}`, 180 `[1, 2, 3]`, 181} 182 183func TestBlocking(t *testing.T) { 184 for _, enc := range blockingTests { 185 r, w := net.Pipe() 186 go w.Write([]byte(enc)) 187 var val interface{} 188 189 // If Decode reads beyond what w.Write writes above, 190 // it will block, and the test will deadlock. 191 if err := NewDecoder(r).Decode(&val); err != nil { 192 t.Errorf("decoding %s: %v", enc, err) 193 } 194 r.Close() 195 w.Close() 196 } 197} 198 199func BenchmarkEncoderEncode(b *testing.B) { 200 b.ReportAllocs() 201 type T struct { 202 X, Y string 203 } 204 v := &T{"foo", "bar"} 205 for i := 0; i < b.N; i++ { 206 if err := NewEncoder(ioutil.Discard).Encode(v); err != nil { 207 b.Fatal(err) 208 } 209 } 210} 211 212type tokenStreamCase struct { 213 json string 214 expTokens []interface{} 215} 216 217type decodeThis struct { 218 v interface{} 219} 220 221var tokenStreamCases []tokenStreamCase = []tokenStreamCase{ 222 // streaming token cases 223 {json: `10`, expTokens: []interface{}{float64(10)}}, 224 {json: ` [10] `, expTokens: []interface{}{ 225 Delim('['), float64(10), Delim(']')}}, 226 {json: ` [false,10,"b"] `, expTokens: []interface{}{ 227 Delim('['), false, float64(10), "b", Delim(']')}}, 228 {json: `{ "a": 1 }`, expTokens: []interface{}{ 229 Delim('{'), "a", float64(1), Delim('}')}}, 230 {json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{ 231 Delim('{'), "a", float64(1), "b", "3", Delim('}')}}, 232 {json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{ 233 Delim('['), 234 Delim('{'), "a", float64(1), Delim('}'), 235 Delim('{'), "a", float64(2), Delim('}'), 236 Delim(']')}}, 237 {json: `{"obj": {"a": 1}}`, expTokens: []interface{}{ 238 Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'), 239 Delim('}')}}, 240 {json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{ 241 Delim('{'), "obj", Delim('['), 242 Delim('{'), "a", float64(1), Delim('}'), 243 Delim(']'), Delim('}')}}, 244 245 // streaming tokens with intermittent Decode() 246 {json: `{ "a": 1 }`, expTokens: []interface{}{ 247 Delim('{'), "a", 248 decodeThis{float64(1)}, 249 Delim('}')}}, 250 {json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{ 251 Delim('['), 252 decodeThis{map[string]interface{}{"a": float64(1)}}, 253 Delim(']')}}, 254 {json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{ 255 Delim('['), 256 decodeThis{map[string]interface{}{"a": float64(1)}}, 257 decodeThis{map[string]interface{}{"a": float64(2)}}, 258 Delim(']')}}, 259 {json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{ 260 Delim('{'), "obj", Delim('['), 261 decodeThis{map[string]interface{}{"a": float64(1)}}, 262 Delim(']'), Delim('}')}}, 263 264 {json: `{"obj": {"a": 1}}`, expTokens: []interface{}{ 265 Delim('{'), "obj", 266 decodeThis{map[string]interface{}{"a": float64(1)}}, 267 Delim('}')}}, 268 {json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{ 269 Delim('{'), "obj", 270 decodeThis{[]interface{}{ 271 map[string]interface{}{"a": float64(1)}, 272 }}, 273 Delim('}')}}, 274 {json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{ 275 Delim('['), 276 decodeThis{map[string]interface{}{"a": float64(1)}}, 277 decodeThis{&SyntaxError{"expected comma after array element", 0}}, 278 }}, 279 {json: `{ "a" 1 }`, expTokens: []interface{}{ 280 Delim('{'), "a", 281 decodeThis{&SyntaxError{"expected colon after object key", 0}}, 282 }}, 283} 284 285func TestDecodeInStream(t *testing.T) { 286 287 for ci, tcase := range tokenStreamCases { 288 289 dec := NewDecoder(strings.NewReader(tcase.json)) 290 for i, etk := range tcase.expTokens { 291 292 var tk interface{} 293 var err error 294 295 if dt, ok := etk.(decodeThis); ok { 296 etk = dt.v 297 err = dec.Decode(&tk) 298 } else { 299 tk, err = dec.Token() 300 } 301 if experr, ok := etk.(error); ok { 302 if err == nil || err.Error() != experr.Error() { 303 t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err) 304 } 305 break 306 } else if err == io.EOF { 307 t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json) 308 break 309 } else if err != nil { 310 t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json) 311 break 312 } 313 if !reflect.DeepEqual(tk, etk) { 314 t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk) 315 break 316 } 317 } 318 } 319 320} 321 322// Test from golang.org/issue/11893 323func TestHTTPDecoding(t *testing.T) { 324 const raw = `{ "foo": "bar" }` 325 326 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 327 w.Write([]byte(raw)) 328 })) 329 defer ts.Close() 330 res, err := http.Get(ts.URL) 331 if err != nil { 332 log.Fatalf("GET failed: %v", err) 333 } 334 defer res.Body.Close() 335 336 foo := struct { 337 Foo string `json:"foo"` 338 }{} 339 340 d := NewDecoder(res.Body) 341 err = d.Decode(&foo) 342 if err != nil { 343 t.Fatalf("Decode: %v", err) 344 } 345 if foo.Foo != "bar" { 346 t.Errorf("decoded %q; want \"bar\"", foo.Foo) 347 } 348 349 // make sure we get the EOF the second time 350 err = d.Decode(&foo) 351 if err != io.EOF { 352 t.Errorf("err = %v; want io.EOF", err) 353 } 354} 355