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