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