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