github.com/goplus/reflectx@v1.2.2/method_test.go (about) 1 package reflectx_test 2 3 import ( 4 "fmt" 5 "io" 6 "reflect" 7 "runtime" 8 "strconv" 9 "testing" 10 "time" 11 12 "github.com/goplus/reflectx" 13 ) 14 15 var ( 16 tyByte = reflect.TypeOf(byte('a')) 17 tyBool = reflect.TypeOf(true) 18 tyInt = reflect.TypeOf(0) 19 tyString = reflect.TypeOf("") 20 tyError = reflect.TypeOf((*error)(nil)).Elem() 21 tyEmptyStruct = reflect.TypeOf((*struct{})(nil)).Elem() 22 tyEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem() 23 emtpyStruct struct{} 24 ) 25 26 type Int int 27 28 func (i Int) String() string { 29 return fmt.Sprintf("(%v)", int(i)) 30 } 31 32 func (i *Int) Set(v int) { 33 *(*int)(i) = v 34 } 35 36 func (i Int) Append(v ...int) int { 37 sum := int(i) 38 for _, n := range v { 39 sum += n 40 } 41 return sum 42 } 43 44 func TestIntMethodOf(t *testing.T) { 45 // Int type 46 var i Int 47 i.Set(100) 48 if v := fmt.Sprint(i); v != "(100)" { 49 t.Fatalf("String(): have %v, want (100)", v) 50 } 51 if v := i.Append(200, 300, 400); v != 1000 { 52 t.Fatalf("Append(): have %v, want (1000)", v) 53 } 54 // make Int type 55 styp := reflectx.NamedTypeOf("main", "Int", tyInt) 56 typ := reflectx.NewMethodSet(styp, 2, 3) 57 mString := reflectx.MakeMethod( 58 "String", 59 "main", 60 false, 61 reflect.FuncOf(nil, []reflect.Type{tyString}, false), 62 func(args []reflect.Value) []reflect.Value { 63 v := args[0] 64 info := fmt.Sprintf("(%d)", v.Int()) 65 return []reflect.Value{reflect.ValueOf(info)} 66 }, 67 ) 68 mSet := reflectx.MakeMethod( 69 "Set", 70 "main", 71 true, 72 reflect.FuncOf([]reflect.Type{tyInt}, nil, false), 73 func(args []reflect.Value) (result []reflect.Value) { 74 v := args[0].Elem() 75 v.SetInt(args[1].Int()) 76 return 77 }, 78 ) 79 mAppend := reflectx.MakeMethod( 80 "Append", 81 "main", 82 false, 83 reflect.FuncOf([]reflect.Type{reflect.SliceOf(tyInt)}, []reflect.Type{tyInt}, true), 84 func(args []reflect.Value) (result []reflect.Value) { 85 var sum int64 = args[0].Int() 86 for i := 0; i < args[1].Len(); i++ { 87 sum += args[1].Index(i).Int() 88 } 89 return []reflect.Value{reflect.ValueOf(int(sum))} 90 }, 91 ) 92 reflectx.SetMethodSet(typ, []reflectx.Method{ 93 mString, 94 mSet, 95 mAppend, 96 }, true) 97 ptrType := reflect.PtrTo(typ) 98 99 if n := typ.NumMethod(); n != 2 { 100 t.Fatal("typ.NumMethod()", n) 101 } 102 if n := ptrType.NumMethod(); n != 3 { 103 t.Fatal("ptrTyp.NumMethod()", n) 104 } 105 106 x := reflect.New(typ).Elem() 107 x.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100)}) 108 109 // String 110 if v := fmt.Sprint(x); v != "(100)" { 111 t.Fatalf("String(): have %v, want (100)", v) 112 } 113 if v := fmt.Sprint(x.Addr()); v != "(100)" { 114 t.Fatalf("ptrTyp String(): have %v, want (100)", v) 115 } 116 117 // Append 118 m, _ := reflectx.MethodByName(typ, "Append") 119 r := m.Func.Call([]reflect.Value{x, reflect.ValueOf(200), reflect.ValueOf(300), reflect.ValueOf(400)}) 120 if v := r[0].Int(); v != 1000 { 121 t.Fatalf("typ reflectx.MethodByName Append: have %v, want 1000", v) 122 } 123 r = x.MethodByName("Append").Call([]reflect.Value{reflect.ValueOf(200), reflect.ValueOf(300), reflect.ValueOf(400)}) 124 if v := r[0].Int(); v != 1000 { 125 t.Fatalf("typ value.MethodByName Append: have %v, want 1000", v) 126 } 127 } 128 129 type IntSlice []int 130 131 func (i IntSlice) String() string { 132 return fmt.Sprintf("{%v}%v", len(i), ([]int)(i)) 133 } 134 135 func (i *IntSlice) Set(v ...int) { 136 *i = v 137 } 138 139 func (i IntSlice) Append(v ...int) int { 140 var sum int 141 for _, n := range i { 142 sum += n 143 } 144 for _, n := range v { 145 sum += n 146 } 147 return sum 148 } 149 150 func TestSliceMethodOf(t *testing.T) { 151 // IntSlice type 152 var i IntSlice 153 i.Set(100, 200, 300) 154 if v := i.String(); v != "{3}[100 200 300]" { 155 t.Fatalf("have %v, want {3}[100 200 300]", v) 156 } 157 if v := i.Append(200, 300, 400); v != 1500 { 158 t.Fatalf("have %v, want 1500", v) 159 } 160 // make IntSlice type 161 intSliceTyp := reflect.TypeOf([]int{}) 162 styp := reflectx.NamedTypeOf("main", "IntSlice", intSliceTyp) 163 typ := reflectx.NewMethodSet(styp, 2, 3) 164 mString := reflectx.MakeMethod( 165 "String", 166 "main", 167 false, 168 reflect.FuncOf(nil, []reflect.Type{tyString}, false), 169 func(args []reflect.Value) []reflect.Value { 170 v := args[0] 171 info := fmt.Sprintf("{%v}%v", v.Len(), v.Convert(intSliceTyp)) 172 return []reflect.Value{reflect.ValueOf(info)} 173 }, 174 ) 175 mSet := reflectx.MakeMethod( 176 "Set", 177 "main", 178 true, 179 reflect.FuncOf([]reflect.Type{intSliceTyp}, nil, true), 180 func(args []reflect.Value) (result []reflect.Value) { 181 v := args[0].Elem() 182 v.Set(args[1]) 183 return 184 }, 185 ) 186 mAppend := reflectx.MakeMethod( 187 "Append", 188 "main", 189 false, 190 reflect.FuncOf([]reflect.Type{reflect.SliceOf(tyInt)}, []reflect.Type{tyInt}, true), 191 func(args []reflect.Value) (result []reflect.Value) { 192 var sum int64 193 for i := 0; i < args[0].Len(); i++ { 194 sum += args[0].Index(i).Int() 195 } 196 for i := 0; i < args[1].Len(); i++ { 197 sum += args[1].Index(i).Int() 198 } 199 return []reflect.Value{reflect.ValueOf(int(sum))} 200 }, 201 ) 202 reflectx.SetMethodSet(typ, []reflectx.Method{ 203 mString, 204 mSet, 205 mAppend, 206 }, true) 207 ptrType := reflect.PtrTo(typ) 208 209 if n := typ.NumMethod(); n != 2 { 210 t.Fatal("typ.NumMethod()", n) 211 } 212 if n := ptrType.NumMethod(); n != 3 { 213 t.Fatal("ptrTyp.NumMethod()", n) 214 } 215 216 x := reflect.New(typ).Elem() 217 x.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200), reflect.ValueOf(300)}) 218 219 // String 220 if v := fmt.Sprint(x); v != "{3}[100 200 300]" { 221 t.Fatalf("String(): have %v, want {3}[100 200 300]", v) 222 } 223 if v := fmt.Sprint(x.Addr()); v != "{3}[100 200 300]" { 224 t.Fatalf("ptrTyp String(): have %v, want {3}[100 200 300]", v) 225 } 226 227 // Append 228 m, _ := reflectx.MethodByName(typ, "Append") 229 r := m.Func.Call([]reflect.Value{x, reflect.ValueOf(200), reflect.ValueOf(300), reflect.ValueOf(400)}) 230 if v := r[0].Int(); v != 1500 { 231 t.Fatalf("typ reflectx.MethodByName Append: have %v, want 1000", v) 232 } 233 r = x.MethodByName("Append").Call([]reflect.Value{reflect.ValueOf(200), reflect.ValueOf(300), reflect.ValueOf(400)}) 234 if v := r[0].Int(); v != 1500 { 235 t.Fatalf("typ value.MethodByName Append: have %v, want 1000", v) 236 } 237 } 238 239 type IntArray [2]int 240 241 func (i IntArray) String() string { 242 return fmt.Sprintf("(%v,%v)", i[0], i[1]) 243 } 244 245 func (i *IntArray) Set(x, y int) { 246 *(*int)(&i[0]), *(*int)(&i[1]) = x, y 247 } 248 249 func (i IntArray) Get() (int, int) { 250 return i[0], i[1] 251 } 252 253 func (i IntArray) Scale(v int) IntArray { 254 return IntArray{i[0] * v, i[1] * v} 255 } 256 257 func TestArrayMethodOf(t *testing.T) { 258 if runtime.Compiler == "gopherjs" { 259 t.Skip("skip gopherjs") 260 } 261 // IntArray 262 var i IntArray 263 i.Set(100, 200) 264 if v := fmt.Sprint(i); v != "(100,200)" { 265 t.Fatalf("have %v, want (100,200)", v) 266 } 267 if v1, v2 := i.Get(); v1 != 100 || v2 != 200 { 268 t.Fatalf("have %v %v, want 100 200)", v1, v2) 269 } 270 if v := fmt.Sprint(i.Scale(5)); v != "(500,1000)" { 271 t.Fatalf("have %v, want (500,1000)", v) 272 } 273 styp := reflectx.NamedTypeOf("main", "IntArray", reflect.TypeOf([2]int{})) 274 // make IntArray 275 typ := reflectx.NewMethodSet(styp, 3, 4) 276 277 mString := reflectx.MakeMethod( 278 "String", 279 "main", 280 false, 281 reflect.FuncOf(nil, []reflect.Type{tyString}, false), 282 func(args []reflect.Value) []reflect.Value { 283 v := args[0] 284 info := fmt.Sprintf("(%v,%v)", v.Index(0), v.Index(1)) 285 return []reflect.Value{reflect.ValueOf(info)} 286 }, 287 ) 288 mSet := reflectx.MakeMethod( 289 "Set", 290 "main", 291 true, 292 reflect.FuncOf([]reflect.Type{tyInt, tyInt}, nil, false), 293 func(args []reflect.Value) (result []reflect.Value) { 294 v := args[0].Elem() 295 v.Index(0).Set(args[1]) 296 v.Index(1).Set(args[2]) 297 return 298 }, 299 ) 300 mGet := reflectx.MakeMethod( 301 "Get", 302 "main", 303 false, 304 reflect.FuncOf(nil, []reflect.Type{tyInt, tyInt}, false), 305 func(args []reflect.Value) (result []reflect.Value) { 306 v := args[0] 307 return []reflect.Value{v.Index(0), v.Index(1)} 308 }, 309 ) 310 mScale := reflectx.MakeMethod( 311 "Scale", 312 "main", 313 false, 314 reflect.FuncOf([]reflect.Type{tyInt}, []reflect.Type{typ}, false), 315 func(args []reflect.Value) (result []reflect.Value) { 316 v := args[0] 317 s := args[1].Int() 318 r := reflect.New(typ).Elem() 319 r.Index(0).SetInt(v.Index(0).Int() * s) 320 r.Index(1).SetInt(v.Index(1).Int() * s) 321 return []reflect.Value{r} 322 }, 323 ) 324 reflectx.SetMethodSet(typ, []reflectx.Method{ 325 mString, 326 mSet, 327 mGet, 328 mScale, 329 }, true) 330 ptrType := reflect.PtrTo(typ) 331 332 if n := typ.NumMethod(); n != 3 { 333 t.Fatal("typ.NumMethod()", n) 334 } 335 if n := ptrType.NumMethod(); n != 4 { 336 t.Fatal("ptrTyp.NumMethod()", n) 337 } 338 339 x := reflect.New(typ).Elem() 340 x.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 341 342 // String 343 if v := fmt.Sprint(x); v != "(100,200)" { 344 t.Fatalf("String(): have %v, want (100,200)", v) 345 } 346 if v := fmt.Sprint(x.Addr()); v != "(100,200)" { 347 t.Fatalf("ptrTyp String(): have %v, want (100,200)", v) 348 } 349 350 // Get 351 m, _ := reflectx.MethodByName(typ, "Get") 352 r := m.Func.Call([]reflect.Value{x}) 353 if len(r) != 2 || r[0].Int() != 100 || r[1].Int() != 200 { 354 t.Fatalf("typ reflectx.MethodByName Get: have %v, want 100 200", r) 355 } 356 r = x.MethodByName("Get").Call(nil) 357 if len(r) != 2 || r[0].Int() != 100 || r[1].Int() != 200 { 358 t.Fatalf("typ value.MethodByName Get: have %v, want 100 200", r) 359 } 360 361 // Scale 362 m, _ = reflectx.MethodByName(typ, "Scale") 363 r = m.Func.Call([]reflect.Value{x, reflect.ValueOf(5)}) 364 if v := fmt.Sprint(r[0]); v != "(500,1000)" { 365 t.Fatalf("typ reflectx.MethodByName Scale: have %v, want (500,1000)", v) 366 } 367 r = x.MethodByName("Scale").Call([]reflect.Value{reflect.ValueOf(5)}) 368 if v := fmt.Sprint((r[0])); v != "(500,1000)" { 369 t.Fatalf("typ value.MethodByName Scale: have %v, want (500,1000)", v) 370 } 371 } 372 373 type Point struct { 374 X int 375 Y int 376 } 377 378 func (i Point) String() string { 379 return fmt.Sprintf("(%v,%v)", i.X, i.Y) 380 } 381 382 func (i Point) Add(v Point) Point { 383 return Point{i.X + v.X, i.Y + v.Y} 384 } 385 386 func (i *Point) Set(x, y int) { 387 i.X, i.Y = x, y 388 } 389 390 func (i Point) Scale(v ...int) (ar []Point) { 391 for _, n := range v { 392 ar = append(ar, Point{i.X * n, i.Y * n}) 393 } 394 return 395 } 396 397 func (i Point) New() *Point { 398 return &Point{i.X, i.Y} 399 } 400 401 func makeDynamicPointType() reflect.Type { 402 fs := []reflect.StructField{ 403 reflect.StructField{Name: "X", Type: reflect.TypeOf(0)}, 404 reflect.StructField{Name: "Y", Type: reflect.TypeOf(0)}, 405 } 406 styp := reflectx.NamedStructOf("main", "Point", fs) 407 //var typ reflect.Type 408 typ := reflectx.NewMethodSet(styp, 4, 5) 409 mString := reflectx.MakeMethod( 410 "String", 411 "main", 412 false, 413 reflect.FuncOf(nil, []reflect.Type{tyString}, false), 414 func(args []reflect.Value) []reflect.Value { 415 v := args[0] 416 info := fmt.Sprintf("(%v,%v)", v.Field(0), v.Field(1)) 417 return []reflect.Value{reflect.ValueOf(info)} 418 }, 419 ) 420 mAdd := reflectx.MakeMethod( 421 "Add", 422 "main", 423 false, 424 reflect.FuncOf([]reflect.Type{typ}, []reflect.Type{typ}, false), 425 func(args []reflect.Value) []reflect.Value { 426 v := reflect.New(typ).Elem() 427 v.Field(0).SetInt(args[0].Field(0).Int() + args[1].Field(0).Int()) 428 v.Field(1).SetInt(args[0].Field(1).Int() + args[1].Field(1).Int()) 429 return []reflect.Value{v} 430 }, 431 ) 432 mSet := reflectx.MakeMethod( 433 "Set", 434 "main", 435 true, 436 reflect.FuncOf([]reflect.Type{tyInt, tyInt}, nil, false), 437 func(args []reflect.Value) (result []reflect.Value) { 438 v := args[0].Elem() 439 v.Field(0).Set(args[1]) 440 v.Field(1).Set(args[2]) 441 return 442 }, 443 ) 444 mScale := reflectx.MakeMethod( 445 "Scale", 446 "main", 447 false, 448 reflect.FuncOf([]reflect.Type{reflect.SliceOf(tyInt)}, []reflect.Type{reflect.SliceOf(typ)}, true), 449 func(args []reflect.Value) (result []reflect.Value) { 450 x, y := args[0].Field(0).Int(), args[0].Field(1).Int() 451 r := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0) 452 for i := 0; i < args[1].Len(); i++ { 453 s := args[1].Index(i).Int() 454 v := reflect.New(typ).Elem() 455 v.Field(0).SetInt(x * s) 456 v.Field(1).SetInt(y * s) 457 r = reflect.Append(r, v) 458 } 459 return []reflect.Value{r} 460 }, 461 ) 462 mNew := reflectx.MakeMethod( 463 "New", 464 "main", 465 false, 466 reflect.FuncOf(nil, []reflect.Type{reflect.PtrTo(typ)}, false), 467 func(args []reflect.Value) (result []reflect.Value) { 468 v := reflect.New(typ).Elem() 469 v.Field(0).SetInt(args[0].Field(0).Int()) 470 v.Field(1).SetInt(args[0].Field(1).Int()) 471 return []reflect.Value{v.Addr()} 472 }, 473 ) 474 reflectx.SetMethodSet(typ, []reflectx.Method{ 475 mAdd, 476 mString, 477 mSet, 478 mScale, 479 mNew, 480 }, true) 481 return typ 482 } 483 484 func TestStructMethodOf(t *testing.T) { 485 // Point 486 var i Point 487 i.Set(100, 200) 488 if v := fmt.Sprint(i); v != "(100,200)" { 489 t.Fatalf("have %v, want (100,200)", v) 490 } 491 if v := fmt.Sprint(i.Add(Point{1, 2})); v != "(101,202)" { 492 t.Fatalf("have %v, want (101,202)", v) 493 } 494 if v := fmt.Sprint(i.Scale(2, 3, 4)); v != "[(200,400) (300,600) (400,800)]" { 495 t.Fatalf("have %v, want [(200,400) (300,600) (400,800)]", v) 496 } 497 if v := fmt.Sprint(i.New()); v != "(100,200)" { 498 t.Fatalf("have %v, want (100,200)", v) 499 } 500 // make Point 501 typ := makeDynamicPointType() 502 ptrType := reflect.PtrTo(typ) 503 504 if n := typ.NumMethod(); n != 4 { 505 t.Fatal("typ.NumMethod()", n) 506 } 507 if n := ptrType.NumMethod(); n != 5 { 508 t.Fatal("ptrTyp.NumMethod()", n) 509 } 510 511 pt1 := reflect.New(typ).Elem() 512 pt1.Field(0).SetInt(100) 513 pt1.Field(1).SetInt(200) 514 515 pt2 := reflect.New(typ).Elem() 516 pt2.Field(0).SetInt(300) 517 pt2.Field(1).SetInt(400) 518 519 // String 520 if v := fmt.Sprint(pt1); v != "(100,200)" { 521 t.Fatalf("String(): have %v, want (100,200)", v) 522 } 523 if v := fmt.Sprint(pt1.Addr()); v != "(100,200)" { 524 t.Fatalf("ptrTyp String(): have %v, want (100,200)", v) 525 } 526 527 // typ Add 528 m, _ := reflectx.MethodByName(typ, "Add") 529 r := m.Func.Call([]reflect.Value{pt1, pt2}) 530 if v := fmt.Sprint(r[0]); v != "(400,600)" { 531 t.Fatalf("type reflectx.MethodByName Add: have %v, want (400,600)", v) 532 } 533 r = pt1.MethodByName("Add").Call([]reflect.Value{pt2}) 534 if v := fmt.Sprint(r[0]); v != "(400,600)" { 535 t.Fatalf("value.MethodByName Add: have %v, want (400,600)", v) 536 } 537 538 // ptrtyp Add 539 m, _ = reflectx.MethodByName(ptrType, "Add") 540 r = m.Func.Call([]reflect.Value{pt1.Addr(), pt2}) 541 if v := fmt.Sprint(r[0]); v != "(400,600)" { 542 t.Fatalf("ptrType reflectx.MethodByName Add: have %v, want (400,600)", v) 543 } 544 r = pt1.Addr().MethodByName("Add").Call([]reflect.Value{pt2}) 545 if v := fmt.Sprint(r[0]); v != "(400,600)" { 546 t.Fatalf("ptrType value.reflectx.MethodByName Add: have %v, want (400,600)", v) 547 } 548 549 // Set 550 m, _ = reflectx.MethodByName(ptrType, "Set") 551 m.Func.Call([]reflect.Value{pt1.Addr(), reflect.ValueOf(-100), reflect.ValueOf(-200)}) 552 if v := fmt.Sprint(pt1); v != "(-100,-200)" { 553 t.Fatalf("ptrType reflectx.MethodByName Set: have %v, want (-100,-200)", v) 554 } 555 pt1.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 556 if v := fmt.Sprint(pt1); v != "(100,200)" { 557 t.Fatalf("ptrType reflectx.MethodByName Set: have %v, want (100,200)", v) 558 } 559 560 // Scale 561 m, _ = reflectx.MethodByName(typ, "Scale") 562 r = m.Func.Call([]reflect.Value{pt1, reflect.ValueOf(2), reflect.ValueOf(3), reflect.ValueOf(4)}) 563 if v := fmt.Sprint(v2is(r[0])); v != "[(200,400) (300,600) (400,800)]" { 564 t.Fatalf("have %v, want [(200,400) (300,600) (400,800)]", v) 565 } 566 r = pt1.MethodByName("Scale").Call([]reflect.Value{reflect.ValueOf(2), reflect.ValueOf(3), reflect.ValueOf(4)}) 567 if v := fmt.Sprint(v2is(r[0])); v != "[(200,400) (300,600) (400,800)]" { 568 t.Fatalf("have %v, want [(200,400) (300,600) (400,800)]", v) 569 } 570 571 // New 572 m, _ = reflectx.MethodByName(typ, "New") 573 r = m.Func.Call([]reflect.Value{pt1}) 574 if v := fmt.Sprint(r[0]); v != "(100,200)" { 575 t.Fatalf("have %v, want (100,200)", v) 576 } 577 r = pt1.MethodByName("New").Call(nil) 578 if v := fmt.Sprint(r[0]); v != "(100,200)" { 579 t.Fatalf("have %v, want (100,200)", v) 580 } 581 } 582 583 func v2is(v reflect.Value) (is []interface{}) { 584 for i := 0; i < v.Len(); i++ { 585 is = append(is, v.Index(i).Interface()) 586 } 587 return is 588 } 589 590 type testMethodStack struct { 591 name string 592 pkgpath string 593 mtyp reflect.Type 594 fun func([]reflect.Value) []reflect.Value 595 args []reflect.Value 596 result []reflect.Value 597 pointer bool 598 } 599 600 var ( 601 testMethodStacks = []testMethodStack{ 602 testMethodStack{ 603 "Empty", 604 "main", 605 reflect.FuncOf(nil, nil, false), 606 func(args []reflect.Value) []reflect.Value { 607 if len(args) != 1 { 608 panic(fmt.Errorf("args have %v, want nil", args[1:])) 609 } 610 return nil 611 }, 612 nil, 613 nil, 614 false, 615 }, 616 testMethodStack{ 617 "Empty Struct", 618 "main", 619 reflect.FuncOf([]reflect.Type{tyEmptyStruct}, []reflect.Type{tyEmptyStruct}, false), 620 func(args []reflect.Value) []reflect.Value { 621 return []reflect.Value{args[1]} 622 }, 623 []reflect.Value{reflect.ValueOf(emtpyStruct)}, 624 []reflect.Value{reflect.ValueOf(emtpyStruct)}, 625 false, 626 }, 627 testMethodStack{ 628 "Empty Struct2", 629 "main", 630 reflect.FuncOf([]reflect.Type{tyEmptyStruct, tyInt, tyEmptyStruct}, []reflect.Type{tyEmptyStruct, tyInt, tyEmptyStruct}, false), 631 func(args []reflect.Value) []reflect.Value { 632 return []reflect.Value{args[1], args[2], args[3]} 633 }, 634 []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(100), reflect.ValueOf(emtpyStruct)}, 635 []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(100), reflect.ValueOf(emtpyStruct)}, 636 false, 637 }, 638 testMethodStack{ 639 "Empty Struct3", 640 "main", 641 reflect.FuncOf([]reflect.Type{tyEmptyStruct, tyEmptyStruct, tyInt, tyEmptyStruct}, []reflect.Type{tyInt}, false), 642 func(args []reflect.Value) []reflect.Value { 643 return []reflect.Value{args[3]} 644 }, 645 []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(100), reflect.ValueOf(emtpyStruct)}, 646 []reflect.Value{reflect.ValueOf(100)}, 647 false, 648 }, 649 testMethodStack{ 650 "Empty Struct4", 651 "main", 652 reflect.FuncOf([]reflect.Type{tyEmptyStruct, tyEmptyStruct, tyInt, tyEmptyStruct}, []reflect.Type{tyEmptyStruct, tyEmptyStruct, tyEmptyStruct, tyBool}, false), 653 func(args []reflect.Value) []reflect.Value { 654 return []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(true)} 655 }, 656 []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(100), reflect.ValueOf(emtpyStruct)}, 657 []reflect.Value{reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(emtpyStruct), reflect.ValueOf(true)}, 658 false, 659 }, 660 testMethodStack{ 661 "Bool_Nil", 662 "main", 663 reflect.FuncOf([]reflect.Type{tyBool}, nil, false), 664 func(args []reflect.Value) []reflect.Value { 665 return nil 666 }, 667 []reflect.Value{reflect.ValueOf(true)}, 668 nil, 669 false, 670 }, 671 testMethodStack{ 672 "Bool_Bool", 673 "main", 674 reflect.FuncOf([]reflect.Type{tyBool}, []reflect.Type{tyBool}, false), 675 func(args []reflect.Value) []reflect.Value { 676 return []reflect.Value{args[1]} 677 }, 678 []reflect.Value{reflect.ValueOf(true)}, 679 []reflect.Value{reflect.ValueOf(true)}, 680 false, 681 }, 682 testMethodStack{ 683 "Int_Int", 684 "main", 685 reflect.FuncOf([]reflect.Type{tyInt}, []reflect.Type{tyInt}, false), 686 func(args []reflect.Value) []reflect.Value { 687 v := 300 + args[1].Int() 688 return []reflect.Value{reflect.ValueOf(int(v))} 689 }, 690 []reflect.Value{reflect.ValueOf(-200)}, 691 []reflect.Value{reflect.ValueOf(100)}, 692 false, 693 }, 694 testMethodStack{ 695 "Big Bytes_ByteInt", 696 "main", 697 reflect.FuncOf([]reflect.Type{reflect.TypeOf([4096]byte{})}, []reflect.Type{tyByte, tyInt, tyByte}, false), 698 func(args []reflect.Value) []reflect.Value { 699 return []reflect.Value{args[1].Index(1), reflect.ValueOf(args[1].Len()), args[1].Index(3)} 700 }, 701 []reflect.Value{reflect.ValueOf([4096]byte{'a', 'b', 'c', 'd', 'e'})}, 702 []reflect.Value{reflect.ValueOf('b'), reflect.ValueOf(4096), reflect.ValueOf('d')}, 703 true, 704 }, 705 } 706 ) 707 708 func TestMethodStack(t *testing.T) { 709 // make Point 710 fs := []reflect.StructField{ 711 reflect.StructField{Name: "X", Type: reflect.TypeOf(0)}, 712 reflect.StructField{Name: "Y", Type: reflect.TypeOf(0)}, 713 } 714 styp := reflectx.NamedStructOf("main", "Point", fs) 715 typ := reflectx.NewMethodSet(styp, len(testMethodStacks), len(testMethodStacks)) 716 var methods []reflectx.Method 717 for _, m := range testMethodStacks { 718 mm := reflectx.MakeMethod( 719 m.name, 720 m.pkgpath, 721 m.pointer, 722 m.mtyp, 723 m.fun, 724 ) 725 methods = append(methods, mm) 726 } 727 reflectx.SetMethodSet(typ, methods, true) 728 v := reflect.New(typ).Elem() 729 v.Field(0).SetInt(100) 730 v.Field(1).SetInt(200) 731 for _, m := range testMethodStacks { 732 var r []reflect.Value 733 if m.pointer { 734 r = v.Addr().MethodByName(m.name).Call(m.args) 735 } else { 736 r = v.MethodByName(m.name).Call(m.args) 737 } 738 if len(r) != len(m.result) { 739 t.Fatalf("failed %v %v, have %v want %v", m.name, m.mtyp, r, m.result) 740 } 741 for i := 0; i < len(r); i++ { 742 if fmt.Sprint(r[i]) != fmt.Sprint(m.result[i]) { 743 t.Fatalf("failed %v, have %v want %v", m.name, r[i], m.result[i]) 744 } 745 } 746 } 747 } 748 749 func checkInterface(t *testing.T, typ, styp reflect.Type) { 750 if typ.NumMethod() != styp.NumMethod() { 751 t.Errorf("num method: have %v, want %v", typ.NumMethod(), styp.NumMethod()) 752 } 753 for i := 0; i < typ.NumMethod(); i++ { 754 if typ.Method(i) != styp.Method(i) { 755 t.Errorf("method: have %v, want %v", typ.Method(i), styp.Method(i)) 756 } 757 } 758 if !typ.ConvertibleTo(styp) { 759 t.Errorf("%v cannot ConvertibleTo %v", typ, styp) 760 } 761 if !styp.ConvertibleTo(typ) { 762 t.Errorf("%v cannot ConvertibleTo %v", styp, typ) 763 } 764 } 765 766 func TestInterfaceOf(t *testing.T) { 767 ms := []reflect.Method{ 768 reflect.Method{ 769 Name: "String", 770 Type: reflect.FuncOf(nil, []reflect.Type{tyString}, false), 771 }, 772 reflect.Method{ 773 Name: "Test", 774 Type: reflect.FuncOf(nil, []reflect.Type{tyBool}, false), 775 }, 776 } 777 typ1 := reflectx.InterfaceOf(nil, ms) 778 typ2 := reflectx.InterfaceOf(nil, ms) 779 if typ1 != typ2 { 780 t.Fatalf("different type: %v %v", typ1, typ2) 781 } 782 } 783 784 func TestNamedInterfaceOf(t *testing.T) { 785 pkgpath := "github.com/goplus/reflectx" 786 typ := reflectx.NamedInterfaceOf(pkgpath, "Stringer", nil, 787 []reflect.Method{ 788 reflect.Method{ 789 Name: "String", 790 Type: reflect.FuncOf(nil, []reflect.Type{tyString}, false), 791 }, 792 }, 793 ) 794 checkInterface(t, typ, reflect.TypeOf((*fmt.Stringer)(nil)).Elem()) 795 796 typ = reflectx.NamedInterfaceOf(pkgpath, "ReadWriteCloser", 797 []reflect.Type{ 798 reflect.TypeOf((*io.Reader)(nil)).Elem(), 799 reflect.TypeOf((*io.Writer)(nil)).Elem(), 800 }, 801 []reflect.Method{ 802 reflect.Method{ 803 Name: "Close", 804 Type: reflect.FuncOf(nil, []reflect.Type{tyError}, false), 805 }, 806 }, 807 ) 808 checkInterface(t, typ, reflect.TypeOf((*io.ReadWriteCloser)(nil)).Elem()) 809 } 810 811 func TestNamedInterfaceOf2(t *testing.T) { 812 pkgpath := "github.com/goplus/reflectx" 813 typ := reflectx.NewInterfaceType(pkgpath, "Stringer") 814 reflectx.SetInterfaceType(typ, nil, 815 []reflect.Method{ 816 reflect.Method{ 817 Name: "String", 818 Type: reflect.FuncOf(nil, []reflect.Type{tyString}, false), 819 }, 820 }, 821 ) 822 checkInterface(t, typ, reflect.TypeOf((*fmt.Stringer)(nil)).Elem()) 823 824 typ = reflectx.NewInterfaceType(pkgpath, "ReadWriteCloser") 825 reflectx.SetInterfaceType(typ, 826 []reflect.Type{ 827 reflect.TypeOf((*io.Reader)(nil)).Elem(), 828 reflect.TypeOf((*io.Writer)(nil)).Elem(), 829 }, 830 []reflect.Method{ 831 reflect.Method{ 832 Name: "Close", 833 Type: reflect.FuncOf(nil, []reflect.Type{tyError}, false), 834 }, 835 }, 836 ) 837 checkInterface(t, typ, reflect.TypeOf((*io.ReadWriteCloser)(nil)).Elem()) 838 } 839 840 type MyPoint1 struct { 841 Point 842 } 843 844 type MyPoint2 struct { 845 *Point 846 } 847 848 type Setter interface { 849 Set(x int, y int) 850 String() string 851 } 852 853 type MyPoint3 struct { 854 Setter 855 } 856 857 type MyPoint4 struct { 858 *Point 859 index int 860 } 861 862 func (s *MyPoint4) SetIndex(n int) { 863 s.index = n 864 } 865 866 func (s MyPoint4) Index() int { 867 return s.index 868 } 869 870 func (s MyPoint4) String() string { 871 return fmt.Sprintf("%v#%v", s.index, s.Point) 872 } 873 874 func makeDynamicSetterType() reflect.Type { 875 return reflectx.NamedInterfaceOf("main", "Setter", nil, 876 []reflect.Method{ 877 reflect.Method{ 878 Name: "Set", 879 Type: reflect.FuncOf([]reflect.Type{tyInt, tyInt}, nil, false), 880 }, 881 reflect.Method{ 882 Name: "String", 883 Type: reflect.FuncOf(nil, []reflect.Type{tyString}, false), 884 }, 885 }, 886 ) 887 } 888 889 func TestEmbedMethods1(t *testing.T) { 890 // MyPoint1 891 typ := reflect.TypeOf((*MyPoint1)(nil)).Elem() 892 if v := typ.NumMethod(); v != 4 { 893 t.Fatalf("NumMethod have %v want 4", v) 894 } 895 if v := reflect.PtrTo(typ).NumMethod(); v != 5 { 896 t.Fatalf("NumMethod have %v want 5", v) 897 } 898 fnTest := func(t *testing.T, tyPoint reflect.Type) { 899 fs := []reflect.StructField{ 900 reflect.StructField{ 901 Name: "Point", 902 Type: tyPoint, 903 Anonymous: true, 904 }, 905 } 906 typ := reflectx.NamedStructOf("main", "MyPoint1", fs) 907 typ = reflectx.StructToMethodSet(typ) 908 if v := typ.NumMethod(); v != 4 { 909 t.Errorf("NumMethod have %v want 4", v) 910 } 911 if v := reflect.PtrTo(typ).NumMethod(); v != 5 { 912 t.Errorf("NumMethod have %v want 5", v) 913 } 914 m := reflect.New(typ).Elem() 915 m.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 916 if v := fmt.Sprint(m); v != "(100,200)" { 917 t.Errorf("have %v want (100,200)", v) 918 } 919 if v := fmt.Sprint(m.Addr()); v != "(100,200)" { 920 t.Errorf("have %v want (100,200)", v) 921 } 922 m.Field(0).Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(-100), reflect.ValueOf(-200)}) 923 if v := fmt.Sprint(m.Field(0)); v != "(-100,-200)" { 924 t.Errorf("have %v want (-100,-200)", v) 925 } 926 if v := fmt.Sprint(m.Field(0).Addr()); v != "(-100,-200)" { 927 t.Errorf("have %v want (-100,-200)", v) 928 } 929 } 930 931 // test mixed embed struct 932 fnTest(t, reflect.TypeOf((*Point)(nil)).Elem()) 933 // test dynamic embed struct 934 fnTest(t, makeDynamicPointType()) 935 } 936 937 func TestEmbedMethods2(t *testing.T) { 938 // MyPoint2 939 typ := reflect.TypeOf((*MyPoint2)(nil)).Elem() 940 if v := typ.NumMethod(); v != 5 { 941 t.Fatalf("NumMethod have %v want 5", v) 942 } 943 if v := reflect.PtrTo(typ).NumMethod(); v != 5 { 944 t.Fatalf("NumMethod have %v want 5", v) 945 } 946 947 // embbed ptr 948 fnTest := func(t *testing.T, tyPoint reflect.Type) { 949 fs := []reflect.StructField{ 950 reflect.StructField{ 951 Name: "Point", 952 Type: reflect.PtrTo(tyPoint), 953 Anonymous: true, 954 }, 955 } 956 typ = reflectx.NamedStructOf("main", "MyPoint2", fs) 957 typ = reflectx.StructToMethodSet(typ) 958 if v := typ.NumMethod(); v != 5 { 959 t.Errorf("NumMethod have %v want 5", v) 960 } 961 if v := reflect.PtrTo(typ).NumMethod(); v != 5 { 962 t.Errorf("NumMethod have %v want 5", v) 963 } 964 m := reflect.New(typ).Elem() 965 m.Field(0).Set(reflect.New(tyPoint)) 966 m.MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 967 if v := fmt.Sprint((m)); v != "(100,200)" { 968 t.Errorf("have %v want (100,200)", v) 969 } 970 if v := fmt.Sprint(m.Addr()); v != "(100,200)" { 971 t.Errorf("have %v want (100,200)", v) 972 } 973 m.Field(0).MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(-100), reflect.ValueOf(-200)}) 974 if v := fmt.Sprint(m); v != "(-100,-200)" { 975 t.Errorf("have %v want (-100,-200)", v) 976 } 977 if v := fmt.Sprint(m.Field(0)); v != "(-100,-200)" { 978 t.Errorf("have %v want (-100,-200)", v) 979 } 980 if v := fmt.Sprint(m.Field(0).Elem()); v != "(-100,-200)" { 981 t.Errorf("have %v want (-100,-200)", v) 982 } 983 m.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(300), reflect.ValueOf(400)}) 984 if v := fmt.Sprint(m); v != "(300,400)" { 985 t.Errorf("have %v want (300,400)", v) 986 } 987 if v := fmt.Sprint((m.Addr())); v != "(300,400)" { 988 t.Errorf("have %v want (300,400)", v) 989 } 990 } 991 // test mixed embed ptr 992 fnTest(t, reflect.TypeOf((*Point)(nil)).Elem()) 993 // test dynamic embed ptr 994 fnTest(t, makeDynamicPointType()) 995 } 996 997 func TestEmbedMethods3(t *testing.T) { 998 // MyPoint3 999 typ := reflect.TypeOf((*MyPoint3)(nil)).Elem() 1000 if v := typ.NumMethod(); v != 2 { 1001 t.Fatalf("NumMethod have %v want 2", v) 1002 } 1003 if v := reflect.PtrTo(typ).NumMethod(); v != 2 { 1004 t.Fatalf("NumMethod have %v want 2", v) 1005 } 1006 var i MyPoint3 1007 i.Setter = &Point{} 1008 i.Set(100, 200) 1009 if v := fmt.Sprint(i); v != "(100,200)" { 1010 t.Fatalf("String have %v, want (100,200)", v) 1011 } 1012 (&i).Set(300, 400) 1013 if v := fmt.Sprint(i); v != "(300,400)" { 1014 t.Fatalf("String have %v, want (300,400)", v) 1015 } 1016 1017 // embbed interface 1018 fnTest := func(t *testing.T, setter reflect.Type, tyPoint reflect.Type) { 1019 fs := []reflect.StructField{ 1020 reflect.StructField{ 1021 Name: "Setter", 1022 Type: setter, 1023 Anonymous: true, 1024 }, 1025 } 1026 typ := reflectx.NamedStructOf("main", "MyPoint3", fs) 1027 typ = reflectx.StructToMethodSet(typ) 1028 if v := typ.NumMethod(); v != 2 { 1029 t.Errorf("NumMethod have %v want 2", v) 1030 } 1031 if v := reflect.PtrTo(typ).NumMethod(); v != 2 { 1032 t.Errorf("NumMethod have %v want 2", v) 1033 } 1034 m := reflect.New(typ).Elem() 1035 m.Field(0).Set(reflect.New(tyPoint)) 1036 m.MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 1037 if v := fmt.Sprint((m)); v != "(100,200)" { 1038 t.Errorf("have %v want (100,200)", v) 1039 } 1040 m.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(300), reflect.ValueOf(400)}) 1041 if v := fmt.Sprint((m)); v != "(300,400)" { 1042 t.Errorf("have %v want (300,400)", v) 1043 } 1044 } 1045 // test mixed embed interface 1046 fnTest(t, reflect.TypeOf((*Setter)(nil)).Elem(), reflect.TypeOf((*Point)(nil)).Elem()) 1047 fnTest(t, reflect.TypeOf((*Setter)(nil)).Elem(), makeDynamicPointType()) 1048 // test dynamic embed interface 1049 fnTest(t, makeDynamicSetterType(), reflect.TypeOf((*Point)(nil)).Elem()) 1050 fnTest(t, makeDynamicSetterType(), makeDynamicPointType()) 1051 } 1052 1053 func TestEmbedMethods4(t *testing.T) { 1054 // MyPoint4 1055 typ := reflect.TypeOf((*MyPoint4)(nil)).Elem() 1056 if v := typ.NumMethod(); v != 6 { 1057 t.Fatalf("NumMethod have %v want 6", v) 1058 } 1059 if v := reflect.PtrTo(typ).NumMethod(); v != 7 { 1060 t.Fatalf("NumMethod have %v want 7", v) 1061 } 1062 var i MyPoint4 1063 i.Point = &Point{} 1064 i.Set(100, 200) 1065 if v := fmt.Sprint(i); v != "0#(100,200)" { 1066 t.Fatalf("String have %v, want 0#(100,200)", v) 1067 } 1068 i.SetIndex(1) 1069 i.Set(300, 400) 1070 if v := fmt.Sprint(i); v != "1#(300,400)" { 1071 t.Fatalf("String have %v, want 1#(300,400)", v) 1072 } 1073 1074 fnTest := func(t *testing.T, tyPoint reflect.Type) { 1075 // embbed ptr 1076 fs := []reflect.StructField{ 1077 reflect.StructField{ 1078 Name: "Point", 1079 Type: reflect.PtrTo(tyPoint), 1080 Anonymous: true, 1081 }, 1082 reflect.StructField{ 1083 Name: "index", 1084 PkgPath: "main", 1085 Type: reflect.TypeOf(int(0)), 1086 Anonymous: false, 1087 }, 1088 } 1089 mSetIndex := reflectx.MakeMethod( 1090 "SetIndex", 1091 "main", 1092 true, 1093 reflect.FuncOf([]reflect.Type{tyInt}, nil, false), 1094 func(args []reflect.Value) []reflect.Value { 1095 reflectx.Field(args[0].Elem(), 1).SetInt(args[1].Int()) 1096 return nil 1097 }, 1098 ) 1099 mIndex := reflectx.MakeMethod( 1100 "Index", 1101 "main", 1102 false, 1103 reflect.FuncOf(nil, []reflect.Type{tyInt}, false), 1104 func(args []reflect.Value) []reflect.Value { 1105 return []reflect.Value{args[0].Field(1)} 1106 }, 1107 ) 1108 mString := reflectx.MakeMethod( 1109 "String", 1110 "main", 1111 false, 1112 reflect.FuncOf(nil, []reflect.Type{tyString}, false), 1113 func(args []reflect.Value) []reflect.Value { 1114 info := fmt.Sprintf("%v#%v", args[0].Field(1), args[0].Field(0)) 1115 return []reflect.Value{reflect.ValueOf(info)} 1116 }, 1117 ) 1118 typ := reflectx.NamedStructOf("main", "MyPoint4", fs) 1119 typ = reflectx.NewMethodSet(typ, 2, 3) 1120 reflectx.SetMethodSet(typ, []reflectx.Method{ 1121 mSetIndex, 1122 mIndex, 1123 mString, 1124 }, true) 1125 if v := typ.NumMethod(); v != 6 { 1126 t.Errorf("NumMethod have %v want 6", v) 1127 } 1128 if v := reflect.PtrTo(typ).NumMethod(); v != 7 { 1129 t.Errorf("NumMethod have %v want 7", v) 1130 } 1131 m := reflect.New(typ).Elem() 1132 m.Field(0).Set(reflect.New(tyPoint)) 1133 m.MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf(200)}) 1134 if v := fmt.Sprint(m); v != "0#(100,200)" { 1135 t.Errorf("have %v want 0#(100,200)", v) 1136 } 1137 m.Addr().MethodByName("SetIndex").Call([]reflect.Value{reflect.ValueOf(1)}) 1138 m.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(300), reflect.ValueOf(400)}) 1139 if v := fmt.Sprint(m); v != "1#(300,400)" { 1140 t.Errorf("have %v want 1#(300,400)", v) 1141 } 1142 } 1143 1144 // test mixed embed ptr with methods 1145 fnTest(t, reflect.TypeOf((*Point)(nil)).Elem()) 1146 // test dynamic embed ptr with methods 1147 fnTest(t, makeDynamicPointType()) 1148 } 1149 1150 type itoaFunc func(i int) string 1151 1152 func (f itoaFunc) Itoa(i int) string { return f(i) } 1153 1154 type Itoa interface { 1155 Itoa(i int) string 1156 } 1157 1158 func TestFunc(t *testing.T) { 1159 if runtime.Compiler == "gopherjs" { 1160 t.Skip("skip gopherjs") 1161 } 1162 fn := itoaFunc(func(i int) string { 1163 return strconv.Itoa(i) 1164 }) 1165 if fn(100) != "100" { 1166 t.Fail() 1167 } 1168 if Itoa(fn).Itoa(100) != "100" { 1169 t.Fail() 1170 } 1171 fnTyp := reflect.TypeOf((*itoaFunc)(nil)).Elem() 1172 fnValue := reflect.MakeFunc(fnTyp, func(args []reflect.Value) []reflect.Value { 1173 r := strconv.Itoa(int(args[0].Int())) 1174 return []reflect.Value{reflect.ValueOf(r)} 1175 }) 1176 if i := fnValue.Interface().(Itoa); i.Itoa(100) != "100" { 1177 t.Fail() 1178 } 1179 styp := reflectx.NamedTypeOf("main", "itoaFunc", reflect.FuncOf([]reflect.Type{tyInt}, []reflect.Type{tyString}, false)) 1180 typ := reflectx.NewMethodSet(styp, 1, 1) 1181 mItoa := reflectx.MakeMethod("Itoa", "main", false, 1182 reflect.FuncOf([]reflect.Type{tyInt}, []reflect.Type{tyString}, false), 1183 func(args []reflect.Value) []reflect.Value { 1184 return args[0].Call(args[1:]) 1185 }) 1186 err := reflectx.SetMethodSet(typ, []reflectx.Method{mItoa}, false) 1187 if err != nil { 1188 t.Errorf("SetMethodSet error: %v", err) 1189 } 1190 if typ.NumMethod() != 1 { 1191 t.Fail() 1192 } 1193 v := reflect.MakeFunc(typ, func(args []reflect.Value) []reflect.Value { 1194 r := strconv.Itoa(int(args[0].Int())) 1195 return []reflect.Value{reflect.ValueOf(r)} 1196 }) 1197 if v.NumMethod() != 1 { 1198 t.Fail() 1199 } 1200 if r := v.Call([]reflect.Value{reflect.ValueOf(100)}); r[0].String() != "100" { 1201 t.Fail() 1202 } 1203 if r := reflectx.MethodByIndex(typ, 0).Func.Call([]reflect.Value{v, reflect.ValueOf(100)}); r[0].String() != "100" { 1204 t.Fail() 1205 } 1206 if r := v.Method(0).Call([]reflect.Value{reflect.ValueOf(100)}); r[0].String() != "100" { 1207 t.Fail() 1208 } 1209 } 1210 1211 type chanType chan int 1212 1213 func (ch chanType) Send(n int) { 1214 ch <- n 1215 } 1216 1217 func (ch chanType) Recv() (n int) { 1218 t := time.NewTimer(1e9) 1219 defer t.Stop() 1220 select { 1221 case n = <-ch: 1222 case <-t.C: 1223 n = -1 1224 } 1225 return 1226 } 1227 1228 func TestChan(t *testing.T) { 1229 if runtime.Compiler == "gopherjs" { 1230 t.Skip("skip gopherjs") 1231 } 1232 c := make(chanType) 1233 go func() { 1234 c.Send(100) 1235 }() 1236 if n := c.Recv(); n != 100 { 1237 t.Fatalf("recv %v", n) 1238 } 1239 styp := reflectx.NamedTypeOf("main", "chanType", reflect.TypeOf((chan int)(nil))) 1240 typ := reflectx.NewMethodSet(styp, 2, 2) 1241 mSend := reflectx.MakeMethod( 1242 "Send", 1243 "main", 1244 false, 1245 reflect.FuncOf([]reflect.Type{tyInt}, nil, false), 1246 func(args []reflect.Value) []reflect.Value { 1247 args[0].Send(args[1]) 1248 return nil 1249 }) 1250 mRecv := reflectx.MakeMethod( 1251 "Recv", 1252 "main", 1253 false, 1254 reflect.FuncOf(nil, []reflect.Type{tyInt}, false), 1255 func(args []reflect.Value) []reflect.Value { 1256 t := time.NewTimer(1e9) 1257 n, r, _ := reflect.Select([]reflect.SelectCase{ 1258 {reflect.SelectRecv, args[0], reflect.Value{}}, 1259 {reflect.SelectRecv, reflect.ValueOf(t.C), reflect.Value{}}, 1260 }) 1261 if n != 0 { 1262 return []reflect.Value{reflect.ValueOf(-1)} 1263 } 1264 return []reflect.Value{r} 1265 }) 1266 err := reflectx.SetMethodSet(typ, []reflectx.Method{ 1267 mSend, 1268 mRecv, 1269 }, false) 1270 if err != nil { 1271 t.Errorf("SetMethodSet error: %v", err) 1272 } 1273 if typ.NumMethod() != 2 { 1274 t.Fatal() 1275 } 1276 ch := reflect.MakeChan(typ, 0) 1277 go func() { 1278 ch.MethodByName("Send").Call([]reflect.Value{reflect.ValueOf(100)}) 1279 }() 1280 if r := ch.MethodByName("Recv").Call(nil); r[0].Int() != 100 { 1281 t.Fatalf("recv %v", r[0]) 1282 } 1283 } 1284 1285 type Map map[int]string 1286 1287 func (m Map) Set(k int, v string) { 1288 m[k] = v 1289 } 1290 1291 func (m Map) Get(k int) (string, bool) { 1292 r, ok := m[k] 1293 return r, ok 1294 } 1295 1296 func TestMap(t *testing.T) { 1297 { 1298 m := make(Map) 1299 m.Set(100, "Hello") 1300 r, ok := m.Get(100) 1301 if !ok { 1302 t.Fail() 1303 } 1304 if r != "Hello" { 1305 t.Fail() 1306 } 1307 } 1308 styp := reflectx.NamedTypeOf("main", "Map", reflect.TypeOf((*map[int]string)(nil)).Elem()) 1309 typ := reflectx.NewMethodSet(styp, 2, 2) 1310 mSet := reflectx.MakeMethod( 1311 "Set", 1312 "main", 1313 false, 1314 reflect.FuncOf([]reflect.Type{tyInt, tyString}, nil, false), 1315 func(args []reflect.Value) []reflect.Value { 1316 args[0].SetMapIndex(args[1], args[2]) 1317 return nil 1318 }) 1319 mGet := reflectx.MakeMethod( 1320 "Get", 1321 "main", 1322 false, 1323 reflect.FuncOf([]reflect.Type{tyInt}, []reflect.Type{tyString, tyBool}, false), 1324 func(args []reflect.Value) []reflect.Value { 1325 r := args[0].MapIndex(args[1]) 1326 if r.IsValid() { 1327 return []reflect.Value{r, reflect.ValueOf(true)} 1328 } 1329 return []reflect.Value{r, reflect.ValueOf(false)} 1330 }) 1331 err := reflectx.SetMethodSet(typ, []reflectx.Method{ 1332 mSet, 1333 mGet, 1334 }, false) 1335 if err != nil { 1336 t.Errorf("SetMethodSet error: %v", err) 1337 } 1338 if typ.NumMethod() != 2 { 1339 t.Fatal() 1340 } 1341 v := reflect.MakeMap(typ) 1342 v.MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100), reflect.ValueOf("Hello")}) 1343 r := v.MethodByName("Get").Call([]reflect.Value{reflect.ValueOf(100)}) 1344 if len(r) != 2 { 1345 t.Fail() 1346 } 1347 if fmt.Sprint(r[0]) != "Hello" || fmt.Sprint(r[1]) != "true" { 1348 t.Fatal(r[0], r[1]) 1349 } 1350 } 1351 1352 type emtpyCall struct { 1353 X int 1354 Y int 1355 } 1356 1357 //go:noinline 1358 func (t *emtpyCall) Set(x int, y int) { 1359 1360 } 1361 1362 //go:noinline 1363 func (t emtpyCall) Info(x int, y int) { 1364 1365 } 1366 1367 func makeDynamicEmptyCall() reflect.Type { 1368 fs := []reflect.StructField{ 1369 reflect.StructField{Name: "X", Type: reflect.TypeOf(0)}, 1370 reflect.StructField{Name: "Y", Type: reflect.TypeOf(0)}, 1371 } 1372 styp := reflectx.NamedStructOf("main", "emptyCall", fs) 1373 //var typ reflect.Type 1374 typ := reflectx.NewMethodSet(styp, 1, 2) 1375 mInfo := reflectx.MakeMethod( 1376 "Info", 1377 "main", 1378 false, 1379 reflect.FuncOf([]reflect.Type{tyInt, tyInt}, nil, false), 1380 func(args []reflect.Value) (result []reflect.Value) { 1381 return 1382 }, 1383 ) 1384 mSet := reflectx.MakeMethod( 1385 "Set", 1386 "main", 1387 true, 1388 reflect.FuncOf([]reflect.Type{tyInt, tyInt}, nil, false), 1389 func(args []reflect.Value) (result []reflect.Value) { 1390 return 1391 }, 1392 ) 1393 reflectx.SetMethodSet(typ, []reflectx.Method{ 1394 mInfo, 1395 mSet, 1396 }, true) 1397 return typ 1398 } 1399 1400 func BenchmarkNativeCallPtr(b *testing.B) { 1401 pt := &emtpyCall{} 1402 for i := 0; i < b.N; i++ { 1403 pt.Set(100, 200) 1404 } 1405 } 1406 1407 func BenchmarkReflectCallPtr(b *testing.B) { 1408 b.StopTimer() 1409 pt := &emtpyCall{} 1410 set := reflect.ValueOf(pt).MethodByName("Set").Interface().(func(int, int)) 1411 b.StartTimer() 1412 for i := 0; i < b.N; i++ { 1413 set(100, 200) 1414 } 1415 } 1416 1417 func BenchmarkDynamicCallPtr(b *testing.B) { 1418 b.StopTimer() 1419 typ := makeDynamicEmptyCall() 1420 pt := reflect.New(typ) 1421 set := pt.MethodByName("Set").Interface().(func(int, int)) 1422 b.StartTimer() 1423 for i := 0; i < b.N; i++ { 1424 set(100, 200) 1425 } 1426 } 1427 1428 func BenchmarkNativeCallNoPtr(b *testing.B) { 1429 pt := emtpyCall{} 1430 for i := 0; i < b.N; i++ { 1431 pt.Info(100, 200) 1432 } 1433 } 1434 1435 func BenchmarkReflectCallNoPtr(b *testing.B) { 1436 b.StopTimer() 1437 pt := emtpyCall{} 1438 set := reflect.ValueOf(pt).MethodByName("Info").Interface().(func(int, int)) 1439 b.StartTimer() 1440 for i := 0; i < b.N; i++ { 1441 set(100, 200) 1442 } 1443 } 1444 1445 func BenchmarkDynamicCallNoPtr(b *testing.B) { 1446 b.StopTimer() 1447 typ := makeDynamicEmptyCall() 1448 pt := reflect.New(typ).Elem() 1449 set := pt.MethodByName("Info").Interface().(func(int, int)) 1450 b.StartTimer() 1451 for i := 0; i < b.N; i++ { 1452 set(100, 200) 1453 } 1454 } 1455 1456 func BenchmarkNativeCallIndirect(b *testing.B) { 1457 pt := &emtpyCall{} 1458 for i := 0; i < b.N; i++ { 1459 pt.Info(100, 200) 1460 } 1461 } 1462 1463 func BenchmarkReflectCallIndirect(b *testing.B) { 1464 b.StopTimer() 1465 pt := &emtpyCall{} 1466 set := reflect.ValueOf(pt).MethodByName("Info").Interface().(func(int, int)) 1467 b.StartTimer() 1468 for i := 0; i < b.N; i++ { 1469 set(100, 200) 1470 } 1471 } 1472 1473 func BenchmarkDynamicCallIndirect(b *testing.B) { 1474 b.StopTimer() 1475 typ := makeDynamicEmptyCall() 1476 pt := reflect.New(typ) 1477 set := pt.MethodByName("Info").Interface().(func(int, int)) 1478 b.StartTimer() 1479 for i := 0; i < b.N; i++ { 1480 set(100, 200) 1481 } 1482 }