1package pretty
2
3import (
4	"fmt"
5	"io"
6	"strings"
7	"testing"
8	"unsafe"
9)
10
11type test struct {
12	v interface{}
13	s string
14}
15
16type passtest struct {
17	v    interface{}
18	f, s string
19}
20
21type LongStructTypeName struct {
22	longFieldName      interface{}
23	otherLongFieldName interface{}
24}
25
26type SA struct {
27	t *T
28	v T
29}
30
31type T struct {
32	x, y int
33}
34
35type F int
36
37func (f F) Format(s fmt.State, c rune) {
38	fmt.Fprintf(s, "F(%d)", int(f))
39}
40
41type Stringer struct { i int }
42
43func (s *Stringer) String() string { return "foo" }
44
45var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
46
47var passthrough = []passtest{
48	{1, "%d", "1"},
49	{"a", "%s", "a"},
50	{&Stringer{}, "%s", "foo"},
51}
52
53func TestPassthrough(t *testing.T) {
54	for _, tt := range passthrough {
55		s := fmt.Sprintf(tt.f, Formatter(tt.v))
56		if tt.s != s {
57			t.Errorf("expected %q", tt.s)
58			t.Errorf("got      %q", s)
59			t.Errorf("expraw\n%s", tt.s)
60			t.Errorf("gotraw\n%s", s)
61		}
62	}
63}
64
65var gosyntax = []test{
66	{nil, `nil`},
67	{"", `""`},
68	{"a", `"a"`},
69	{1, "int(1)"},
70	{1.0, "float64(1)"},
71	{[]int(nil), "[]int(nil)"},
72	{[0]int{}, "[0]int{}"},
73	{complex(1, 0), "(1+0i)"},
74	//{make(chan int), "(chan int)(0x1234)"},
75	{unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))},
76	{func(int) {}, "func(int) {...}"},
77	{map[int]int{1: 1}, "map[int]int{1:1}"},
78	{int32(1), "int32(1)"},
79	{io.EOF, `&errors.errorString{s:"EOF"}`},
80	{[]string{"a"}, `[]string{"a"}`},
81	{
82		[]string{long},
83		`[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`,
84	},
85	{F(5), "pretty.F(5)"},
86	{
87		SA{&T{1, 2}, T{3, 4}},
88		`pretty.SA{
89    t:  &pretty.T{x:1, y:2},
90    v:  pretty.T{x:3, y:4},
91}`,
92	},
93	{
94		map[int][]byte{1: {}},
95		`map[int][]uint8{
96    1:  {},
97}`,
98	},
99	{
100		map[int]T{1: {}},
101		`map[int]pretty.T{
102    1:  {},
103}`,
104	},
105	{
106		long,
107		`"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`,
108	},
109	{
110		LongStructTypeName{
111			longFieldName:      LongStructTypeName{},
112			otherLongFieldName: long,
113		},
114		`pretty.LongStructTypeName{
115    longFieldName:      pretty.LongStructTypeName{},
116    otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
117}`,
118	},
119	{
120		&LongStructTypeName{
121			longFieldName:      &LongStructTypeName{},
122			otherLongFieldName: (*LongStructTypeName)(nil),
123		},
124		`&pretty.LongStructTypeName{
125    longFieldName:      &pretty.LongStructTypeName{},
126    otherLongFieldName: (*pretty.LongStructTypeName)(nil),
127}`,
128	},
129	{
130		[]LongStructTypeName{
131			{nil, nil},
132			{3, 3},
133			{long, nil},
134		},
135		`[]pretty.LongStructTypeName{
136    {},
137    {
138        longFieldName:      int(3),
139        otherLongFieldName: int(3),
140    },
141    {
142        longFieldName:      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
143        otherLongFieldName: nil,
144    },
145}`,
146	},
147	{
148		[]interface{}{
149			LongStructTypeName{nil, nil},
150			[]byte{1, 2, 3},
151			T{3, 4},
152			LongStructTypeName{long, nil},
153		},
154		`[]interface {}{
155    pretty.LongStructTypeName{},
156    []uint8{0x1, 0x2, 0x3},
157    pretty.T{x:3, y:4},
158    pretty.LongStructTypeName{
159        longFieldName:      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
160        otherLongFieldName: nil,
161    },
162}`,
163	},
164}
165
166func TestGoSyntax(t *testing.T) {
167	for _, tt := range gosyntax {
168		s := fmt.Sprintf("%# v", Formatter(tt.v))
169		if tt.s != s {
170			t.Errorf("expected %q", tt.s)
171			t.Errorf("got      %q", s)
172			t.Errorf("expraw\n%s", tt.s)
173			t.Errorf("gotraw\n%s", s)
174		}
175	}
176}
177
178type I struct {
179	i int
180	R interface{}
181}
182
183func (i *I) I() *I { return i.R.(*I) }
184
185func TestCycle(t *testing.T) {
186	type A struct{ *A }
187	v := &A{}
188	v.A = v
189
190	// panics from stack overflow without cycle detection
191	t.Logf("Example cycle:\n%# v", Formatter(v))
192
193	p := &A{}
194	s := fmt.Sprintf("%# v", Formatter([]*A{p, p}))
195	if strings.Contains(s, "CYCLIC") {
196		t.Errorf("Repeated address detected as cyclic reference:\n%s", s)
197	}
198
199	type R struct {
200		i int
201		*R
202	}
203	r := &R{
204		i: 1,
205		R: &R{
206			i: 2,
207			R: &R{
208				i: 3,
209			},
210		},
211	}
212	r.R.R.R = r
213	t.Logf("Example longer cycle:\n%# v", Formatter(r))
214
215	r = &R{
216		i: 1,
217		R: &R{
218			i: 2,
219			R: &R{
220				i: 3,
221				R: &R{
222					i: 4,
223					R: &R{
224						i: 5,
225						R: &R{
226							i: 6,
227							R: &R{
228								i: 7,
229								R: &R{
230									i: 8,
231									R: &R{
232										i: 9,
233										R: &R{
234											i: 10,
235											R: &R{
236												i: 11,
237											},
238										},
239									},
240								},
241							},
242						},
243					},
244				},
245			},
246		},
247	}
248	// here be pirates
249	r.R.R.R.R.R.R.R.R.R.R.R = r
250	t.Logf("Example very long cycle:\n%# v", Formatter(r))
251
252	i := &I{
253		i: 1,
254		R: &I{
255			i: 2,
256			R: &I{
257				i: 3,
258				R: &I{
259					i: 4,
260					R: &I{
261						i: 5,
262						R: &I{
263							i: 6,
264							R: &I{
265								i: 7,
266								R: &I{
267									i: 8,
268									R: &I{
269										i: 9,
270										R: &I{
271											i: 10,
272											R: &I{
273												i: 11,
274											},
275										},
276									},
277								},
278							},
279						},
280					},
281				},
282			},
283		},
284	}
285	iv := i.I().I().I().I().I().I().I().I().I().I()
286	*iv = *i
287	t.Logf("Example long interface cycle:\n%# v", Formatter(i))
288}
289