aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect/all_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/reflect/all_test.go')
-rw-r--r--libgo/go/reflect/all_test.go238
1 files changed, 238 insertions, 0 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 33ee9ed83cc..595d6908f7d 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -10,6 +10,7 @@ import (
"flag"
"fmt"
"io"
+ "math"
"math/rand"
"os"
. "reflect"
@@ -647,6 +648,8 @@ var (
fn3 = func() { fn1() } // Not nil.
)
+type self struct{}
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{nil, nil, true},
@@ -681,6 +684,13 @@ var deepEqualTests = []DeepEqualTest{
{fn1, fn3, false},
{fn3, fn3, false},
{[][]int{{1}}, [][]int{{2}}, false},
+ {math.NaN(), math.NaN(), false},
+ {&[1]float64{math.NaN()}, &[1]float64{math.NaN()}, false},
+ {&[1]float64{math.NaN()}, self{}, true},
+ {[]float64{math.NaN()}, []float64{math.NaN()}, false},
+ {[]float64{math.NaN()}, self{}, true},
+ {map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false},
+ {map[float64]float64{math.NaN(): 1}, self{}, true},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
@@ -702,6 +712,9 @@ var deepEqualTests = []DeepEqualTest{
func TestDeepEqual(t *testing.T) {
for _, test := range deepEqualTests {
+ if test.b == (self{}) {
+ test.b = test.a
+ }
if r := DeepEqual(test.a, test.b); r != test.eq {
t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
}
@@ -2783,14 +2796,27 @@ func TestSetBytes(t *testing.T) {
type Private struct {
x int
y **int
+ Z int
}
func (p *Private) m() {
}
+type private struct {
+ Z int
+ z int
+ S string
+ A [1]Private
+ T []Private
+}
+
+func (p *private) P() {
+}
+
type Public struct {
X int
Y **int
+ private
}
func (p *Public) M() {
@@ -2798,17 +2824,30 @@ func (p *Public) M() {
func TestUnexported(t *testing.T) {
var pub Public
+ pub.S = "S"
+ pub.T = pub.A[:]
v := ValueOf(&pub)
isValid(v.Elem().Field(0))
isValid(v.Elem().Field(1))
+ isValid(v.Elem().Field(2))
isValid(v.Elem().FieldByName("X"))
isValid(v.Elem().FieldByName("Y"))
+ isValid(v.Elem().FieldByName("Z"))
isValid(v.Type().Method(0).Func)
+ m, _ := v.Type().MethodByName("M")
+ isValid(m.Func)
+ m, _ = v.Type().MethodByName("P")
+ isValid(m.Func)
isNonNil(v.Elem().Field(0).Interface())
isNonNil(v.Elem().Field(1).Interface())
+ isNonNil(v.Elem().Field(2).Field(2).Index(0))
isNonNil(v.Elem().FieldByName("X").Interface())
isNonNil(v.Elem().FieldByName("Y").Interface())
+ isNonNil(v.Elem().FieldByName("Z").Interface())
+ isNonNil(v.Elem().FieldByName("S").Index(0).Interface())
isNonNil(v.Type().Method(0).Func.Interface())
+ m, _ = v.Type().MethodByName("P")
+ isNonNil(m.Func.Interface())
var priv Private
v = ValueOf(&priv)
@@ -2824,6 +2863,170 @@ func TestUnexported(t *testing.T) {
shouldPanic(func() { v.Type().Method(0).Func.Interface() })
}
+func TestSetPanic(t *testing.T) {
+ ok := func(f func()) { f() }
+ bad := shouldPanic
+ clear := func(v Value) { v.Set(Zero(v.Type())) }
+
+ type t0 struct {
+ W int
+ }
+
+ type t1 struct {
+ Y int
+ t0
+ }
+
+ type T2 struct {
+ Z int
+ namedT0 t0
+ }
+
+ type T struct {
+ X int
+ t1
+ T2
+ NamedT1 t1
+ NamedT2 T2
+ namedT1 t1
+ namedT2 T2
+ }
+
+ // not addressable
+ v := ValueOf(T{})
+ bad(func() { clear(v.Field(0)) }) // .X
+ bad(func() { clear(v.Field(1)) }) // .t1
+ bad(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
+ bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
+ bad(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
+ bad(func() { clear(v.Field(2)) }) // .T2
+ bad(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
+ bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
+ bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+ bad(func() { clear(v.Field(3)) }) // .NamedT1
+ bad(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
+ bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
+ bad(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
+ bad(func() { clear(v.Field(4)) }) // .NamedT2
+ bad(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
+ bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
+ bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+ bad(func() { clear(v.Field(5)) }) // .namedT1
+ bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
+ bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
+ bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+ bad(func() { clear(v.Field(6)) }) // .namedT2
+ bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
+ bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
+ bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+
+ // addressable
+ v = ValueOf(&T{}).Elem()
+ ok(func() { clear(v.Field(0)) }) // .X
+ bad(func() { clear(v.Field(1)) }) // .t1
+ ok(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
+ bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
+ ok(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
+ ok(func() { clear(v.Field(2)) }) // .T2
+ ok(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
+ bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
+ bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+ ok(func() { clear(v.Field(3)) }) // .NamedT1
+ ok(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
+ bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
+ ok(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
+ ok(func() { clear(v.Field(4)) }) // .NamedT2
+ ok(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
+ bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
+ bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+ bad(func() { clear(v.Field(5)) }) // .namedT1
+ bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
+ bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
+ bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+ bad(func() { clear(v.Field(6)) }) // .namedT2
+ bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
+ bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
+ bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+}
+
+type timp int
+
+func (t timp) W() {}
+func (t timp) Y() {}
+func (t timp) w() {}
+func (t timp) y() {}
+
+func TestCallPanic(t *testing.T) {
+ type t0 interface {
+ W()
+ w()
+ }
+ type T1 interface {
+ Y()
+ y()
+ }
+ type T2 struct {
+ T1
+ t0
+ }
+ type T struct {
+ t0 // 0
+ T1 // 1
+
+ NamedT0 t0 // 2
+ NamedT1 T1 // 3
+ NamedT2 T2 // 4
+
+ namedT0 t0 // 5
+ namedT1 T1 // 6
+ namedT2 T2 // 7
+ }
+ ok := func(f func()) { f() }
+ bad := shouldPanic
+ call := func(v Value) { v.Call(nil) }
+
+ i := timp(0)
+ v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
+ ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
+ ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
+ bad(func() { call(v.Field(0).Method(1)) }) // .t0.w
+ bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
+ ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
+ ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y
+ bad(func() { call(v.Field(1).Method(1)) }) // .T1.y
+ bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
+
+ ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W
+ ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W
+ bad(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
+ bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
+
+ ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y
+ ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y
+ bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
+ bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
+
+ ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
+ ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
+ ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
+ ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
+
+ bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
+ bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
+ bad(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
+ bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
+
+ bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y
+ bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y
+ bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.y
+ bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y
+
+ bad(func() { call(v.Field(7).Field(0).Method(0)) }) // .namedT2.T1.Y
+ bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W
+ bad(func() { call(v.Field(7).Field(1).Method(0)) }) // .namedT2.t0.W
+ bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
+}
+
func shouldPanic(f func()) {
defer func() {
if recover() == nil {
@@ -4786,3 +4989,38 @@ func TestPtrToMethods(t *testing.T) {
t.Fatal("does not implement Stringer, but should")
}
}
+
+func TestMapAlloc(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping on gccgo until we have escape analysis")
+ }
+ m := ValueOf(make(map[int]int, 10))
+ k := ValueOf(5)
+ v := ValueOf(7)
+ allocs := testing.AllocsPerRun(100, func() {
+ m.SetMapIndex(k, v)
+ })
+ if allocs > 0.5 {
+ t.Errorf("allocs per map assignment: want 0 got %f", allocs)
+ }
+}
+
+func TestChanAlloc(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping on gccgo until we have escape analysis")
+ }
+ // Note: for a chan int, the return Value must be allocated, so we
+ // use a chan *int instead.
+ c := ValueOf(make(chan *int, 1))
+ v := ValueOf(new(int))
+ allocs := testing.AllocsPerRun(100, func() {
+ c.Send(v)
+ _, _ = c.Recv()
+ })
+ if allocs < 0.5 || allocs > 1.5 {
+ t.Errorf("allocs per chan send/recv: want 1 got %f", allocs)
+ }
+ // Note: there is one allocation in reflect.recv which seems to be
+ // a limitation of escape analysis. If that is ever fixed the
+ // allocs < 0.5 condition will trigger and this test should be fixed.
+}