1// Copyright 2013 Google Inc.  All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package pretty
16
17import (
18	"bytes"
19	"strings"
20	"testing"
21)
22
23func TestFormat(t *testing.T) {
24	tests := []struct {
25		desc string
26		node node
27
28		// All strings have a leading newline trimmed before comparison:
29		normal   string
30		diffable string
31	}{
32		{
33			desc:     "string",
34			node:     stringVal("zaphod"),
35			normal:   `"zaphod"`,
36			diffable: `"zaphod"`,
37		},
38		{
39			desc:     "raw",
40			node:     rawVal("42"),
41			normal:   `42`,
42			diffable: `42`,
43		},
44		{
45			desc: "keyvals",
46			node: keyvals{
47				{"name", stringVal("zaphod")},
48				{"age", rawVal("42")},
49			},
50			normal: `
51{name: "zaphod",
52 age:  42}`,
53			diffable: `
54{
55 name: "zaphod",
56 age: 42,
57}`,
58		},
59		{
60			desc: "empty list",
61			node: list{},
62			normal: `
63[]`,
64			diffable: `
65[
66]`,
67		},
68		{
69			desc: "empty nested list",
70			node: list{list{}},
71			normal: `
72[[]]`,
73			diffable: `
74[
75 [
76 ],
77]`,
78		},
79		{
80			desc: "list",
81			node: list{
82				stringVal("zaphod"),
83				rawVal("42"),
84			},
85			normal: `
86["zaphod",
87 42]`,
88			diffable: `
89[
90 "zaphod",
91 42,
92]`,
93		},
94		{
95			desc: "empty keyvals",
96			node: keyvals{},
97			normal: `
98{}`,
99			diffable: `
100{
101}`,
102		},
103		{
104			desc: "empty nested keyvals",
105			node: keyvals{{"k", keyvals{}}},
106			normal: `
107{k: {}}`,
108			diffable: `
109{
110 k: {
111 },
112}`,
113		},
114		{
115			desc: "nested",
116			node: list{
117				stringVal("first"),
118				list{rawVal("1"), rawVal("2"), rawVal("3")},
119				keyvals{
120					{"trillian", keyvals{
121						{"race", stringVal("human")},
122						{"age", rawVal("36")},
123					}},
124					{"zaphod", keyvals{
125						{"occupation", stringVal("president of the galaxy")},
126						{"features", stringVal("two heads")},
127					}},
128				},
129				keyvals{},
130			},
131			normal: `
132["first",
133 [1,
134  2,
135  3],
136 {trillian: {race: "human",
137             age:  36},
138  zaphod:   {occupation: "president of the galaxy",
139             features:   "two heads"}},
140 {}]`,
141			diffable: `
142[
143 "first",
144 [
145  1,
146  2,
147  3,
148 ],
149 {
150  trillian: {
151   race: "human",
152   age: 36,
153  },
154  zaphod: {
155   occupation: "president of the galaxy",
156   features: "two heads",
157  },
158 },
159 {
160 },
161]`,
162		},
163		{
164			desc: "recursive",
165			node: target{1, keyvals{
166				{"Value", rawVal("1")},
167				{"Next", keyvals{
168					{"Value", rawVal("2")},
169					{"Next", keyvals{
170						{"Value", rawVal("3")},
171						{"Next", ref{1}},
172					}},
173				}},
174			}},
175			normal: `
176<#1> {Value: 1,
177      Next:  {Value: 2,
178              Next:  {Value: 3,
179                      Next:  <see #1>}}}`,
180			diffable: `
181<#1> {
182 Value: 1,
183 Next: {
184  Value: 2,
185  Next: {
186   Value: 3,
187   Next: <see #1>,
188  },
189 },
190}`,
191		},
192		{
193			desc: "print in order",
194			node: list{
195				target{2, keyvals{
196					{"Next", ref{1}},
197				}},
198				target{1, keyvals{
199					{"Next", ref{2}},
200				}},
201			},
202			normal: `
203[<#1> {Next: <see #2>},
204 <#2> {Next: <see #1>}]`,
205			diffable: `
206[
207 <#1> {
208  Next: <see #2>,
209 },
210 <#2> {
211  Next: <see #1>,
212 },
213]`,
214		},
215	}
216
217	normal := &Config{}
218	diffable := &Config{Diffable: true}
219	for _, test := range tests {
220		// For readability, we have a newline that won't be there in the output
221		test.normal = strings.TrimPrefix(test.normal, "\n")
222		test.diffable = strings.TrimPrefix(test.diffable, "\n")
223
224		buf := new(bytes.Buffer)
225		newFormatter(normal, buf).write(test.node)
226		if got, want := buf.String(), test.normal; got != want {
227			t.Errorf("%s: normal rendendered incorrectly\ngot:\n%s\nwant:\n%s", test.desc, got, want)
228		}
229		buf.Reset()
230
231		newFormatter(diffable, buf).write(test.node)
232		if got, want := buf.String(), test.diffable; got != want {
233			t.Errorf("%s: diffable rendendered incorrectly\ngot:\n%s\nwant:\n%s", test.desc, got, want)
234		}
235	}
236}
237
238func TestCompactString(t *testing.T) {
239	tests := []struct {
240		node
241		compact string
242	}{
243		{
244			stringVal("abc"),
245			"abc",
246		},
247		{
248			rawVal("2"),
249			"2",
250		},
251		{
252			list{
253				rawVal("2"),
254				rawVal("3"),
255			},
256			"[2,3]",
257		},
258		{
259			keyvals{
260				{"name", stringVal("zaphod")},
261				{"age", rawVal("42")},
262			},
263			`{name:"zaphod",age:42}`,
264		},
265		{
266			list{
267				list{
268					rawVal("0"),
269					rawVal("1"),
270					rawVal("2"),
271					rawVal("3"),
272				},
273				list{
274					rawVal("1"),
275					rawVal("2"),
276					rawVal("3"),
277					rawVal("0"),
278				},
279				list{
280					rawVal("2"),
281					rawVal("3"),
282					rawVal("0"),
283					rawVal("1"),
284				},
285			},
286			`[[0,1,2,3],[1,2,3,0],[2,3,0,1]]`,
287		},
288	}
289
290	for _, test := range tests {
291		if got, want := new(formatter).compactString(test.node), test.compact; got != want {
292			t.Errorf("%#v: compact = %q, want %q", test.node, got, want)
293		}
294	}
295}
296
297func TestShortList(t *testing.T) {
298	cfg := &Config{
299		ShortList: 16,
300	}
301
302	tests := []struct {
303		node
304		want string
305	}{
306		{
307			list{
308				list{
309					rawVal("0"),
310					rawVal("1"),
311					rawVal("2"),
312					rawVal("3"),
313				},
314				list{
315					rawVal("1"),
316					rawVal("2"),
317					rawVal("3"),
318					rawVal("0"),
319				},
320				list{
321					rawVal("2"),
322					rawVal("3"),
323					rawVal("0"),
324					rawVal("1"),
325				},
326			},
327			`[[0,1,2,3],
328 [1,2,3,0],
329 [2,3,0,1]]`,
330		},
331	}
332
333	for _, test := range tests {
334		buf := new(bytes.Buffer)
335		newFormatter(cfg, buf).write(test.node)
336		if got, want := buf.String(), test.want; got != want {
337			t.Errorf("%#v:\ngot:\n%s\nwant:\n%s", test.node, got, want)
338		}
339	}
340}
341
342var benchNode = keyvals{
343	{"list", list{
344		rawVal("0"),
345		rawVal("1"),
346		rawVal("2"),
347		rawVal("3"),
348	}},
349	{"keyvals", keyvals{
350		{"a", stringVal("b")},
351		{"c", stringVal("e")},
352		{"d", stringVal("f")},
353	}},
354}
355
356func benchOpts(b *testing.B, cfg *Config) {
357	buf := new(bytes.Buffer)
358	newFormatter(cfg, buf).write(benchNode)
359	b.SetBytes(int64(buf.Len()))
360	b.ResetTimer()
361
362	for i := 0; i < b.N; i++ {
363		buf.Reset()
364		newFormatter(cfg, buf).write(benchNode)
365	}
366}
367
368func BenchmarkWriteDefault(b *testing.B)   { benchOpts(b, DefaultConfig) }
369func BenchmarkWriteShortList(b *testing.B) { benchOpts(b, &Config{ShortList: 16}) }
370func BenchmarkWriteCompact(b *testing.B)   { benchOpts(b, &Config{Compact: true}) }
371func BenchmarkWriteDiffable(b *testing.B)  { benchOpts(b, &Config{Diffable: true}) }
372