diff options
Diffstat (limited to 'libgo/go/reflect/all_test.go')
-rw-r--r-- | libgo/go/reflect/all_test.go | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 33ee9ed..595d690 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. +} |