Home | History | Annotate | Download | only in json
      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 }
    338