github.com/goplus/reflectx@v1.2.2/reflectx_test.go (about)

     1  package reflectx_test
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"runtime"
     8  	"testing"
     9  	"unsafe"
    10  
    11  	"github.com/goplus/reflectx"
    12  )
    13  
    14  type nPoint struct {
    15  	x int
    16  	y int
    17  }
    18  
    19  func TestFieldCanSet(t *testing.T) {
    20  	x := &nPoint{10, 20}
    21  	v := reflect.ValueOf(x).Elem()
    22  
    23  	sf := v.Field(0)
    24  	if sf.CanSet() {
    25  		t.Fatal("x unexport cannot set")
    26  	}
    27  
    28  	sf = reflectx.CanSet(sf)
    29  	if !sf.CanSet() {
    30  		t.Fatal("CanSet failed")
    31  	}
    32  
    33  	sf.Set(reflect.ValueOf(201))
    34  	if x.x != 201 {
    35  		t.Fatalf("x value %v", x.x)
    36  	}
    37  	sf.SetInt(202)
    38  	if x.x != 202 {
    39  		t.Fatalf("x value %v", x.x)
    40  	}
    41  }
    42  
    43  type Rect struct {
    44  	pt1 nPoint
    45  	pt2 *nPoint
    46  }
    47  
    48  func TestField(t *testing.T) {
    49  	x := &Rect{nPoint{1, 2}, &nPoint{3, 4}}
    50  	v := reflect.ValueOf(x).Elem()
    51  	reflectx.Field(v, 0).Set(reflect.ValueOf(nPoint{10, 20}))
    52  	if x.pt1.x != 10 || x.pt1.y != 20 {
    53  		t.Fatalf("pt1 %v", x.pt1)
    54  	}
    55  	reflectx.FieldByName(v, "pt2").Set(reflect.ValueOf(&nPoint{30, 40}))
    56  	if x.pt2.x != 30 || x.pt2.y != 40 {
    57  		t.Fatalf("pt2 %v", x.pt2)
    58  	}
    59  	reflectx.FieldByNameFunc(v, func(name string) bool {
    60  		return name == "pt2"
    61  	}).Set(reflect.ValueOf(&nPoint{50, 60}))
    62  	if x.pt2.x != 50 || x.pt2.y != 60 {
    63  		t.Fatalf("pt2 %v", x.pt2)
    64  	}
    65  	reflectx.FieldByIndex(v, []int{0, 1}).SetInt(100)
    66  	if x.pt1.y != 100 {
    67  		t.Fatalf("pt1.y %v", x.pt1)
    68  	}
    69  }
    70  
    71  func TestFieldX(t *testing.T) {
    72  	x := &Rect{nPoint{1, 2}, &nPoint{3, 4}}
    73  	v := reflect.ValueOf(x).Elem()
    74  	reflectx.FieldX(v, 0).Set(reflect.ValueOf(nPoint{10, 20}))
    75  	if x.pt1.x != 10 || x.pt1.y != 20 {
    76  		t.Fatalf("pt1 %v", x.pt1)
    77  	}
    78  	reflectx.FieldByNameX(v, "pt2").Set(reflect.ValueOf(&nPoint{30, 40}))
    79  	if x.pt2.x != 30 || x.pt2.y != 40 {
    80  		t.Fatalf("pt2 %v", x.pt2)
    81  	}
    82  	reflectx.FieldByNameFuncX(v, func(name string) bool {
    83  		return name == "pt2"
    84  	}).Set(reflect.ValueOf(&nPoint{50, 60}))
    85  	if x.pt2.x != 50 || x.pt2.y != 60 {
    86  		t.Fatalf("pt2 %v", x.pt2)
    87  	}
    88  	reflectx.FieldByIndexX(v, []int{0, 1}).SetInt(100)
    89  	if x.pt1.y != 100 {
    90  		t.Fatalf("pt1.y %v", x.pt1)
    91  	}
    92  }
    93  
    94  func TestStructOfUnderscore(t *testing.T) {
    95  	fs := []reflect.StructField{
    96  		reflect.StructField{
    97  			Name:    "_",
    98  			PkgPath: "main",
    99  			Type:    tyInt,
   100  		},
   101  		reflect.StructField{
   102  			Name:    "_",
   103  			PkgPath: "main",
   104  			Type:    tyInt,
   105  		},
   106  	}
   107  	typ := reflectx.NamedStructOf("main", "Point", fs)
   108  	if typ.Field(0).Name != "_" {
   109  		t.Fatalf("field name must underscore")
   110  	}
   111  	if typ.Field(1).Name != "_" {
   112  		t.Fatalf("field name must underscore")
   113  	}
   114  }
   115  
   116  func TestStructOfExport(t *testing.T) {
   117  	fs := []reflect.StructField{
   118  		reflect.StructField{
   119  			Name:    "x",
   120  			PkgPath: "main",
   121  			Type:    tyInt,
   122  		},
   123  		reflect.StructField{
   124  			Name:    "y",
   125  			PkgPath: "main",
   126  			Type:    tyInt,
   127  		},
   128  	}
   129  	typ := reflectx.NamedStructOf("main", "Point", fs)
   130  	v := reflect.New(typ).Elem()
   131  	reflectx.FieldByIndex(v, []int{0}).SetInt(100)
   132  	reflectx.FieldByIndex(v, []int{1}).SetInt(200)
   133  	if s := fmt.Sprint(v); s != "{100 200}" {
   134  		t.Fatalf("have %v, want {100 200}", s)
   135  	}
   136  }
   137  
   138  type Buffer struct {
   139  	*bytes.Buffer
   140  	size  int
   141  	value reflect.Value
   142  	*bytes.Reader
   143  }
   144  
   145  func TestStructOf(t *testing.T) {
   146  	defer func() {
   147  		v := recover()
   148  		if v != nil {
   149  			t.Fatalf("reflectx.StructOf %v", v)
   150  		}
   151  	}()
   152  	typ := reflect.TypeOf((*Buffer)(nil)).Elem()
   153  	var fs []reflect.StructField
   154  	for i := 0; i < typ.NumField(); i++ {
   155  		fs = append(fs, typ.Field(i))
   156  	}
   157  	dst := reflectx.StructOf(fs)
   158  	for i := 0; i < dst.NumField(); i++ {
   159  		if dst.Field(i).Anonymous != fs[i].Anonymous {
   160  			t.Errorf("error field %v", dst.Field(i))
   161  		}
   162  	}
   163  
   164  	v := reflect.New(dst)
   165  	v.Elem().Field(0).Set(reflect.ValueOf(bytes.NewBufferString("hello")))
   166  	reflectx.CanSet(v.Elem().Field(1)).SetInt(100)
   167  }
   168  
   169  func TestNamedStruct(t *testing.T) {
   170  	fs := []reflect.StructField{
   171  		reflect.StructField{Name: "X", Type: reflect.TypeOf(0)},
   172  		reflect.StructField{Name: "Y", Type: reflect.TypeOf(0)},
   173  	}
   174  	t1 := reflect.StructOf(fs)
   175  	t2 := reflect.StructOf(fs)
   176  	if t1 != t2 {
   177  		t.Fatalf("reflect.StructOf %v != %v", t1, t2)
   178  	}
   179  	t3 := reflectx.NamedStructOf("github.com/goplus/reflectx_test", "Point", fs)
   180  	t4 := reflectx.NamedStructOf("github.com/goplus/reflectx_test", "Point2", fs)
   181  	if t3 == t4 {
   182  		t.Fatalf("NamedStructOf %v == %v", t3, t4)
   183  	}
   184  	if t4.String() != "reflectx_test.Point2" {
   185  		t.Fatalf("t4.String=%v", t4.String())
   186  	}
   187  	if t4.Name() != "Point2" {
   188  		t.Fatalf("t4.Name=%v", t4.Name())
   189  	}
   190  	if t4.PkgPath() != "github.com/goplus/reflectx_test" {
   191  		t.Fatalf("t4.PkgPath=%v", t4.PkgPath())
   192  	}
   193  }
   194  
   195  var (
   196  	ch = make(chan bool)
   197  	fn = func(int, string) (bool, int) {
   198  		return true, 0
   199  	}
   200  	fn2 = func(*nPoint, int, bool, []byte) int {
   201  		return 0
   202  	}
   203  	testNamedValue = []interface{}{
   204  		true,
   205  		false,
   206  		int(2),
   207  		int8(3),
   208  		int16(4),
   209  		int32(5),
   210  		int64(6),
   211  		uint(7),
   212  		uint8(8),
   213  		uint16(9),
   214  		uint32(10),
   215  		uint64(11),
   216  		uintptr(12),
   217  		float32(13),
   218  		float64(14),
   219  		complex64(15),
   220  		complex128(16),
   221  		"hello",
   222  		unsafe.Pointer(nil),
   223  		unsafe.Pointer(&fn),
   224  		[]byte("hello"),
   225  		[]int{1, 2, 3},
   226  		[5]byte{'a', 'b', 'c', 'd', 'e'},
   227  		[5]int{1, 2, 3, 4, 5},
   228  		[]string{"a", "b"},
   229  		[]int{100, 200},
   230  		map[int]string{1: "hello", 2: "world"},
   231  		new(uint8),
   232  		&fn,
   233  		&fn2,
   234  		&ch,
   235  		ch,
   236  		fn,
   237  		fn2,
   238  	}
   239  )
   240  
   241  func TestNamedType(t *testing.T) {
   242  	pkgpath := "github.com/goplus/reflectx"
   243  	for i, v := range testNamedValue {
   244  		value := reflect.ValueOf(v)
   245  		typ := value.Type()
   246  		nt := reflectx.NamedTypeOf("github.com/goplus/reflectx", fmt.Sprintf("MyType%v", i), typ)
   247  		if nt.Kind() != typ.Kind() {
   248  			t.Errorf("kind: have %v, want %v", nt.Kind(), typ.Kind())
   249  		}
   250  		if nt == typ {
   251  			t.Errorf("same type, %v", typ)
   252  		}
   253  		name := fmt.Sprintf("My_Type%v", i)
   254  		nt2 := reflectx.NamedTypeOf(pkgpath, name, typ)
   255  		if nt == nt2 {
   256  			t.Errorf("same type, %v", nt)
   257  		}
   258  		nv := reflect.New(nt).Elem()
   259  		reflectx.SetValue(nv, value) //
   260  		s1 := fmt.Sprint((nv))
   261  		s2 := fmt.Sprint(v)
   262  		if s1 != s2 {
   263  			t.Errorf("%v: have %v, want %v", nt.Kind(), s1, s2)
   264  		}
   265  		if nt2.Name() != name {
   266  			t.Errorf("name: have %v, want %v", nt2.Name(), name)
   267  		}
   268  		if nt2.PkgPath() != pkgpath {
   269  			t.Errorf("pkgpath: have %v, want %v", nt2.PkgPath(), pkgpath)
   270  		}
   271  	}
   272  }
   273  
   274  var testInterfaceType = []reflect.Type{
   275  	reflect.TypeOf((*interface{})(nil)).Elem(),
   276  	reflect.TypeOf((*fmt.Stringer)(nil)).Elem(),
   277  	reflect.TypeOf((*interface {
   278  		Read(p []byte) (n int, err error)
   279  		Write(p []byte) (n int, err error)
   280  		Close() error
   281  	})(nil)),
   282  }
   283  
   284  func TestNamedInterface(t *testing.T) {
   285  	pkgpath := "main"
   286  	for i, styp := range testInterfaceType {
   287  		name := fmt.Sprintf("T%v", i)
   288  		typ := reflectx.NamedTypeOf(pkgpath, name, styp)
   289  		if typ.Name() != name {
   290  			t.Errorf("name: have %v, want %v", typ.Name(), name)
   291  		}
   292  		if typ.PkgPath() != pkgpath {
   293  			t.Errorf("pkgpath: have %v, want %v", typ.PkgPath(), pkgpath)
   294  		}
   295  		if typ.NumMethod() != styp.NumMethod() {
   296  			t.Errorf("num method: have %v, want %v", typ.NumMethod(), styp.NumMethod())
   297  		}
   298  		for i := 0; i < typ.NumMethod(); i++ {
   299  			if typ.Method(i) != styp.Method(i) {
   300  				t.Errorf("method: have %v, want %v", typ.Method(i), styp.Method(i))
   301  			}
   302  		}
   303  		if !typ.ConvertibleTo(styp) {
   304  			t.Errorf("%v cannot ConvertibleTo %v", typ, styp)
   305  		}
   306  		if !styp.ConvertibleTo(typ) {
   307  			t.Errorf("%v cannot ConvertibleTo %v", styp, typ)
   308  		}
   309  	}
   310  }
   311  
   312  func TestNamedTypeStruct(t *testing.T) {
   313  	typ := reflect.TypeOf((*nPoint)(nil)).Elem()
   314  	pkgpath := typ.PkgPath()
   315  	nt := reflectx.NamedTypeOf(pkgpath, "MyPoint", typ)
   316  	nt2 := reflectx.NamedTypeOf(pkgpath, "MyPoint2", typ)
   317  	if nt.NumField() != typ.NumField() {
   318  		t.Fatal("NumField != 2", nt.NumField())
   319  	}
   320  	if nt.Name() != "MyPoint" {
   321  		t.Fatal("Name != MyPoint", nt.Name())
   322  	}
   323  	if nt == nt2 {
   324  		t.Fatalf("same type %v", nt)
   325  	}
   326  	v := reflect.New(nt).Elem()
   327  	reflectx.Field(v, 0).SetInt(100)
   328  	reflectx.Field(v, 1).SetInt(200)
   329  	if v.FieldByName("x").Int() != 100 || v.FieldByName("y").Int() != 200 {
   330  		t.Fatal("Value != {100 200},", v)
   331  	}
   332  }
   333  
   334  func TestSetElem(t *testing.T) {
   335  	if runtime.Compiler == "gopherjs" {
   336  		t.Skip("skip gopherjs")
   337  	}
   338  	typ := reflectx.NamedTypeOf("main", "T", reflect.TypeOf(([]struct{})(nil)))
   339  	reflectx.SetElem(typ, typ)
   340  	v := reflect.MakeSlice(typ, 3, 3)
   341  	v.Index(0).Set(reflect.MakeSlice(typ, 1, 1))
   342  	v.Index(1).Set(reflect.MakeSlice(typ, 2, 2))
   343  	s := fmt.Sprintf("%v", v.Interface())
   344  	if s != "[[[]] [[] []] []]" {
   345  		t.Fatalf("failed SetElem s=%v", s)
   346  	}
   347  }
   348  
   349  func TestNamedStructComparable(t *testing.T) {
   350  	if runtime.Compiler == "gopherjs" {
   351  		t.Skip("skip gopherjs")
   352  	}
   353  	fs := []reflect.StructField{
   354  		reflect.StructField{Name: "_", PkgPath: "main", Type: reflect.TypeOf(0)},
   355  		reflect.StructField{Name: "x", PkgPath: "main", Type: reflect.TypeOf(0)},
   356  	}
   357  	typ := reflectx.NamedStructOf("main", "blankStruct", fs)
   358  	v1 := reflect.New(typ).Elem()
   359  	reflectx.Field(v1, 0).SetInt(100)
   360  	reflectx.Field(v1, 1).SetInt(200)
   361  	v2 := reflect.New(typ).Elem()
   362  	reflectx.Field(v2, 0).SetInt(-100)
   363  	reflectx.Field(v2, 1).SetInt(200)
   364  	if v1.Interface() != v2.Interface() {
   365  		t.Fatal("failed struct equal")
   366  	}
   367  }
   368  
   369  func TestNamedStructUncomparable(t *testing.T) {
   370  	fs := []reflect.StructField{
   371  		reflect.StructField{Name: "_", PkgPath: "main", Type: reflect.TypeOf(0)},
   372  		reflect.StructField{Name: "fn", PkgPath: "main", Type: reflect.TypeOf(func() {})},
   373  	}
   374  	typ := reflectx.NamedStructOf("main", "funcStruct", fs)
   375  	v1 := reflect.New(typ).Elem()
   376  	v2 := reflect.New(typ).Elem()
   377  	defer func() {
   378  		if err := recover(); err == nil {
   379  			t.Fatal("must panic comparing uncomparable type")
   380  		}
   381  	}()
   382  	if v1.Interface() == v2.Interface() {
   383  		t.Fatal("must panic")
   384  	}
   385  }
   386  
   387  type point struct {
   388  	x int
   389  	y int
   390  }
   391  
   392  func (p *point) Set(x, y int) {
   393  	p.x, p.y = x, y
   394  }
   395  
   396  func (p *point) mset(x, y int) {
   397  	p.x, p.y = x, y
   398  }
   399  
   400  func (p *point) String() string {
   401  	return fmt.Sprintf("(%v,%v)", p.x, p.y)
   402  }
   403  
   404  func TestMethodX(t *testing.T) {
   405  	typ := reflect.TypeOf((*point)(nil))
   406  	if n := reflectx.NumMethodX(typ); n != 3 {
   407  		t.Fatalf("all method got: %v, want 3", n)
   408  	}
   409  	if m, ok := reflectx.MethodByName(typ, "mset"); !ok || m.Name != "mset" {
   410  		t.Fatalf("failed lookup method mset %v\n", m)
   411  	}
   412  }