github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/encoding/json/scanner_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 "math" 10 "math/rand" 11 "reflect" 12 "testing" 13 ) 14 15 var validTests = []struct { 16 data string 17 ok bool 18 }{ 19 {`foo`, false}, 20 {`}{`, false}, 21 {`{]`, false}, 22 {`{}`, true}, 23 {`{"foo":"bar"}`, true}, 24 {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, 25 } 26 27 func TestValid(t *testing.T) { 28 for _, tt := range validTests { 29 if ok := Valid([]byte(tt.data)); ok != tt.ok { 30 t.Errorf("Valid(%#q) = %v, want %v", tt.data, ok, tt.ok) 31 } 32 } 33 } 34 35 // Tests of simple examples. 36 37 type example struct { 38 compact string 39 indent string 40 } 41 42 var examples = []example{ 43 {`1`, `1`}, 44 {`{}`, `{}`}, 45 {`[]`, `[]`}, 46 {`{"":2}`, "{\n\t\"\": 2\n}"}, 47 {`[3]`, "[\n\t3\n]"}, 48 {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"}, 49 {`{"x":1}`, "{\n\t\"x\": 1\n}"}, 50 {ex1, ex1i}, 51 } 52 53 var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]` 54 55 var ex1i = `[ 56 true, 57 false, 58 null, 59 "x", 60 1, 61 1.5, 62 0, 63 -5e+2 64 ]` 65 66 func TestCompact(t *testing.T) { 67 var buf bytes.Buffer 68 for _, tt := range examples { 69 buf.Reset() 70 if err := Compact(&buf, []byte(tt.compact)); err != nil { 71 t.Errorf("Compact(%#q): %v", tt.compact, err) 72 } else if s := buf.String(); s != tt.compact { 73 t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s) 74 } 75 76 buf.Reset() 77 if err := Compact(&buf, []byte(tt.indent)); err != nil { 78 t.Errorf("Compact(%#q): %v", tt.indent, err) 79 continue 80 } else if s := buf.String(); s != tt.compact { 81 t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact) 82 } 83 } 84 } 85 86 func TestCompactSeparators(t *testing.T) { 87 // U+2028 and U+2029 should be escaped inside strings. 88 // They should not appear outside strings. 89 tests := []struct { 90 in, compact string 91 }{ 92 {"{\"\u2028\": 1}", `{"\u2028":1}`}, 93 {"{\"\u2029\" :2}", `{"\u2029":2}`}, 94 } 95 for _, tt := range tests { 96 var buf bytes.Buffer 97 if err := Compact(&buf, []byte(tt.in)); err != nil { 98 t.Errorf("Compact(%q): %v", tt.in, err) 99 } else if s := buf.String(); s != tt.compact { 100 t.Errorf("Compact(%q) = %q, want %q", tt.in, s, tt.compact) 101 } 102 } 103 } 104 105 func TestIndent(t *testing.T) { 106 var buf bytes.Buffer 107 for _, tt := range examples { 108 buf.Reset() 109 if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil { 110 t.Errorf("Indent(%#q): %v", tt.indent, err) 111 } else if s := buf.String(); s != tt.indent { 112 t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s) 113 } 114 115 buf.Reset() 116 if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil { 117 t.Errorf("Indent(%#q): %v", tt.compact, err) 118 continue 119 } else if s := buf.String(); s != tt.indent { 120 t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent) 121 } 122 } 123 } 124 125 // Tests of a large random structure. 126 127 func TestCompactBig(t *testing.T) { 128 initBig() 129 var buf bytes.Buffer 130 if err := Compact(&buf, jsonBig); err != nil { 131 t.Fatalf("Compact: %v", err) 132 } 133 b := buf.Bytes() 134 if !bytes.Equal(b, jsonBig) { 135 t.Error("Compact(jsonBig) != jsonBig") 136 diff(t, b, jsonBig) 137 return 138 } 139 } 140 141 func TestIndentBig(t *testing.T) { 142 t.Parallel() 143 initBig() 144 var buf bytes.Buffer 145 if err := Indent(&buf, jsonBig, "", "\t"); err != nil { 146 t.Fatalf("Indent1: %v", err) 147 } 148 b := buf.Bytes() 149 if len(b) == len(jsonBig) { 150 // jsonBig is compact (no unnecessary spaces); 151 // indenting should make it bigger 152 t.Fatalf("Indent(jsonBig) did not get bigger") 153 } 154 155 // should be idempotent 156 var buf1 bytes.Buffer 157 if err := Indent(&buf1, b, "", "\t"); err != nil { 158 t.Fatalf("Indent2: %v", err) 159 } 160 b1 := buf1.Bytes() 161 if !bytes.Equal(b1, b) { 162 t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)") 163 diff(t, b1, b) 164 return 165 } 166 167 // should get back to original 168 buf1.Reset() 169 if err := Compact(&buf1, b); err != nil { 170 t.Fatalf("Compact: %v", err) 171 } 172 b1 = buf1.Bytes() 173 if !bytes.Equal(b1, jsonBig) { 174 t.Error("Compact(Indent(jsonBig)) != jsonBig") 175 diff(t, b1, jsonBig) 176 return 177 } 178 } 179 180 type indentErrorTest struct { 181 in string 182 err error 183 } 184 185 var indentErrorTests = []indentErrorTest{ 186 {`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}}, 187 {`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}}, 188 } 189 190 func TestIndentErrors(t *testing.T) { 191 for i, tt := range indentErrorTests { 192 slice := make([]uint8, 0) 193 buf := bytes.NewBuffer(slice) 194 if err := Indent(buf, []uint8(tt.in), "", ""); err != nil { 195 if !reflect.DeepEqual(err, tt.err) { 196 t.Errorf("#%d: Indent: %#v", i, err) 197 continue 198 } 199 } 200 } 201 } 202 203 func TestNextValueBig(t *testing.T) { 204 initBig() 205 var scan scanner 206 item, rest, err := nextValue(jsonBig, &scan) 207 if err != nil { 208 t.Fatalf("nextValue: %s", err) 209 } 210 if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] { 211 t.Errorf("invalid item: %d %d", len(item), len(jsonBig)) 212 } 213 if len(rest) != 0 { 214 t.Errorf("invalid rest: %d", len(rest)) 215 } 216 217 item, rest, err = nextValue(append(jsonBig, "HELLO WORLD"...), &scan) 218 if err != nil { 219 t.Fatalf("nextValue extra: %s", err) 220 } 221 if len(item) != len(jsonBig) { 222 t.Errorf("invalid item: %d %d", len(item), len(jsonBig)) 223 } 224 if string(rest) != "HELLO WORLD" { 225 t.Errorf("invalid rest: %d", len(rest)) 226 } 227 } 228 229 var benchScan scanner 230 231 func BenchmarkSkipValue(b *testing.B) { 232 initBig() 233 b.ResetTimer() 234 for i := 0; i < b.N; i++ { 235 nextValue(jsonBig, &benchScan) 236 } 237 b.SetBytes(int64(len(jsonBig))) 238 } 239 240 func diff(t *testing.T, a, b []byte) { 241 for i := 0; ; i++ { 242 if i >= len(a) || i >= len(b) || a[i] != b[i] { 243 j := i - 10 244 if j < 0 { 245 j = 0 246 } 247 t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:])) 248 return 249 } 250 } 251 } 252 253 func trim(b []byte) []byte { 254 if len(b) > 20 { 255 return b[0:20] 256 } 257 return b 258 } 259 260 // Generate a random JSON object. 261 262 var jsonBig []byte 263 264 func initBig() { 265 n := 10000 266 if testing.Short() { 267 n = 100 268 } 269 b, err := Marshal(genValue(n)) 270 if err != nil { 271 panic(err) 272 } 273 jsonBig = b 274 } 275 276 func genValue(n int) interface{} { 277 if n > 1 { 278 switch rand.Intn(2) { 279 case 0: 280 return genArray(n) 281 case 1: 282 return genMap(n) 283 } 284 } 285 switch rand.Intn(3) { 286 case 0: 287 return rand.Intn(2) == 0 288 case 1: 289 return rand.NormFloat64() 290 case 2: 291 return genString(30) 292 } 293 panic("unreachable") 294 } 295 296 func genString(stddev float64) string { 297 n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2)) 298 c := make([]rune, n) 299 for i := range c { 300 f := math.Abs(rand.NormFloat64()*64 + 32) 301 if f > 0x10ffff { 302 f = 0x10ffff 303 } 304 c[i] = rune(f) 305 } 306 return string(c) 307 } 308 309 func genArray(n int) []interface{} { 310 f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 311 if f > n { 312 f = n 313 } 314 if f < 1 { 315 f = 1 316 } 317 x := make([]interface{}, f) 318 for i := range x { 319 x[i] = genValue(((i+1)*n)/f - (i*n)/f) 320 } 321 return x 322 } 323 324 func genMap(n int) map[string]interface{} { 325 f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 326 if f > n { 327 f = n 328 } 329 if n > 0 && f == 0 { 330 f = 1 331 } 332 x := make(map[string]interface{}) 333 for i := 0; i < f; i++ { 334 x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f) 335 } 336 return x 337 }