1package pretty
2
3import (
4	"bytes"
5	"fmt"
6	"log"
7	"reflect"
8	"testing"
9	"unsafe"
10)
11
12var (
13	_ Logfer   = (*testing.T)(nil)
14	_ Logfer   = (*testing.B)(nil)
15	_ Printfer = (*log.Logger)(nil)
16)
17
18type difftest struct {
19	a   interface{}
20	b   interface{}
21	exp []string
22}
23
24type S struct {
25	A int
26	S *S
27	I interface{}
28	C []int
29}
30
31type (
32	N struct{ N int }
33	E interface{}
34)
35
36var (
37	c0 = make(chan int)
38	c1 = make(chan int)
39	f0 = func() {}
40	f1 = func() {}
41	i0 = 0
42	i1 = 1
43)
44
45var diffs = []difftest{
46	{a: nil, b: nil},
47	{a: S{A: 1}, b: S{A: 1}},
48
49	{0, "", []string{`int != string`}},
50	{0, 1, []string{`0 != 1`}},
51	{S{}, new(S), []string{`pretty.S != *pretty.S`}},
52	{"a", "b", []string{`"a" != "b"`}},
53	{S{}, S{A: 1}, []string{`A: 0 != 1`}},
54	{new(S), &S{A: 1}, []string{`A: 0 != 1`}},
55	{S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}},
56	{S{}, S{I: 0}, []string{`I: nil != int(0)`}},
57	{S{I: 1}, S{I: "x"}, []string{`I: int != string`}},
58	{S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
59	{S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
60	{S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}},
61	{S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &pretty.S{}`}},
62
63	// unexported fields of every reflect.Kind (both equal and unequal)
64	{struct{ x bool }{false}, struct{ x bool }{false}, nil},
65	{struct{ x bool }{false}, struct{ x bool }{true}, []string{`x: false != true`}},
66	{struct{ x int }{0}, struct{ x int }{0}, nil},
67	{struct{ x int }{0}, struct{ x int }{1}, []string{`x: 0 != 1`}},
68	{struct{ x int8 }{0}, struct{ x int8 }{0}, nil},
69	{struct{ x int8 }{0}, struct{ x int8 }{1}, []string{`x: 0 != 1`}},
70	{struct{ x int16 }{0}, struct{ x int16 }{0}, nil},
71	{struct{ x int16 }{0}, struct{ x int16 }{1}, []string{`x: 0 != 1`}},
72	{struct{ x int32 }{0}, struct{ x int32 }{0}, nil},
73	{struct{ x int32 }{0}, struct{ x int32 }{1}, []string{`x: 0 != 1`}},
74	{struct{ x int64 }{0}, struct{ x int64 }{0}, nil},
75	{struct{ x int64 }{0}, struct{ x int64 }{1}, []string{`x: 0 != 1`}},
76	{struct{ x uint }{0}, struct{ x uint }{0}, nil},
77	{struct{ x uint }{0}, struct{ x uint }{1}, []string{`x: 0 != 1`}},
78	{struct{ x uint8 }{0}, struct{ x uint8 }{0}, nil},
79	{struct{ x uint8 }{0}, struct{ x uint8 }{1}, []string{`x: 0 != 1`}},
80	{struct{ x uint16 }{0}, struct{ x uint16 }{0}, nil},
81	{struct{ x uint16 }{0}, struct{ x uint16 }{1}, []string{`x: 0 != 1`}},
82	{struct{ x uint32 }{0}, struct{ x uint32 }{0}, nil},
83	{struct{ x uint32 }{0}, struct{ x uint32 }{1}, []string{`x: 0 != 1`}},
84	{struct{ x uint64 }{0}, struct{ x uint64 }{0}, nil},
85	{struct{ x uint64 }{0}, struct{ x uint64 }{1}, []string{`x: 0 != 1`}},
86	{struct{ x uintptr }{0}, struct{ x uintptr }{0}, nil},
87	{struct{ x uintptr }{0}, struct{ x uintptr }{1}, []string{`x: 0 != 1`}},
88	{struct{ x float32 }{0}, struct{ x float32 }{0}, nil},
89	{struct{ x float32 }{0}, struct{ x float32 }{1}, []string{`x: 0 != 1`}},
90	{struct{ x float64 }{0}, struct{ x float64 }{0}, nil},
91	{struct{ x float64 }{0}, struct{ x float64 }{1}, []string{`x: 0 != 1`}},
92	{struct{ x complex64 }{0}, struct{ x complex64 }{0}, nil},
93	{struct{ x complex64 }{0}, struct{ x complex64 }{1}, []string{`x: (0+0i) != (1+0i)`}},
94	{struct{ x complex128 }{0}, struct{ x complex128 }{0}, nil},
95	{struct{ x complex128 }{0}, struct{ x complex128 }{1}, []string{`x: (0+0i) != (1+0i)`}},
96	{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{0}}, nil},
97	{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{1}}, []string{`x[0]: 0 != 1`}},
98	{struct{ x chan int }{c0}, struct{ x chan int }{c0}, nil},
99	{struct{ x chan int }{c0}, struct{ x chan int }{c1}, []string{fmt.Sprintf("x: %p != %p", c0, c1)}},
100	{struct{ x func() }{f0}, struct{ x func() }{f0}, nil},
101	{struct{ x func() }{f0}, struct{ x func() }{f1}, []string{fmt.Sprintf("x: %p != %p", f0, f1)}},
102	{struct{ x interface{} }{0}, struct{ x interface{} }{0}, nil},
103	{struct{ x interface{} }{0}, struct{ x interface{} }{1}, []string{`x: 0 != 1`}},
104	{struct{ x interface{} }{0}, struct{ x interface{} }{""}, []string{`x: int != string`}},
105	{struct{ x interface{} }{0}, struct{ x interface{} }{nil}, []string{`x: int(0) != nil`}},
106	{struct{ x interface{} }{nil}, struct{ x interface{} }{0}, []string{`x: nil != int(0)`}},
107	{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 0}}, nil},
108	{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 1}}, []string{`x[0]: 0 != 1`}},
109	{struct{ x *int }{new(int)}, struct{ x *int }{new(int)}, nil},
110	{struct{ x *int }{&i0}, struct{ x *int }{&i1}, []string{`x: 0 != 1`}},
111	{struct{ x *int }{nil}, struct{ x *int }{&i0}, []string{`x: nil != &int(0)`}},
112	{struct{ x *int }{&i0}, struct{ x *int }{nil}, []string{`x: &int(0) != nil`}},
113	{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{0}}, nil},
114	{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{1}}, []string{`x[0]: 0 != 1`}},
115	{struct{ x string }{"a"}, struct{ x string }{"a"}, nil},
116	{struct{ x string }{"a"}, struct{ x string }{"b"}, []string{`x: "a" != "b"`}},
117	{struct{ x N }{N{0}}, struct{ x N }{N{0}}, nil},
118	{struct{ x N }{N{0}}, struct{ x N }{N{1}}, []string{`x.N: 0 != 1`}},
119	{
120		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
121		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
122		nil,
123	},
124	{
125		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
126		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(1))},
127		[]string{`x: 0x0 != 0x1`},
128	},
129}
130
131func TestDiff(t *testing.T) {
132	for _, tt := range diffs {
133		got := Diff(tt.a, tt.b)
134		eq := len(got) == len(tt.exp)
135		if eq {
136			for i := range got {
137				eq = eq && got[i] == tt.exp[i]
138			}
139		}
140		if !eq {
141			t.Errorf("diffing % #v", tt.a)
142			t.Errorf("with    % #v", tt.b)
143			diffdiff(t, got, tt.exp)
144			continue
145		}
146	}
147}
148
149func TestKeyEqual(t *testing.T) {
150	var emptyInterfaceZero interface{} = 0
151
152	cases := []interface{}{
153		new(bool),
154		new(int),
155		new(int8),
156		new(int16),
157		new(int32),
158		new(int64),
159		new(uint),
160		new(uint8),
161		new(uint16),
162		new(uint32),
163		new(uint64),
164		new(uintptr),
165		new(float32),
166		new(float64),
167		new(complex64),
168		new(complex128),
169		new([1]int),
170		new(chan int),
171		new(unsafe.Pointer),
172		new(interface{}),
173		&emptyInterfaceZero,
174		new(*int),
175		new(string),
176		new(struct{ int }),
177	}
178
179	for _, test := range cases {
180		rv := reflect.ValueOf(test).Elem()
181		if !keyEqual(rv, rv) {
182			t.Errorf("keyEqual(%s, %s) = false want true", rv.Type(), rv.Type())
183		}
184	}
185}
186
187func TestFdiff(t *testing.T) {
188	var buf bytes.Buffer
189	Fdiff(&buf, 0, 1)
190	want := "0 != 1\n"
191	if got := buf.String(); got != want {
192		t.Errorf("Fdiff(0, 1) = %q want %q", got, want)
193	}
194}
195
196func diffdiff(t *testing.T, got, exp []string) {
197	minus(t, "unexpected:", got, exp)
198	minus(t, "missing:", exp, got)
199}
200
201func minus(t *testing.T, s string, a, b []string) {
202	var i, j int
203	for i = 0; i < len(a); i++ {
204		for j = 0; j < len(b); j++ {
205			if a[i] == b[j] {
206				break
207			}
208		}
209		if j == len(b) {
210			t.Error(s, a[i])
211		}
212	}
213}
214