1
2
3
4
5 package json
6
7 import (
8 "bytes"
9 "math"
10 "rand"
11 "testing"
12 )
13
14
15
16 type example struct {
17 compact string
18 indent string
19 }
20
21 var examples = []example{
22 {`1`, `1`},
23 {`{}`, `{}`},
24 {`[]`, `[]`},
25 {`{"":2}`, "{\n\t\"\": 2\n}"},
26 {`[3]`, "[\n\t3\n]"},
27 {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
28 {`{"x":1}`, "{\n\t\"x\": 1\n}"},
29 {ex1, ex1i},
30 }
31
32 var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
33
34 var ex1i = `[
35 true,
36 false,
37 null,
38 "x",
39 1,
40 1.5,
41 0,
42 -5e+2
43 ]`
44
45 func TestCompact(t *testing.T) {
46 var buf bytes.Buffer
47 for _, tt := range examples {
48 buf.Reset()
49 if err := Compact(&buf, []byte(tt.compact)); err != nil {
50 t.Errorf("Compact(%#q): %v", tt.compact, err)
51 } else if s := buf.String(); s != tt.compact {
52 t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
53 }
54
55 buf.Reset()
56 if err := Compact(&buf, []byte(tt.indent)); err != nil {
57 t.Errorf("Compact(%#q): %v", tt.indent, err)
58 continue
59 } else if s := buf.String(); s != tt.compact {
60 t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
61 }
62 }
63 }
64
65 func TestIndent(t *testing.T) {
66 var buf bytes.Buffer
67 for _, tt := range examples {
68 buf.Reset()
69 if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
70 t.Errorf("Indent(%#q): %v", tt.indent, err)
71 } else if s := buf.String(); s != tt.indent {
72 t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
73 }
74
75 buf.Reset()
76 if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
77 t.Errorf("Indent(%#q): %v", tt.compact, err)
78 continue
79 } else if s := buf.String(); s != tt.indent {
80 t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
81 }
82 }
83 }
84
85
86
87 func TestCompactBig(t *testing.T) {
88 initBig()
89 var buf bytes.Buffer
90 if err := Compact(&buf, jsonBig); err != nil {
91 t.Fatalf("Compact: %v", err)
92 }
93 b := buf.Bytes()
94 if bytes.Compare(b, jsonBig) != 0 {
95 t.Error("Compact(jsonBig) != jsonBig")
96 diff(t, b, jsonBig)
97 return
98 }
99 }
100
101 func TestIndentBig(t *testing.T) {
102 initBig()
103 var buf bytes.Buffer
104 if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
105 t.Fatalf("Indent1: %v", err)
106 }
107 b := buf.Bytes()
108 if len(b) == len(jsonBig) {
109
110
111 t.Fatalf("Indent(jsonBig) did not get bigger")
112 }
113
114
115 var buf1 bytes.Buffer
116 if err := Indent(&buf1, b, "", "\t"); err != nil {
117 t.Fatalf("Indent2: %v", err)
118 }
119 b1 := buf1.Bytes()
120 if bytes.Compare(b1, b) != 0 {
121 t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
122 diff(t, b1, b)
123 return
124 }
125
126
127 buf1.Reset()
128 if err := Compact(&buf1, b); err != nil {
129 t.Fatalf("Compact: %v", err)
130 }
131 b1 = buf1.Bytes()
132 if bytes.Compare(b1, jsonBig) != 0 {
133 t.Error("Compact(Indent(jsonBig)) != jsonBig")
134 diff(t, b1, jsonBig)
135 return
136 }
137 }
138
139 func TestNextValueBig(t *testing.T) {
140 initBig()
141 var scan scanner
142 item, rest, err := nextValue(jsonBig, &scan)
143 if err != nil {
144 t.Fatalf("nextValue: %s", err)
145 }
146 if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
147 t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
148 }
149 if len(rest) != 0 {
150 t.Errorf("invalid rest: %d", len(rest))
151 }
152
153 item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
154 if err != nil {
155 t.Fatalf("nextValue extra: %s", err)
156 }
157 if len(item) != len(jsonBig) {
158 t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
159 }
160 if string(rest) != "HELLO WORLD" {
161 t.Errorf("invalid rest: %d", len(rest))
162 }
163 }
164
165 func BenchmarkSkipValue(b *testing.B) {
166 initBig()
167 var scan scanner
168 for i := 0; i < b.N; i++ {
169 nextValue(jsonBig, &scan)
170 }
171 b.SetBytes(int64(len(jsonBig)))
172 }
173
174 func diff(t *testing.T, a, b []byte) {
175 for i := 0; ; i++ {
176 if i >= len(a) || i >= len(b) || a[i] != b[i] {
177 j := i - 10
178 if j < 0 {
179 j = 0
180 }
181 t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
182 return
183 }
184 }
185 }
186
187 func trim(b []byte) []byte {
188 if len(b) > 20 {
189 return b[0:20]
190 }
191 return b
192 }
193
194
195
196 var jsonBig []byte
197
198 const (
199 big = 10000
200 small = 100
201 )
202
203 func initBig() {
204 n := big
205 if testing.Short() {
206 n = small
207 }
208 if len(jsonBig) != n {
209 b, err := Marshal(genValue(n))
210 if err != nil {
211 panic(err)
212 }
213 jsonBig = b
214 }
215 }
216
217 func genValue(n int) interface{} {
218 if n > 1 {
219 switch rand.Intn(2) {
220 case 0:
221 return genArray(n)
222 case 1:
223 return genMap(n)
224 }
225 }
226 switch rand.Intn(3) {
227 case 0:
228 return rand.Intn(2) == 0
229 case 1:
230 return rand.NormFloat64()
231 case 2:
232 return genString(30)
233 }
234 panic("unreachable")
235 }
236
237 func genString(stddev float64) string {
238 n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
239 c := make([]int, n)
240 for i := range c {
241 f := math.Fabs(rand.NormFloat64()*64 + 32)
242 if f > 0x10ffff {
243 f = 0x10ffff
244 }
245 c[i] = int(f)
246 }
247 return string(c)
248 }
249
250 func genArray(n int) []interface{} {
251 f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
252 if f > n {
253 f = n
254 }
255 if n > 0 && f == 0 {
256 f = 1
257 }
258 x := make([]interface{}, f)
259 for i := range x {
260 x[i] = genValue(((i+1)*n)/f - (i*n)/f)
261 }
262 return x
263 }
264
265 func genMap(n int) map[string]interface{} {
266 f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
267 if f > n {
268 f = n
269 }
270 if n > 0 && f == 0 {
271 f = 1
272 }
273 x := make(map[string]interface{})
274 for i := 0; i < f; i++ {
275 x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
276 }
277 return x
278 }