| // Copyright 2009 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. | |
| package reflectlite_test | |
| import ( | |
| "encoding/base64" | |
| "fmt" | |
| . "internal/reflectlite" | |
| "math" | |
| "reflect" | |
| "runtime" | |
| "testing" | |
| "unsafe" | |
| ) | |
| func ToValue(v Value) reflect.Value { | |
| return reflect.ValueOf(ToInterface(v)) | |
| } | |
| func TypeString(t Type) string { | |
| return fmt.Sprintf("%T", ToInterface(Zero(t))) | |
| } | |
| type integer int | |
| type T struct { | |
| a int | |
| b float64 | |
| c string | |
| d *int | |
| } | |
| type pair struct { | |
| i interface{} | |
| s string | |
| } | |
| func assert(t *testing.T, s, want string) { | |
| t.Helper() | |
| if s != want { | |
| t.Errorf("have %#q want %#q", s, want) | |
| } | |
| } | |
| var typeTests = []pair{ | |
| {struct{ x int }{}, "int"}, | |
| {struct{ x int8 }{}, "int8"}, | |
| {struct{ x int16 }{}, "int16"}, | |
| {struct{ x int32 }{}, "int32"}, | |
| {struct{ x int64 }{}, "int64"}, | |
| {struct{ x uint }{}, "uint"}, | |
| {struct{ x uint8 }{}, "uint8"}, | |
| {struct{ x uint16 }{}, "uint16"}, | |
| {struct{ x uint32 }{}, "uint32"}, | |
| {struct{ x uint64 }{}, "uint64"}, | |
| {struct{ x float32 }{}, "float32"}, | |
| {struct{ x float64 }{}, "float64"}, | |
| {struct{ x int8 }{}, "int8"}, | |
| {struct{ x (**int8) }{}, "**int8"}, | |
| {struct{ x (**integer) }{}, "**reflectlite_test.integer"}, | |
| {struct{ x ([32]int32) }{}, "[32]int32"}, | |
| {struct{ x ([]int8) }{}, "[]int8"}, | |
| {struct{ x (map[string]int32) }{}, "map[string]int32"}, | |
| {struct{ x (chan<- string) }{}, "chan<- string"}, | |
| {struct { | |
| x struct { | |
| c chan *int32 | |
| d float32 | |
| } | |
| }{}, | |
| "struct { c chan *int32; d float32 }", | |
| }, | |
| {struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"}, | |
| {struct { | |
| x struct { | |
| c func(chan *integer, *int8) | |
| } | |
| }{}, | |
| "struct { c func(chan *reflectlite_test.integer, *int8) }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 | |
| b int32 | |
| } | |
| }{}, | |
| "struct { a int8; b int32 }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 | |
| b int8 | |
| c int32 | |
| } | |
| }{}, | |
| "struct { a int8; b int8; c int32 }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 | |
| b int8 | |
| c int8 | |
| d int32 | |
| } | |
| }{}, | |
| "struct { a int8; b int8; c int8; d int32 }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 | |
| b int8 | |
| c int8 | |
| d int8 | |
| e int32 | |
| } | |
| }{}, | |
| "struct { a int8; b int8; c int8; d int8; e int32 }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 | |
| b int8 | |
| c int8 | |
| d int8 | |
| e int8 | |
| f int32 | |
| } | |
| }{}, | |
| "struct { a int8; b int8; c int8; d int8; e int8; f int32 }", | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 `reflect:"hi there"` | |
| } | |
| }{}, | |
| `struct { a int8 "reflect:\"hi there\"" }`, | |
| }, | |
| {struct { | |
| x struct { | |
| a int8 `reflect:"hi \x00there\t\n\"\\"` | |
| } | |
| }{}, | |
| `struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`, | |
| }, | |
| {struct { | |
| x struct { | |
| f func(args ...int) | |
| } | |
| }{}, | |
| "struct { f func(...int) }", | |
| }, | |
| // {struct { | |
| // x (interface { | |
| // a(func(func(int) int) func(func(int)) int) | |
| // b() | |
| // }) | |
| // }{}, | |
| // "interface { reflectlite_test.a(func(func(int) int) func(func(int)) int); reflectlite_test.b() }", | |
| // }, | |
| {struct { | |
| x struct { | |
| int32 | |
| int64 | |
| } | |
| }{}, | |
| "struct { int32; int64 }", | |
| }, | |
| } | |
| var valueTests = []pair{ | |
| {new(int), "132"}, | |
| {new(int8), "8"}, | |
| {new(int16), "16"}, | |
| {new(int32), "32"}, | |
| {new(int64), "64"}, | |
| {new(uint), "132"}, | |
| {new(uint8), "8"}, | |
| {new(uint16), "16"}, | |
| {new(uint32), "32"}, | |
| {new(uint64), "64"}, | |
| {new(float32), "256.25"}, | |
| {new(float64), "512.125"}, | |
| {new(complex64), "532.125+10i"}, | |
| {new(complex128), "564.25+1i"}, | |
| {new(string), "stringy cheese"}, | |
| {new(bool), "true"}, | |
| {new(*int8), "*int8(0)"}, | |
| {new(**int8), "**int8(0)"}, | |
| {new([5]int32), "[5]int32{0, 0, 0, 0, 0}"}, | |
| {new(**integer), "**reflectlite_test.integer(0)"}, | |
| {new(map[string]int32), "map[string]int32{<can't iterate on maps>}"}, | |
| {new(chan<- string), "chan<- string"}, | |
| {new(func(a int8, b int32)), "func(int8, int32)(arg)"}, | |
| {new(struct { | |
| c chan *int32 | |
| d float32 | |
| }), | |
| "struct { c chan *int32; d float32 }{chan *int32, 0}", | |
| }, | |
| {new(struct{ c func(chan *integer, *int8) }), | |
| "struct { c func(chan *reflectlite_test.integer, *int8) }{func(chan *reflectlite_test.integer, *int8)(arg)}", | |
| }, | |
| {new(struct { | |
| a int8 | |
| b int32 | |
| }), | |
| "struct { a int8; b int32 }{0, 0}", | |
| }, | |
| {new(struct { | |
| a int8 | |
| b int8 | |
| c int32 | |
| }), | |
| "struct { a int8; b int8; c int32 }{0, 0, 0}", | |
| }, | |
| } | |
| func testType(t *testing.T, i int, typ Type, want string) { | |
| s := TypeString(typ) | |
| if s != want { | |
| t.Errorf("#%d: have %#q, want %#q", i, s, want) | |
| } | |
| } | |
| func testReflectType(t *testing.T, i int, typ Type, want string) { | |
| s := TypeString(typ) | |
| if s != want { | |
| t.Errorf("#%d: have %#q, want %#q", i, s, want) | |
| } | |
| } | |
| func TestTypes(t *testing.T) { | |
| for i, tt := range typeTests { | |
| testReflectType(t, i, Field(ValueOf(tt.i), 0).Type(), tt.s) | |
| } | |
| } | |
| func TestSetValue(t *testing.T) { | |
| for i, tt := range valueTests { | |
| v := ValueOf(tt.i).Elem() | |
| switch v.Kind() { | |
| case Int: | |
| v.Set(ValueOf(int(132))) | |
| case Int8: | |
| v.Set(ValueOf(int8(8))) | |
| case Int16: | |
| v.Set(ValueOf(int16(16))) | |
| case Int32: | |
| v.Set(ValueOf(int32(32))) | |
| case Int64: | |
| v.Set(ValueOf(int64(64))) | |
| case Uint: | |
| v.Set(ValueOf(uint(132))) | |
| case Uint8: | |
| v.Set(ValueOf(uint8(8))) | |
| case Uint16: | |
| v.Set(ValueOf(uint16(16))) | |
| case Uint32: | |
| v.Set(ValueOf(uint32(32))) | |
| case Uint64: | |
| v.Set(ValueOf(uint64(64))) | |
| case Float32: | |
| v.Set(ValueOf(float32(256.25))) | |
| case Float64: | |
| v.Set(ValueOf(512.125)) | |
| case Complex64: | |
| v.Set(ValueOf(complex64(532.125 + 10i))) | |
| case Complex128: | |
| v.Set(ValueOf(complex128(564.25 + 1i))) | |
| case String: | |
| v.Set(ValueOf("stringy cheese")) | |
| case Bool: | |
| v.Set(ValueOf(true)) | |
| } | |
| s := valueToString(v) | |
| if s != tt.s { | |
| t.Errorf("#%d: have %#q, want %#q", i, s, tt.s) | |
| } | |
| } | |
| } | |
| func TestCanSetField(t *testing.T) { | |
| type embed struct{ x, X int } | |
| type Embed struct{ x, X int } | |
| type S1 struct { | |
| embed | |
| x, X int | |
| } | |
| type S2 struct { | |
| *embed | |
| x, X int | |
| } | |
| type S3 struct { | |
| Embed | |
| x, X int | |
| } | |
| type S4 struct { | |
| *Embed | |
| x, X int | |
| } | |
| type testCase struct { | |
| index []int | |
| canSet bool | |
| } | |
| tests := []struct { | |
| val Value | |
| cases []testCase | |
| }{{ | |
| val: ValueOf(&S1{}), | |
| cases: []testCase{ | |
| {[]int{0}, false}, | |
| {[]int{0, 0}, false}, | |
| {[]int{0, 1}, true}, | |
| {[]int{1}, false}, | |
| {[]int{2}, true}, | |
| }, | |
| }, { | |
| val: ValueOf(&S2{embed: &embed{}}), | |
| cases: []testCase{ | |
| {[]int{0}, false}, | |
| {[]int{0, 0}, false}, | |
| {[]int{0, 1}, true}, | |
| {[]int{1}, false}, | |
| {[]int{2}, true}, | |
| }, | |
| }, { | |
| val: ValueOf(&S3{}), | |
| cases: []testCase{ | |
| {[]int{0}, true}, | |
| {[]int{0, 0}, false}, | |
| {[]int{0, 1}, true}, | |
| {[]int{1}, false}, | |
| {[]int{2}, true}, | |
| }, | |
| }, { | |
| val: ValueOf(&S4{Embed: &Embed{}}), | |
| cases: []testCase{ | |
| {[]int{0}, true}, | |
| {[]int{0, 0}, false}, | |
| {[]int{0, 1}, true}, | |
| {[]int{1}, false}, | |
| {[]int{2}, true}, | |
| }, | |
| }} | |
| for _, tt := range tests { | |
| t.Run(tt.val.Type().Name(), func(t *testing.T) { | |
| for _, tc := range tt.cases { | |
| f := tt.val | |
| for _, i := range tc.index { | |
| if f.Kind() == Ptr { | |
| f = f.Elem() | |
| } | |
| f = Field(f, i) | |
| } | |
| if got := f.CanSet(); got != tc.canSet { | |
| t.Errorf("CanSet() = %v, want %v", got, tc.canSet) | |
| } | |
| } | |
| }) | |
| } | |
| } | |
| var _i = 7 | |
| var valueToStringTests = []pair{ | |
| {123, "123"}, | |
| {123.5, "123.5"}, | |
| {byte(123), "123"}, | |
| {"abc", "abc"}, | |
| {T{123, 456.75, "hello", &_i}, "reflectlite_test.T{123, 456.75, hello, *int(&7)}"}, | |
| {new(chan *T), "*chan *reflectlite_test.T(&chan *reflectlite_test.T)"}, | |
| {[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"}, | |
| {&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"}, | |
| {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"}, | |
| {&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"}, | |
| } | |
| func TestValueToString(t *testing.T) { | |
| for i, test := range valueToStringTests { | |
| s := valueToString(ValueOf(test.i)) | |
| if s != test.s { | |
| t.Errorf("#%d: have %#q, want %#q", i, s, test.s) | |
| } | |
| } | |
| } | |
| func TestPtrSetNil(t *testing.T) { | |
| var i int32 = 1234 | |
| ip := &i | |
| vip := ValueOf(&ip) | |
| vip.Elem().Set(Zero(vip.Elem().Type())) | |
| if ip != nil { | |
| t.Errorf("got non-nil (%d), want nil", *ip) | |
| } | |
| } | |
| func TestMapSetNil(t *testing.T) { | |
| m := make(map[string]int) | |
| vm := ValueOf(&m) | |
| vm.Elem().Set(Zero(vm.Elem().Type())) | |
| if m != nil { | |
| t.Errorf("got non-nil (%p), want nil", m) | |
| } | |
| } | |
| func TestAll(t *testing.T) { | |
| testType(t, 1, TypeOf((int8)(0)), "int8") | |
| testType(t, 2, TypeOf((*int8)(nil)).Elem(), "int8") | |
| typ := TypeOf((*struct { | |
| c chan *int32 | |
| d float32 | |
| })(nil)) | |
| testType(t, 3, typ, "*struct { c chan *int32; d float32 }") | |
| etyp := typ.Elem() | |
| testType(t, 4, etyp, "struct { c chan *int32; d float32 }") | |
| } | |
| func TestInterfaceValue(t *testing.T) { | |
| var inter struct { | |
| E interface{} | |
| } | |
| inter.E = 123.456 | |
| v1 := ValueOf(&inter) | |
| v2 := Field(v1.Elem(), 0) | |
| // assert(t, TypeString(v2.Type()), "interface {}") | |
| v3 := v2.Elem() | |
| assert(t, TypeString(v3.Type()), "float64") | |
| i3 := ToInterface(v2) | |
| if _, ok := i3.(float64); !ok { | |
| t.Error("v2.Interface() did not return float64, got ", TypeOf(i3)) | |
| } | |
| } | |
| func TestFunctionValue(t *testing.T) { | |
| var x interface{} = func() {} | |
| v := ValueOf(x) | |
| if fmt.Sprint(ToInterface(v)) != fmt.Sprint(x) { | |
| t.Fatalf("TestFunction returned wrong pointer") | |
| } | |
| assert(t, TypeString(v.Type()), "func()") | |
| } | |
| var appendTests = []struct { | |
| orig, extra []int | |
| }{ | |
| {make([]int, 2, 4), []int{22}}, | |
| {make([]int, 2, 4), []int{22, 33, 44}}, | |
| } | |
| func sameInts(x, y []int) bool { | |
| if len(x) != len(y) { | |
| return false | |
| } | |
| for i, xx := range x { | |
| if xx != y[i] { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| func TestBigUnnamedStruct(t *testing.T) { | |
| b := struct{ a, b, c, d int64 }{1, 2, 3, 4} | |
| v := ValueOf(b) | |
| b1 := ToInterface(v).(struct { | |
| a, b, c, d int64 | |
| }) | |
| if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d { | |
| t.Errorf("ValueOf(%v).Interface().(*Big) = %v", b, b1) | |
| } | |
| } | |
| type big struct { | |
| a, b, c, d, e int64 | |
| } | |
| func TestBigStruct(t *testing.T) { | |
| b := big{1, 2, 3, 4, 5} | |
| v := ValueOf(b) | |
| b1 := ToInterface(v).(big) | |
| if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e { | |
| t.Errorf("ValueOf(%v).Interface().(big) = %v", b, b1) | |
| } | |
| } | |
| type Basic struct { | |
| x int | |
| y float32 | |
| } | |
| type NotBasic Basic | |
| type DeepEqualTest struct { | |
| a, b interface{} | |
| eq bool | |
| } | |
| // Simple functions for DeepEqual tests. | |
| var ( | |
| fn1 func() // nil. | |
| fn2 func() // nil. | |
| fn3 = func() { fn1() } // Not nil. | |
| ) | |
| type self struct{} | |
| type Loop *Loop | |
| type Loopy interface{} | |
| var loop1, loop2 Loop | |
| var loopy1, loopy2 Loopy | |
| func init() { | |
| loop1 = &loop2 | |
| loop2 = &loop1 | |
| loopy1 = &loopy2 | |
| loopy2 = &loopy1 | |
| } | |
| var typeOfTests = []DeepEqualTest{ | |
| // Equalities | |
| {nil, nil, true}, | |
| {1, 1, true}, | |
| {int32(1), int32(1), true}, | |
| {0.5, 0.5, true}, | |
| {float32(0.5), float32(0.5), true}, | |
| {"hello", "hello", true}, | |
| {make([]int, 10), make([]int, 10), true}, | |
| {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true}, | |
| {Basic{1, 0.5}, Basic{1, 0.5}, true}, | |
| {error(nil), error(nil), true}, | |
| {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true}, | |
| {fn1, fn2, true}, | |
| // Inequalities | |
| {1, 2, false}, | |
| {int32(1), int32(2), false}, | |
| {0.5, 0.6, false}, | |
| {float32(0.5), float32(0.6), false}, | |
| {"hello", "hey", false}, | |
| {make([]int, 10), make([]int, 11), false}, | |
| {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false}, | |
| {Basic{1, 0.5}, Basic{1, 0.6}, false}, | |
| {Basic{1, 0}, Basic{2, 0}, false}, | |
| {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false}, | |
| {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false}, | |
| {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false}, | |
| {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false}, | |
| {nil, 1, false}, | |
| {1, nil, false}, | |
| {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}, | |
| {[]int{}, []int{}, true}, | |
| {[]int(nil), []int(nil), true}, | |
| {map[int]int{}, map[int]int(nil), false}, | |
| {map[int]int{}, map[int]int{}, true}, | |
| {map[int]int(nil), map[int]int(nil), true}, | |
| // Mismatched types | |
| {1, 1.0, false}, | |
| {int32(1), int64(1), false}, | |
| {0.5, "hello", false}, | |
| {[]int{1, 2, 3}, [3]int{1, 2, 3}, false}, | |
| {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false}, | |
| {Basic{1, 0.5}, NotBasic{1, 0.5}, false}, | |
| {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false}, | |
| // Possible loops. | |
| {&loop1, &loop1, true}, | |
| {&loop1, &loop2, true}, | |
| {&loopy1, &loopy1, true}, | |
| {&loopy1, &loopy2, true}, | |
| } | |
| func TestTypeOf(t *testing.T) { | |
| // Special case for nil | |
| if typ := TypeOf(nil); typ != nil { | |
| t.Errorf("expected nil type for nil value; got %v", typ) | |
| } | |
| for _, test := range typeOfTests { | |
| v := ValueOf(test.a) | |
| if !v.IsValid() { | |
| continue | |
| } | |
| typ := TypeOf(test.a) | |
| if typ != v.Type() { | |
| t.Errorf("TypeOf(%v) = %v, but ValueOf(%v).Type() = %v", test.a, typ, test.a, v.Type()) | |
| } | |
| } | |
| } | |
| func Nil(a interface{}, t *testing.T) { | |
| n := Field(ValueOf(a), 0) | |
| if !n.IsNil() { | |
| t.Errorf("%v should be nil", a) | |
| } | |
| } | |
| func NotNil(a interface{}, t *testing.T) { | |
| n := Field(ValueOf(a), 0) | |
| if n.IsNil() { | |
| t.Errorf("value of type %v should not be nil", TypeString(ValueOf(a).Type())) | |
| } | |
| } | |
| func TestIsNil(t *testing.T) { | |
| // These implement IsNil. | |
| // Wrap in extra struct to hide interface type. | |
| doNil := []interface{}{ | |
| struct{ x *int }{}, | |
| struct{ x interface{} }{}, | |
| struct{ x map[string]int }{}, | |
| struct{ x func() bool }{}, | |
| struct{ x chan int }{}, | |
| struct{ x []string }{}, | |
| struct{ x unsafe.Pointer }{}, | |
| } | |
| for _, ts := range doNil { | |
| ty := TField(TypeOf(ts), 0) | |
| v := Zero(ty) | |
| v.IsNil() // panics if not okay to call | |
| } | |
| // Check the implementations | |
| var pi struct { | |
| x *int | |
| } | |
| Nil(pi, t) | |
| pi.x = new(int) | |
| NotNil(pi, t) | |
| var si struct { | |
| x []int | |
| } | |
| Nil(si, t) | |
| si.x = make([]int, 10) | |
| NotNil(si, t) | |
| var ci struct { | |
| x chan int | |
| } | |
| Nil(ci, t) | |
| ci.x = make(chan int) | |
| NotNil(ci, t) | |
| var mi struct { | |
| x map[int]int | |
| } | |
| Nil(mi, t) | |
| mi.x = make(map[int]int) | |
| NotNil(mi, t) | |
| var ii struct { | |
| x interface{} | |
| } | |
| Nil(ii, t) | |
| ii.x = 2 | |
| NotNil(ii, t) | |
| var fi struct { | |
| x func(t *testing.T) | |
| } | |
| Nil(fi, t) | |
| fi.x = TestIsNil | |
| NotNil(fi, t) | |
| } | |
| // Indirect returns the value that v points to. | |
| // If v is a nil pointer, Indirect returns a zero Value. | |
| // If v is not a pointer, Indirect returns v. | |
| func Indirect(v Value) Value { | |
| if v.Kind() != Ptr { | |
| return v | |
| } | |
| return v.Elem() | |
| } | |
| func TestNilPtrValueSub(t *testing.T) { | |
| var pi *int | |
| if pv := ValueOf(pi); pv.Elem().IsValid() { | |
| t.Error("ValueOf((*int)(nil)).Elem().IsValid()") | |
| } | |
| } | |
| type Point struct { | |
| x, y int | |
| } | |
| // This will be index 0. | |
| func (p Point) AnotherMethod(scale int) int { | |
| return -1 | |
| } | |
| // This will be index 1. | |
| func (p Point) Dist(scale int) int { | |
| //println("Point.Dist", p.x, p.y, scale) | |
| return p.x*p.x*scale + p.y*p.y*scale | |
| } | |
| // This will be index 2. | |
| func (p Point) GCMethod(k int) int { | |
| runtime.GC() | |
| return k + p.x | |
| } | |
| // This will be index 3. | |
| func (p Point) NoArgs() { | |
| // Exercise no-argument/no-result paths. | |
| } | |
| // This will be index 4. | |
| func (p Point) TotalDist(points ...Point) int { | |
| tot := 0 | |
| for _, q := range points { | |
| dx := q.x - p.x | |
| dy := q.y - p.y | |
| tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test. | |
| } | |
| return tot | |
| } | |
| type D1 struct { | |
| d int | |
| } | |
| type D2 struct { | |
| d int | |
| } | |
| func TestImportPath(t *testing.T) { | |
| tests := []struct { | |
| t Type | |
| path string | |
| }{ | |
| {TypeOf(&base64.Encoding{}).Elem(), "encoding/base64"}, | |
| {TypeOf(int(0)), ""}, | |
| {TypeOf(int8(0)), ""}, | |
| {TypeOf(int16(0)), ""}, | |
| {TypeOf(int32(0)), ""}, | |
| {TypeOf(int64(0)), ""}, | |
| {TypeOf(uint(0)), ""}, | |
| {TypeOf(uint8(0)), ""}, | |
| {TypeOf(uint16(0)), ""}, | |
| {TypeOf(uint32(0)), ""}, | |
| {TypeOf(uint64(0)), ""}, | |
| {TypeOf(uintptr(0)), ""}, | |
| {TypeOf(float32(0)), ""}, | |
| {TypeOf(float64(0)), ""}, | |
| {TypeOf(complex64(0)), ""}, | |
| {TypeOf(complex128(0)), ""}, | |
| {TypeOf(byte(0)), ""}, | |
| {TypeOf(rune(0)), ""}, | |
| {TypeOf([]byte(nil)), ""}, | |
| {TypeOf([]rune(nil)), ""}, | |
| {TypeOf(string("")), ""}, | |
| {TypeOf((*interface{})(nil)).Elem(), ""}, | |
| {TypeOf((*byte)(nil)), ""}, | |
| {TypeOf((*rune)(nil)), ""}, | |
| {TypeOf((*int64)(nil)), ""}, | |
| {TypeOf(map[string]int{}), ""}, | |
| {TypeOf((*error)(nil)).Elem(), ""}, | |
| {TypeOf((*Point)(nil)), ""}, | |
| {TypeOf((*Point)(nil)).Elem(), "internal/reflectlite_test"}, | |
| } | |
| for _, test := range tests { | |
| if path := test.t.PkgPath(); path != test.path { | |
| t.Errorf("%v.PkgPath() = %q, want %q", test.t, path, test.path) | |
| } | |
| } | |
| } | |
| func noAlloc(t *testing.T, n int, f func(int)) { | |
| if testing.Short() { | |
| t.Skip("skipping malloc count in short mode") | |
| } | |
| if runtime.GOMAXPROCS(0) > 1 { | |
| t.Skip("skipping; GOMAXPROCS>1") | |
| } | |
| i := -1 | |
| allocs := testing.AllocsPerRun(n, func() { | |
| f(i) | |
| i++ | |
| }) | |
| if allocs > 0 { | |
| t.Errorf("%d iterations: got %v mallocs, want 0", n, allocs) | |
| } | |
| } | |
| func TestAllocations(t *testing.T) { | |
| noAlloc(t, 100, func(j int) { | |
| var i interface{} | |
| var v Value | |
| // We can uncomment this when compiler escape analysis | |
| // is good enough to see that the integer assigned to i | |
| // does not escape and therefore need not be allocated. | |
| // | |
| // i = 42 + j | |
| // v = ValueOf(i) | |
| // if int(v.Int()) != 42+j { | |
| // panic("wrong int") | |
| // } | |
| i = func(j int) int { return j } | |
| v = ValueOf(i) | |
| if ToInterface(v).(func(int) int)(j) != j { | |
| panic("wrong result") | |
| } | |
| }) | |
| } | |
| 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(Field(v, 0)) }) // .X | |
| bad(func() { clear(Field(v, 1)) }) // .t1 | |
| bad(func() { clear(Field(Field(v, 1), 0)) }) // .t1.Y | |
| bad(func() { clear(Field(Field(v, 1), 1)) }) // .t1.t0 | |
| bad(func() { clear(Field(Field(Field(v, 1), 1), 0)) }) // .t1.t0.W | |
| bad(func() { clear(Field(v, 2)) }) // .T2 | |
| bad(func() { clear(Field(Field(v, 2), 0)) }) // .T2.Z | |
| bad(func() { clear(Field(Field(v, 2), 1)) }) // .T2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 2), 1), 0)) }) // .T2.namedT0.W | |
| bad(func() { clear(Field(v, 3)) }) // .NamedT1 | |
| bad(func() { clear(Field(Field(v, 3), 0)) }) // .NamedT1.Y | |
| bad(func() { clear(Field(Field(v, 3), 1)) }) // .NamedT1.t0 | |
| bad(func() { clear(Field(Field(Field(v, 3), 1), 0)) }) // .NamedT1.t0.W | |
| bad(func() { clear(Field(v, 4)) }) // .NamedT2 | |
| bad(func() { clear(Field(Field(v, 4), 0)) }) // .NamedT2.Z | |
| bad(func() { clear(Field(Field(v, 4), 1)) }) // .NamedT2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 4), 1), 0)) }) // .NamedT2.namedT0.W | |
| bad(func() { clear(Field(v, 5)) }) // .namedT1 | |
| bad(func() { clear(Field(Field(v, 5), 0)) }) // .namedT1.Y | |
| bad(func() { clear(Field(Field(v, 5), 1)) }) // .namedT1.t0 | |
| bad(func() { clear(Field(Field(Field(v, 5), 1), 0)) }) // .namedT1.t0.W | |
| bad(func() { clear(Field(v, 6)) }) // .namedT2 | |
| bad(func() { clear(Field(Field(v, 6), 0)) }) // .namedT2.Z | |
| bad(func() { clear(Field(Field(v, 6), 1)) }) // .namedT2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 6), 1), 0)) }) // .namedT2.namedT0.W | |
| // addressable | |
| v = ValueOf(&T{}).Elem() | |
| ok(func() { clear(Field(v, 0)) }) // .X | |
| bad(func() { clear(Field(v, 1)) }) // .t1 | |
| ok(func() { clear(Field(Field(v, 1), 0)) }) // .t1.Y | |
| bad(func() { clear(Field(Field(v, 1), 1)) }) // .t1.t0 | |
| ok(func() { clear(Field(Field(Field(v, 1), 1), 0)) }) // .t1.t0.W | |
| ok(func() { clear(Field(v, 2)) }) // .T2 | |
| ok(func() { clear(Field(Field(v, 2), 0)) }) // .T2.Z | |
| bad(func() { clear(Field(Field(v, 2), 1)) }) // .T2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 2), 1), 0)) }) // .T2.namedT0.W | |
| ok(func() { clear(Field(v, 3)) }) // .NamedT1 | |
| ok(func() { clear(Field(Field(v, 3), 0)) }) // .NamedT1.Y | |
| bad(func() { clear(Field(Field(v, 3), 1)) }) // .NamedT1.t0 | |
| ok(func() { clear(Field(Field(Field(v, 3), 1), 0)) }) // .NamedT1.t0.W | |
| ok(func() { clear(Field(v, 4)) }) // .NamedT2 | |
| ok(func() { clear(Field(Field(v, 4), 0)) }) // .NamedT2.Z | |
| bad(func() { clear(Field(Field(v, 4), 1)) }) // .NamedT2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 4), 1), 0)) }) // .NamedT2.namedT0.W | |
| bad(func() { clear(Field(v, 5)) }) // .namedT1 | |
| bad(func() { clear(Field(Field(v, 5), 0)) }) // .namedT1.Y | |
| bad(func() { clear(Field(Field(v, 5), 1)) }) // .namedT1.t0 | |
| bad(func() { clear(Field(Field(Field(v, 5), 1), 0)) }) // .namedT1.t0.W | |
| bad(func() { clear(Field(v, 6)) }) // .namedT2 | |
| bad(func() { clear(Field(Field(v, 6), 0)) }) // .namedT2.Z | |
| bad(func() { clear(Field(Field(v, 6), 1)) }) // .namedT2.namedT0 | |
| bad(func() { clear(Field(Field(Field(v, 6), 1), 0)) }) // .namedT2.namedT0.W | |
| } | |
| func shouldPanic(f func()) { | |
| defer func() { | |
| if recover() == nil { | |
| panic("did not panic") | |
| } | |
| }() | |
| f() | |
| } | |
| type S struct { | |
| i1 int64 | |
| i2 int64 | |
| } | |
| func TestBigZero(t *testing.T) { | |
| const size = 1 << 10 | |
| var v [size]byte | |
| z := ToInterface(Zero(ValueOf(v).Type())).([size]byte) | |
| for i := 0; i < size; i++ { | |
| if z[i] != 0 { | |
| t.Fatalf("Zero object not all zero, index %d", i) | |
| } | |
| } | |
| } | |
| func TestInvalid(t *testing.T) { | |
| // Used to have inconsistency between IsValid() and Kind() != Invalid. | |
| type T struct{ v interface{} } | |
| v := Field(ValueOf(T{}), 0) | |
| if v.IsValid() != true || v.Kind() != Interface { | |
| t.Errorf("field: IsValid=%v, Kind=%v, want true, Interface", v.IsValid(), v.Kind()) | |
| } | |
| v = v.Elem() | |
| if v.IsValid() != false || v.Kind() != Invalid { | |
| t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind()) | |
| } | |
| } | |
| type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int | |
| type nameTest struct { | |
| v interface{} | |
| want string | |
| } | |
| var nameTests = []nameTest{ | |
| {(*int32)(nil), "int32"}, | |
| {(*D1)(nil), "D1"}, | |
| {(*[]D1)(nil), ""}, | |
| {(*chan D1)(nil), ""}, | |
| {(*func() D1)(nil), ""}, | |
| {(*<-chan D1)(nil), ""}, | |
| {(*chan<- D1)(nil), ""}, | |
| {(*interface{})(nil), ""}, | |
| {(*interface { | |
| F() | |
| })(nil), ""}, | |
| {(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"}, | |
| } | |
| func TestNames(t *testing.T) { | |
| for _, test := range nameTests { | |
| typ := TypeOf(test.v).Elem() | |
| if got := typ.Name(); got != test.want { | |
| t.Errorf("%v Name()=%q, want %q", typ, got, test.want) | |
| } | |
| } | |
| } | |
| type embed struct { | |
| EmbedWithUnexpMeth | |
| } | |
| func TestNameBytesAreAligned(t *testing.T) { | |
| typ := TypeOf(embed{}) | |
| b := FirstMethodNameBytes(typ) | |
| v := uintptr(unsafe.Pointer(b)) | |
| if v%unsafe.Alignof((*byte)(nil)) != 0 { | |
| t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) | |
| } | |
| } | |
| // TestUnaddressableField tests that the reflect package will not allow | |
| // a type from another package to be used as a named type with an | |
| // unexported field. | |
| // | |
| // This ensures that unexported fields cannot be modified by other packages. | |
| func TestUnaddressableField(t *testing.T) { | |
| var b Buffer // type defined in reflect, a different package | |
| var localBuffer struct { | |
| buf []byte | |
| } | |
| lv := ValueOf(&localBuffer).Elem() | |
| rv := ValueOf(b) | |
| shouldPanic(func() { | |
| lv.Set(rv) | |
| }) | |
| } | |
| type Tint int | |
| type Tint2 = Tint | |
| type Talias1 struct { | |
| byte | |
| uint8 | |
| int | |
| int32 | |
| rune | |
| } | |
| type Talias2 struct { | |
| Tint | |
| Tint2 | |
| } | |
| func TestAliasNames(t *testing.T) { | |
| t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5} | |
| out := fmt.Sprintf("%#v", t1) | |
| want := "reflectlite_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}" | |
| if out != want { | |
| t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want) | |
| } | |
| t2 := Talias2{Tint: 1, Tint2: 2} | |
| out = fmt.Sprintf("%#v", t2) | |
| want = "reflectlite_test.Talias2{Tint:1, Tint2:2}" | |
| if out != want { | |
| t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want) | |
| } | |
| } |