mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: more generated equality function tests
Change-Id: I05cd103ea8d8bbee0ad907ff3e594de273d49e86 Reviewed-on: https://go-review.googlesource.com/c/go/+/725600 Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
c1acdcb345
commit
e432b4f3a1
1 changed files with 298 additions and 0 deletions
298
src/cmd/compile/internal/test/eq_test.go
Normal file
298
src/cmd/compile/internal/test/eq_test.go
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Tests of generated equality functions.
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:noinline
|
||||
func checkEq(t *testing.T, x, y any) {
|
||||
// Make sure we don't inline the equality test.
|
||||
if x != y {
|
||||
t.Errorf("%#v != %#v, wanted equal", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func checkNe(t *testing.T, x, y any) {
|
||||
// Make sure we don't inline the equality test.
|
||||
if x == y {
|
||||
t.Errorf("%#v == %#v, wanted not equal", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func checkPanic(t *testing.T, x, y any) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("%#v == %#v didn't panic", x, y)
|
||||
}
|
||||
}()
|
||||
_ = x == y
|
||||
}
|
||||
|
||||
type fooComparable struct {
|
||||
x int
|
||||
}
|
||||
|
||||
func (f fooComparable) foo() {
|
||||
}
|
||||
|
||||
type fooIncomparable struct {
|
||||
b func()
|
||||
}
|
||||
|
||||
func (i fooIncomparable) foo() {
|
||||
}
|
||||
|
||||
type eqResult int
|
||||
|
||||
const (
|
||||
eq eqResult = iota
|
||||
ne
|
||||
panic_
|
||||
)
|
||||
|
||||
func (x eqResult) String() string {
|
||||
return []string{eq: "eq", ne: "ne", panic_: "panic"}[x]
|
||||
}
|
||||
|
||||
// testEq returns eq if x==y, ne if x!=y, or panic_ if the comparison panics.
|
||||
func testEq(x, y any) (r eqResult) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
r = panic_
|
||||
}
|
||||
}()
|
||||
r = ne
|
||||
if x == y {
|
||||
r = eq
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// testCompare make two instances of struct type typ, then
|
||||
// assigns its len(vals) fields one value from each slice in vals.
|
||||
// Then it checks the results against a "manual" comparison field
|
||||
// by field.
|
||||
func testCompare(t *testing.T, typ reflect.Type, vals [][]any) {
|
||||
if len(vals) != typ.NumField() {
|
||||
t.Fatalf("bad test, have %d fields in the list, but %d fields in the type", len(vals), typ.NumField())
|
||||
}
|
||||
|
||||
x := reflect.New(typ).Elem()
|
||||
y := reflect.New(typ).Elem()
|
||||
ps := powerSet(vals) // all possible settings of fields of the test type.
|
||||
for _, xf := range ps { // Pick fields for x
|
||||
for _, yf := range ps { // Pick fields for y
|
||||
// Make x and y from their chosen fields.
|
||||
for i, f := range xf {
|
||||
x.Field(i).Set(reflect.ValueOf(f))
|
||||
}
|
||||
for i, f := range yf {
|
||||
y.Field(i).Set(reflect.ValueOf(f))
|
||||
}
|
||||
// Compute what we want the result to be.
|
||||
want := eq
|
||||
for i := range len(vals) {
|
||||
if c := testEq(xf[i], yf[i]); c != eq {
|
||||
want = c
|
||||
break
|
||||
}
|
||||
}
|
||||
// Compute actual result using generated equality function.
|
||||
got := testEq(x.Interface(), y.Interface())
|
||||
if got != want {
|
||||
t.Errorf("%#v == %#v, got %s want %s\n", x, y, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// powerset returns all possible sequences of choosing one
|
||||
// element from each entry in s.
|
||||
// For instance, if s = {{1,2}, {a,b}}, then
|
||||
// it returns {{1,a},{1,b},{2,a},{2,b}}.
|
||||
func powerSet(s [][]any) [][]any {
|
||||
if len(s) == 0 {
|
||||
return [][]any{{}}
|
||||
}
|
||||
p := powerSet(s[:len(s)-1]) // powerset from first len(s)-1 entries
|
||||
var r [][]any
|
||||
for _, head := range p {
|
||||
// add one more entry.
|
||||
for _, v := range s[len(s)-1] {
|
||||
x := make([]any, 0, len(s))
|
||||
x = append(x, head...)
|
||||
x = append(x, v)
|
||||
r = append(r, x)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func TestCompareKinds1(t *testing.T) {
|
||||
type S struct {
|
||||
X0 int8
|
||||
X1 int16
|
||||
X2 int32
|
||||
X3 int64
|
||||
X4 float32
|
||||
X5 float64
|
||||
}
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{int8(0), int8(1)},
|
||||
{int16(0), int16(1), int16(1 << 14)},
|
||||
{int32(0), int32(1), int32(1 << 30)},
|
||||
{int64(0), int64(1), int64(1 << 62)},
|
||||
{float32(0), float32(1.0)},
|
||||
{0.0, 1.0},
|
||||
})
|
||||
}
|
||||
func TestCompareKinds2(t *testing.T) {
|
||||
type S struct {
|
||||
X0 uint8
|
||||
X1 uint16
|
||||
X2 uint32
|
||||
X3 uint64
|
||||
X4 uintptr
|
||||
X5 bool
|
||||
}
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{uint8(0), uint8(1)},
|
||||
{uint16(0), uint16(1), uint16(1 << 15)},
|
||||
{uint32(0), uint32(1), uint32(1 << 31)},
|
||||
{uint64(0), uint64(1), uint64(1 << 63)},
|
||||
{uintptr(0), uintptr(1)},
|
||||
{false, true},
|
||||
})
|
||||
}
|
||||
func TestCompareKinds3(t *testing.T) {
|
||||
type S struct {
|
||||
X0 complex64
|
||||
X1 complex128
|
||||
X2 *byte
|
||||
X3 chan int
|
||||
X4 unsafe.Pointer
|
||||
}
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{complex64(1 + 1i), complex64(1 + 2i), complex64(2 + 1i)},
|
||||
{complex128(1 + 1i), complex128(1 + 2i), complex128(2 + 1i)},
|
||||
{new(byte), new(byte)},
|
||||
{make(chan int), make(chan int)},
|
||||
{unsafe.Pointer(new(byte)), unsafe.Pointer(new(byte))},
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompareOrdering(t *testing.T) {
|
||||
type S struct {
|
||||
A string
|
||||
E any
|
||||
B string
|
||||
}
|
||||
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{"a", "b", "cc"},
|
||||
{3, []byte{0}, []byte{1}},
|
||||
{"a", "b", "cc"},
|
||||
})
|
||||
}
|
||||
func TestCompareInterfaces(t *testing.T) {
|
||||
type S struct {
|
||||
A any
|
||||
B fooer
|
||||
}
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{3, []byte{0}},
|
||||
{fooComparable{x: 3}, fooIncomparable{b: nil}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompareSkip(t *testing.T) {
|
||||
type S struct {
|
||||
A int8
|
||||
B int16
|
||||
}
|
||||
type S2 struct {
|
||||
A int8
|
||||
padding int8
|
||||
B int16
|
||||
}
|
||||
x := S{A: 1, B: 3}
|
||||
y := S{A: 1, B: 3}
|
||||
(*S2)(unsafe.Pointer(&x)).padding = 88
|
||||
(*S2)(unsafe.Pointer(&y)).padding = 99
|
||||
|
||||
want := eq
|
||||
if got := testEq(x, y); got != want {
|
||||
t.Errorf("%#v == %#v, got %s want %s", x, y, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareMemequal(t *testing.T) {
|
||||
type S struct {
|
||||
s1 string
|
||||
d [100]byte
|
||||
s2 string
|
||||
}
|
||||
var x, y S
|
||||
|
||||
checkEq(t, x, y)
|
||||
y.d[0] = 1
|
||||
checkNe(t, x, y)
|
||||
y.d[0] = 0
|
||||
y.d[99] = 1
|
||||
checkNe(t, x, y)
|
||||
}
|
||||
|
||||
func TestComparePanic(t *testing.T) {
|
||||
type S struct {
|
||||
X0 string
|
||||
X1 any
|
||||
X2 string
|
||||
X3 fooer
|
||||
X4 string
|
||||
}
|
||||
testCompare(t, reflect.TypeOf(S{}), [][]any{
|
||||
{"a", "b", "cc"}, // length equal, as well as length unequal
|
||||
{3, []byte{1}}, // comparable and incomparable
|
||||
{"a", "b", "cc"}, // length equal, as well as length unequal
|
||||
{fooComparable{x: 3}, fooIncomparable{b: nil}}, // comparable and incomparable
|
||||
{"a", "b", "cc"}, // length equal, as well as length unequal
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompareArray(t *testing.T) {
|
||||
type S struct {
|
||||
X0 string
|
||||
X1 [100]string
|
||||
X2 string
|
||||
}
|
||||
x := S{X0: "a", X2: "b"}
|
||||
y := x
|
||||
checkEq(t, x, y)
|
||||
x.X0 = "c"
|
||||
checkNe(t, x, y)
|
||||
x.X0 = "a"
|
||||
x.X2 = "c"
|
||||
checkNe(t, x, y)
|
||||
x.X2 = "b"
|
||||
checkEq(t, x, y)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
x.X1[i] = "d"
|
||||
checkNe(t, x, y)
|
||||
y.X1[i] = "e"
|
||||
checkNe(t, x, y)
|
||||
x.X1[i] = ""
|
||||
y.X1[i] = ""
|
||||
checkEq(t, x, y)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue