1
2
3
4
5
6
7 package test
8
9 import (
10 "reflect"
11 "testing"
12 "unsafe"
13 )
14
15
16 func checkEq(t *testing.T, x, y any) {
17
18 if x != y {
19 t.Errorf("%#v != %#v, wanted equal", x, y)
20 }
21 }
22
23
24 func checkNe(t *testing.T, x, y any) {
25
26 if x == y {
27 t.Errorf("%#v == %#v, wanted not equal", x, y)
28 }
29 }
30
31
32 func checkPanic(t *testing.T, x, y any) {
33 defer func() {
34 if recover() == nil {
35 t.Errorf("%#v == %#v didn't panic", x, y)
36 }
37 }()
38 _ = x == y
39 }
40
41 type fooComparable struct {
42 x int
43 }
44
45 func (f fooComparable) foo() {
46 }
47
48 type fooIncomparable struct {
49 b func()
50 }
51
52 func (i fooIncomparable) foo() {
53 }
54
55 type eqResult int
56
57 const (
58 eq eqResult = iota
59 ne
60 panic_
61 )
62
63 func (x eqResult) String() string {
64 return []string{eq: "eq", ne: "ne", panic_: "panic"}[x]
65 }
66
67
68 func testEq(x, y any) (r eqResult) {
69 defer func() {
70 if e := recover(); e != nil {
71 r = panic_
72 }
73 }()
74 r = ne
75 if x == y {
76 r = eq
77 }
78 return
79 }
80
81
82
83
84
85 func testCompare(t *testing.T, typ reflect.Type, vals [][]any) {
86 if len(vals) != typ.NumField() {
87 t.Fatalf("bad test, have %d fields in the list, but %d fields in the type", len(vals), typ.NumField())
88 }
89
90 x := reflect.New(typ).Elem()
91 y := reflect.New(typ).Elem()
92 ps := powerSet(vals)
93 for _, xf := range ps {
94 for _, yf := range ps {
95
96 for i, f := range xf {
97 x.Field(i).Set(reflect.ValueOf(f))
98 }
99 for i, f := range yf {
100 y.Field(i).Set(reflect.ValueOf(f))
101 }
102
103 want := eq
104 for i := range len(vals) {
105 if c := testEq(xf[i], yf[i]); c != eq {
106 want = c
107 break
108 }
109 }
110
111 got := testEq(x.Interface(), y.Interface())
112 if got != want {
113 t.Errorf("%#v == %#v, got %s want %s\n", x, y, got, want)
114 }
115 }
116 }
117 }
118
119
120
121
122
123 func powerSet(s [][]any) [][]any {
124 if len(s) == 0 {
125 return [][]any{{}}
126 }
127 p := powerSet(s[:len(s)-1])
128 var r [][]any
129 for _, head := range p {
130
131 for _, v := range s[len(s)-1] {
132 x := make([]any, 0, len(s))
133 x = append(x, head...)
134 x = append(x, v)
135 r = append(r, x)
136 }
137 }
138 return r
139 }
140
141 func TestCompareKinds1(t *testing.T) {
142 type S struct {
143 X0 int8
144 X1 int16
145 X2 int32
146 X3 int64
147 X4 float32
148 X5 float64
149 }
150 testCompare(t, reflect.TypeOf(S{}), [][]any{
151 {int8(0), int8(1)},
152 {int16(0), int16(1), int16(1 << 14)},
153 {int32(0), int32(1), int32(1 << 30)},
154 {int64(0), int64(1), int64(1 << 62)},
155 {float32(0), float32(1.0)},
156 {0.0, 1.0},
157 })
158 }
159 func TestCompareKinds2(t *testing.T) {
160 type S struct {
161 X0 uint8
162 X1 uint16
163 X2 uint32
164 X3 uint64
165 X4 uintptr
166 X5 bool
167 }
168 testCompare(t, reflect.TypeOf(S{}), [][]any{
169 {uint8(0), uint8(1)},
170 {uint16(0), uint16(1), uint16(1 << 15)},
171 {uint32(0), uint32(1), uint32(1 << 31)},
172 {uint64(0), uint64(1), uint64(1 << 63)},
173 {uintptr(0), uintptr(1)},
174 {false, true},
175 })
176 }
177 func TestCompareKinds3(t *testing.T) {
178 type S struct {
179 X0 complex64
180 X1 complex128
181 X2 *byte
182 X3 chan int
183 X4 unsafe.Pointer
184 }
185 testCompare(t, reflect.TypeOf(S{}), [][]any{
186 {complex64(1 + 1i), complex64(1 + 2i), complex64(2 + 1i)},
187 {complex128(1 + 1i), complex128(1 + 2i), complex128(2 + 1i)},
188 {new(byte), new(byte)},
189 {make(chan int), make(chan int)},
190 {unsafe.Pointer(new(byte)), unsafe.Pointer(new(byte))},
191 })
192 }
193
194 func TestCompareOrdering(t *testing.T) {
195 type S struct {
196 A string
197 E any
198 B string
199 }
200
201 testCompare(t, reflect.TypeOf(S{}), [][]any{
202 {"a", "b", "cc"},
203 {3, []byte{0}, []byte{1}},
204 {"a", "b", "cc"},
205 })
206 }
207 func TestCompareInterfaces(t *testing.T) {
208 type S struct {
209 A any
210 B fooer
211 }
212 testCompare(t, reflect.TypeOf(S{}), [][]any{
213 {3, []byte{0}},
214 {fooComparable{x: 3}, fooIncomparable{b: nil}},
215 })
216 }
217
218 func TestCompareSkip(t *testing.T) {
219 type S struct {
220 A int8
221 B int16
222 }
223 type S2 struct {
224 A int8
225 padding int8
226 B int16
227 }
228 x := S{A: 1, B: 3}
229 y := S{A: 1, B: 3}
230 (*S2)(unsafe.Pointer(&x)).padding = 88
231 (*S2)(unsafe.Pointer(&y)).padding = 99
232
233 want := eq
234 if got := testEq(x, y); got != want {
235 t.Errorf("%#v == %#v, got %s want %s", x, y, got, want)
236 }
237 }
238
239 func TestCompareMemequal(t *testing.T) {
240 type S struct {
241 s1 string
242 d [100]byte
243 s2 string
244 }
245 var x, y S
246
247 checkEq(t, x, y)
248 y.d[0] = 1
249 checkNe(t, x, y)
250 y.d[0] = 0
251 y.d[99] = 1
252 checkNe(t, x, y)
253 }
254
255 func TestComparePanic(t *testing.T) {
256 type S struct {
257 X0 string
258 X1 any
259 X2 string
260 X3 fooer
261 X4 string
262 }
263 testCompare(t, reflect.TypeOf(S{}), [][]any{
264 {"a", "b", "cc"},
265 {3, []byte{1}},
266 {"a", "b", "cc"},
267 {fooComparable{x: 3}, fooIncomparable{b: nil}},
268 {"a", "b", "cc"},
269 })
270 }
271
272 func TestCompareArray(t *testing.T) {
273 type S struct {
274 X0 string
275 X1 [100]string
276 X2 string
277 }
278 x := S{X0: "a", X2: "b"}
279 y := x
280 checkEq(t, x, y)
281 x.X0 = "c"
282 checkNe(t, x, y)
283 x.X0 = "a"
284 x.X2 = "c"
285 checkNe(t, x, y)
286 x.X2 = "b"
287 checkEq(t, x, y)
288
289 for i := 0; i < 100; i++ {
290 x.X1[i] = "d"
291 checkNe(t, x, y)
292 y.X1[i] = "e"
293 checkNe(t, x, y)
294 x.X1[i] = ""
295 y.X1[i] = ""
296 checkEq(t, x, y)
297 }
298 }
299
View as plain text