github.com/goplus/igop@v0.25.0/interp_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package igop_test 6 7 // This test runs the SSA interpreter over sample Go programs. 8 // Because the interpreter requires intrinsics for assembly 9 // functions and many low-level runtime routines, it is inherently 10 // not robust to evolutionary change in the standard library. 11 // Therefore the test cases are restricted to programs that 12 // use a fake standard library in testdata/src containing a tiny 13 // subset of simple functions useful for writing assertions. 14 // 15 // We no longer attempt to interpret any real standard packages such as 16 // fmt or testing, as it proved too fragile. 17 18 import ( 19 "bytes" 20 "context" 21 "fmt" 22 "log" 23 "os" 24 "path/filepath" 25 "reflect" 26 "runtime" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/goplus/igop" 32 "github.com/goplus/igop/testdata/info" 33 34 _ "github.com/goplus/igop/pkg/bytes" 35 _ "github.com/goplus/igop/pkg/errors" 36 _ "github.com/goplus/igop/pkg/fmt" 37 _ "github.com/goplus/igop/pkg/math" 38 _ "github.com/goplus/igop/pkg/os" 39 _ "github.com/goplus/igop/pkg/path/filepath" 40 _ "github.com/goplus/igop/pkg/reflect" 41 _ "github.com/goplus/igop/pkg/runtime" 42 _ "github.com/goplus/igop/pkg/strings" 43 _ "github.com/goplus/igop/pkg/sync" 44 _ "github.com/goplus/igop/pkg/time" 45 ) 46 47 // These are files in github.com/goplus/igop/testdata/. 48 var testdataTests = []string{ 49 "boundmeth.go", 50 "complit.go", 51 "coverage.go", 52 "defer.go", 53 "fieldprom.go", 54 "ifaceconv.go", 55 "ifaceprom.go", 56 "initorder.go", 57 "methprom.go", 58 "mrvchain.go", 59 "range.go", 60 "recover.go", 61 "reflect.go", 62 "static.go", 63 "recover2.go", 64 "static.go", 65 "issue23536.go", 66 "tinyfin.go", 67 "issue5963.go", 68 } 69 70 func runInput(t *testing.T, input string) bool { 71 fmt.Println("Input:", input) 72 start := time.Now() 73 _, err := igop.Run(input, nil, 0) 74 sec := time.Since(start).Seconds() 75 if err != nil { 76 t.Error(err) 77 fmt.Printf("FAIL %0.3fs\n", sec) 78 return false 79 } 80 fmt.Printf("PASS %0.3fs\n", sec) 81 return true 82 } 83 84 // TestTestdataFiles runs the interpreter on testdata/*.go. 85 func TestTestdataFiles(t *testing.T) { 86 cwd, err := os.Getwd() 87 if err != nil { 88 log.Fatal(err) 89 } 90 91 var failures []string 92 for _, input := range testdataTests { 93 if !runInput(t, filepath.Join(cwd, "testdata", input)) { 94 failures = append(failures, input) 95 } 96 } 97 printFailures(failures) 98 } 99 100 func printFailures(failures []string) { 101 if failures != nil { 102 fmt.Println("The following tests failed:") 103 for _, f := range failures { 104 fmt.Printf("\t%s\n", f) 105 } 106 } 107 } 108 109 func TestUntypedNil(t *testing.T) { 110 src := `package main 111 112 type T func() 113 114 func main() { 115 if T(nil) != nil { 116 panic("error") 117 } 118 if !(T(nil) == nil) { 119 panic("error") 120 } 121 } 122 ` 123 _, err := igop.RunFile("main.go", src, nil, 0) 124 if err != nil { 125 t.Fatal(err) 126 } 127 } 128 129 func TestRegisterExternal(t *testing.T) { 130 ctx := igop.NewContext(0) 131 ctx.RegisterExternal("main.call", func(i, j int) int { 132 return i * j 133 }) 134 var v int = 200 135 ctx.RegisterExternal("main.v", &v) 136 src := `package main 137 138 func call(i, j int) int { 139 return i+j 140 } 141 142 var v int 143 144 func main() { 145 if n := call(10,20); n != 200 { 146 panic(n) 147 } 148 if v != 200 { 149 panic(v) 150 } 151 } 152 ` 153 _, err := ctx.RunFile("main.go", src, nil) 154 if err != nil { 155 t.Fatal(err) 156 } 157 158 // reset override func 159 ctx.RegisterExternal("main.call", nil) 160 _, err = ctx.RunFile("main.go", src, nil) 161 if err == nil || err.Error() != "30" { 162 t.Fatal("must panic 30") 163 } 164 } 165 166 func TestOsExit(t *testing.T) { 167 src := `package main 168 169 import "os" 170 171 func main() { 172 os.Exit(-2) 173 } 174 ` 175 code, err := igop.RunFile("main.go", src, nil, 0) 176 if err != nil { 177 t.Fatal(err) 178 } 179 if code != -2 { 180 t.Fatalf("exit code %v, must -2", code) 181 } 182 } 183 184 func TestOpAlloc(t *testing.T) { 185 src := `package main 186 187 type T struct { 188 n1 int 189 n2 int 190 } 191 192 func (t T) call() int { 193 return t.n1 * t.n2 194 } 195 196 func main() { 197 var n int 198 for i := 0; i < 3; i++ { 199 n += T{i,3}.call() 200 } 201 if n != 9 { 202 panic(n) 203 } 204 } 205 ` 206 _, err := igop.RunFile("main.go", src, nil, 0) 207 if err != nil { 208 t.Fatal(err) 209 } 210 } 211 212 func TestOpBin(t *testing.T) { 213 src := `package main 214 215 func main() { 216 a := 10 // 1010 217 b := 12 // 1100 218 n1 := a + b 219 n2 := a - b 220 n3 := a * b 221 n4 := a / b 222 n5 := a % b 223 n6 := a & b 224 n7 := a | b 225 n8 := a ^ b 226 n9 := a &^ b 227 n10 := a << 3 228 n11 := a >> 3 229 v1 := a > b 230 v2 := a < b 231 v3 := a >= b 232 v4 := a <= b 233 v5 := a == b 234 v6 := a != b 235 if n1 != 22 || n2 != -2 || n3 != 120 || n4 != 0 || n5 != 10 || n6 != 8 || 236 n7 != 14 || n8 != 6 || n9 != 2 || n10 != 80 || n11 != 1 || 237 v1 != false || v2 != true || v3 != false || v4 != true || v5 != false || v6 != true { 238 println(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11) 239 println(v1, v2, v3, v4, v5, v6) 240 panic("error") 241 } 242 } 243 ` 244 _, err := igop.RunFile("main.go", src, nil, 0) 245 if err != nil { 246 t.Fatal(err) 247 } 248 } 249 250 func TestOpChangeType(t *testing.T) { 251 src := `package main 252 253 type T func(int, int) int 254 255 func add(i, j int) int { 256 return i + j 257 } 258 259 type I interface{} 260 261 func main() { 262 // static change type 263 fn := T(add) 264 if n := fn(10, 20); n != 30 { 265 panic(n) 266 } 267 var i interface{} = I(nil) 268 if i != nil { 269 panic("must nil") 270 } 271 // dynamic change type 272 var k interface{} 273 i = I(k) 274 if i != nil { 275 panic("must nil") 276 } 277 i = I(100) 278 if i == nil { 279 panic("must not nil") 280 } 281 } 282 ` 283 _, err := igop.RunFile("main.go", src, nil, 0) 284 if err != nil { 285 t.Fatal(err) 286 } 287 } 288 289 func TestOpIndex(t *testing.T) { 290 src := `package main 291 292 func main() { 293 var n int 294 for _, v := range [3]int{1, 2, 4} { 295 n += v 296 } 297 if n != 7 { 298 panic(n) 299 } 300 } 301 ` 302 _, err := igop.RunFile("main.go", src, nil, 0) 303 if err != nil { 304 t.Fatal(err) 305 } 306 } 307 308 func TestUnderscopeMap(t *testing.T) { 309 src := `package main 310 311 type key struct { 312 _ int 313 x int 314 } 315 316 var ( 317 s1 = "s1" 318 s2 = "s2" 319 s3 = "s3" 320 s4 = "s4" 321 ) 322 323 func main() { 324 m := make(map[key]string) 325 m[key{0, 1}] = s1 326 m[key{0, 2}] = s2 327 m[key{0, 3}] = s3 328 m[key{1, 1}] = s4 329 m[key{1, 2}] = "s22" 330 if n := len(m); n != 3 { 331 panic(n) 332 } 333 if v := m[key{2, 2}]; v != "s22" { 334 panic(v) 335 } 336 if v, ok := m[key{1,4}]; ok { 337 panic(v) 338 } 339 } 340 ` 341 _, err := igop.RunFile("main.go", src, nil, 0) 342 if err != nil { 343 t.Fatal(err) 344 } 345 } 346 347 func TestOpSend(t *testing.T) { 348 src := `package main 349 350 import ( 351 "fmt" 352 ) 353 354 type T struct{} 355 356 func main() { 357 ch := make(chan *T) 358 go func() { 359 ch <- nil 360 }() 361 v := <-ch 362 if v != nil { 363 panic("must nil") 364 } 365 if s := fmt.Sprintf("%T", v); s != "*main.T" { 366 panic(s) 367 } 368 go func() { 369 ch <- &T{} 370 }() 371 v = <-ch 372 if v == nil { 373 panic("must not nil") 374 } 375 } 376 ` 377 _, err := igop.RunFile("main.go", src, nil, 0) 378 if err != nil { 379 t.Fatal(err) 380 } 381 } 382 383 func TestShadowedMethod(t *testing.T) { 384 src := `// run 385 386 // Copyright 2018 The Go Authors. All rights reserved. 387 // Use of this source code is governed by a BSD-style 388 // license that can be found in the LICENSE file. 389 390 // When computing method sets with shadowed methods, make sure we 391 // compute whether a method promotion involved a pointer traversal 392 // based on the promoted method, not the shadowed method. 393 394 package main 395 396 import ( 397 "bytes" 398 "fmt" 399 ) 400 401 type mystruct struct { 402 f int 403 } 404 405 func (t mystruct) String() string { 406 return "FAIL" 407 } 408 409 func main() { 410 type deep struct { 411 mystruct 412 } 413 s := struct { 414 deep 415 *bytes.Buffer 416 }{ 417 deep{}, 418 bytes.NewBufferString("ok"), 419 } 420 421 if got := s.String(); got != "ok" { 422 panic(got) 423 } 424 425 var i fmt.Stringer = s 426 if got := i.String(); got != "ok" { 427 panic(got) 428 } 429 } 430 ` 431 _, err := igop.RunFile("main.go", src, nil, 0) 432 if err != nil { 433 t.Fatal(err) 434 } 435 } 436 437 func TestConvertUnsafePointer(t *testing.T) { 438 src := `package main 439 440 import ( 441 "unsafe" 442 ) 443 444 func main() { 445 a := [4]int{0, 1, 2, 3} 446 p := unsafe.Pointer(&a) 447 p2 := unsafe.Pointer(uintptr(p) + 2*unsafe.Sizeof(a[0])) 448 *(*int)(p2) = 4 449 if a != [4]int{0, 1, 4, 3} { 450 panic("error") 451 } 452 } 453 ` 454 _, err := igop.RunFile("main.go", src, nil, 0) 455 if err != nil { 456 t.Fatal(err) 457 } 458 } 459 460 func TestBuiltinPrintln(t *testing.T) { 461 src := `// run 462 463 // Copyright 2014 The Go Authors. All rights reserved. 464 // Use of this source code is governed by a BSD-style 465 // license that can be found in the LICENSE file. 466 467 // Test internal print routines that are generated 468 // by the print builtin. This test is not exhaustive, 469 // we're just checking that the formatting is correct. 470 471 package main 472 473 func main() { 474 println((interface{})(nil)) // printeface 475 println((interface { // printiface 476 f() 477 })(nil)) 478 println((map[int]int)(nil)) // printpointer 479 println(([]int)(nil)) // printslice 480 println(int64(-7)) // printint 481 println(uint64(7)) // printuint 482 println(uint32(7)) // printuint 483 println(uint16(7)) // printuint 484 println(uint8(7)) // printuint 485 println(uint(7)) // printuint 486 println(uintptr(7)) // printuint 487 println(8.0) // printfloat 488 println(complex(9.0, 10.0)) // printcomplex 489 println(true) // printbool 490 println(false) // printbool 491 println("hello") // printstring 492 println("one", "two") // printsp 493 494 // test goprintf 495 defer println((interface{})(nil)) 496 defer println((interface { 497 f() 498 })(nil)) 499 defer println((map[int]int)(nil)) 500 defer println(([]int)(nil)) 501 defer println(int64(-11)) 502 defer println(uint64(12)) 503 defer println(uint32(12)) 504 defer println(uint16(12)) 505 defer println(uint8(12)) 506 defer println(uint(12)) 507 defer println(uintptr(12)) 508 defer println(13.0) 509 defer println(complex(14.0, 15.0)) 510 defer println(true) 511 defer println(false) 512 defer println("hello") 513 defer println("one", "two") 514 } 515 ` 516 out := `(0x0,0x0) 517 (0x0,0x0) 518 0x0 519 [0/0]0x0 520 -7 521 7 522 7 523 7 524 7 525 7 526 7 527 +8.000000e+000 528 (+9.000000e+000+1.000000e+001i) 529 true 530 false 531 hello 532 one two 533 one two 534 hello 535 false 536 true 537 (+1.400000e+001+1.500000e+001i) 538 +1.300000e+001 539 12 540 12 541 12 542 12 543 12 544 12 545 -11 546 [0/0]0x0 547 0x0 548 (0x0,0x0) 549 (0x0,0x0) 550 ` 551 ctx := igop.NewContext(0) 552 var buf bytes.Buffer 553 ctx.SetPrintOutput(&buf) 554 _, err := ctx.RunFile("main.go", src, nil) 555 if err != nil { 556 t.Fatal(err) 557 } 558 if buf.String() != out { 559 t.Fatal("error") 560 } 561 } 562 563 type panicinfo struct { 564 src string 565 err string 566 } 567 568 func TestPanicInfo(t *testing.T) { 569 infos := []panicinfo{ 570 {`panic(100)`, `100`}, 571 {`panic(100.0)`, `+1.000000e+002`}, 572 {`panic("hello")`, `hello`}, 573 {`panic((*interface{})(nil))`, `(*interface {}) 0x0`}, 574 {`type T int; panic(T(100))`, `main.T(100)`}, 575 {`type T float64; panic(T(100.0))`, `main.T(+1.000000e+002)`}, 576 {`type T string; panic(T("hello"))`, `main.T("hello")`}, 577 {`type T struct{}; panic((*T)(nil))`, `(*main.T) 0x0`}, 578 } 579 ctx := igop.NewContext(0) 580 for _, info := range infos { 581 src := fmt.Sprintf("package main;func main(){%v}", info.src) 582 code, err := ctx.RunFile("main.go", src, nil) 583 if code != 2 || err == nil { 584 t.Fatalf("%v must panic", info.src) 585 } 586 if s := err.Error(); s != info.err { 587 t.Fatalf("%v err is %v, want %v", info.src, s, info.err) 588 } 589 } 590 } 591 592 func TestPanicError(t *testing.T) { 593 src := `package main 594 import "errors" 595 596 func test() { 597 panic(errors.New("error info")) 598 } 599 600 func main() { 601 test() 602 } 603 ` 604 _, err := igop.RunFile("main.go", src, nil, 0) 605 if err == nil { 606 t.Fatal("must panic") 607 } 608 if s := err.Error(); s != "error info" { 609 t.Fatalf("error %q", s) 610 } 611 pe, ok := err.(igop.PanicError) 612 if !ok { 613 t.Fatal("error type must igop.PanicError") 614 } 615 ve, ok := pe.Value.(error) 616 if !ok { 617 t.Fatal("e.Value type must error") 618 } 619 if s := ve.Error(); s != "error info" { 620 t.Fatalf("e.Value %q", s) 621 } 622 t.Log("dump panic stack\n", string(pe.Stack())) 623 } 624 625 func TestPanicErrorRecover(t *testing.T) { 626 src := `package main 627 import "errors" 628 func main() { 629 defer func() { 630 err := recover() 631 if err == nil { 632 panic("must error") 633 } 634 if s := err.(error).Error(); s != "error info" { 635 panic(s) 636 } 637 }() 638 panic(errors.New("error info")) 639 } 640 ` 641 _, err := igop.RunFile("main.go", src, nil, 0) 642 if err != nil { 643 t.Fatal(err) 644 } 645 } 646 647 func TestEnablePrintAny(t *testing.T) { 648 src := `package main 649 650 type T struct { 651 X int 652 Y int 653 } 654 func main() { 655 println([2]int{100,200}) 656 println(T{100,200}) 657 } 658 ` 659 ctx := igop.NewContext(0) 660 var buf bytes.Buffer 661 ctx.SetPrintOutput(&buf) 662 _, err := ctx.RunFile("main.go", src, nil) 663 if err == nil { 664 t.Fatal("must panic") 665 } 666 if s := err.Error(); s != "illegal types for operand: print\n\t[2]int" { 667 t.Fatal(s) 668 } 669 ctx.Mode |= igop.EnablePrintAny 670 _, err = ctx.RunFile("main.go", src, nil) 671 if err != nil { 672 t.Fatal(err) 673 } 674 if s := buf.String(); s != "[100 200]\n{100 200}\n" { 675 t.Fatal(s) 676 } 677 } 678 679 func TestFib(t *testing.T) { 680 src := `package main 681 682 import ( 683 "sync" 684 ) 685 686 func fib(n int) int { 687 if n < 2 { 688 return n 689 } 690 return fib(n-2) + fib(n-1) 691 } 692 693 func main() { 694 var wg sync.WaitGroup 695 const N = 10 696 for i := 0; i < N; i++ { 697 wg.Add(1) 698 go func() { 699 if fib(20) != 6765 { 700 panic("error") 701 } 702 wg.Done() 703 }() 704 } 705 wg.Wait() 706 } 707 ` 708 _, err := igop.RunFile("main.go", src, nil, 0) 709 if err != nil { 710 t.Fatal(err) 711 } 712 } 713 714 func TestFibv(t *testing.T) { 715 src := `package main 716 717 import "sync" 718 719 func main() { 720 var fib func(n int) int 721 fib = func(n int) int { 722 if n < 2 { 723 return n 724 } 725 return fib(n-2) + fib(n-1) 726 } 727 728 var wg sync.WaitGroup 729 const N = 10 730 for i := 0; i < N; i++ { 731 wg.Add(1) 732 go func() { 733 if fib(20) != 6765 { 734 panic("error") 735 } 736 wg.Done() 737 }() 738 } 739 wg.Wait() 740 } 741 ` 742 _, err := igop.RunFile("main.go", src, nil, 0) 743 if err != nil { 744 t.Fatal(err) 745 } 746 } 747 748 func TestFibi(t *testing.T) { 749 src := `package main 750 751 import "sync" 752 753 type I interface { 754 fib(i I, n int) int 755 } 756 757 type T struct { 758 } 759 760 func (t *T) fib(i I, n int) int { 761 if n < 2 { 762 return n 763 } 764 return i.fib(i, n-2) + i.fib(i, n-1) 765 } 766 767 func fib(n int) int { 768 t := &T{} 769 return t.fib(t, n) 770 } 771 772 func main() { 773 var wg sync.WaitGroup 774 const N = 10 775 for i := 0; i < N; i++ { 776 wg.Add(1) 777 go func() { 778 if fib(20) != 6765 { 779 panic("error") 780 } 781 wg.Done() 782 }() 783 } 784 wg.Wait() 785 } 786 ` 787 _, err := igop.RunFile("main.go", src, nil, 0) 788 if err != nil { 789 t.Fatal(err) 790 } 791 } 792 793 func TestBinOpInt(t *testing.T) { 794 // + - * / % & ^ &^ < <= > >= 795 tsrc := `package main 796 797 import "fmt" 798 799 type T $int 800 801 func main() { 802 // 0101 0110 803 test(5, 6) 804 testConst() 805 testDivideZero() 806 } 807 808 func testConst() { 809 var a T = 4 810 var b T = 2 811 var c T = 4 812 check(a+b,6) 813 check(a-b,2) 814 check(a*b,8) 815 check(a/b,2) 816 check(a%b,0) 817 check(a&b,0) 818 check(a|b,6) 819 check(a^b,6) 820 check(a&^b,4) 821 assert(a>b) 822 assert(a>=b) 823 assert(b<a) 824 assert(a<=a) 825 assert(a==c) 826 assert(a!=b) 827 } 828 829 func testDivideZero() { 830 defer func() { 831 if r := recover(); r == nil { 832 panic("must panic") 833 } 834 }() 835 var a T 836 var b T 837 _ = a/b 838 } 839 840 func test(a, b T) { 841 check(a+1, 6) 842 check(1+a, 6) 843 check(a+b, 11) 844 check(a-1, 4) 845 check(6-a, 1) 846 check(b-a, 1) 847 check(a*2, 10) 848 check(2*a, 10) 849 check(a*b, 30) 850 check(a/2, 2) 851 check(T(10)/a, 2) 852 check(a/b, 0) 853 check(a%2, 1) 854 check(10%a, 0) 855 check(b%a, 1) 856 check(a&4, 4) 857 check(1&a, 1) 858 check(a&b, 4) 859 check(a|4, 5) 860 check(2|a, 7) 861 check(a|b, 7) 862 check(a^2, 7) 863 check(7^a, 2) 864 check(a^b, 3) 865 check(a&^3, 4) 866 check(3&^a, 2) 867 check(a&^b, 1) 868 assert(a < 6) 869 assert(4 < a) 870 assert(a < b) 871 assert(a <= 5) 872 assert(4 <= a) 873 assert(a <= b) 874 assert(a > 4) 875 assert(6 > a) 876 assert(b > a) 877 assert(a >= 5) 878 assert(6 >= a) 879 assert(b >= a) 880 assert(a == 5) 881 assert(5 == a) 882 assert(a != 6) 883 assert(6 != a) 884 assert(a != b) 885 assert(a+1 == b) 886 } 887 888 func assert(t bool) { 889 if !t { 890 panic("error") 891 } 892 } 893 894 func check(a, b T) { 895 if a != b { 896 panic(fmt.Errorf("error %v != %v", a, b)) 897 } 898 } 899 ` 900 types := []string{ 901 "int", "int8", "int16", "int32", "int64", 902 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 903 } 904 for _, s := range types { 905 t.Log("test binop xtype", s) 906 src := strings.Replace(tsrc, "$int", "="+s, 1) 907 _, err := igop.RunFile("main.go", src, nil, 0) 908 if err != nil { 909 t.Fatal(err) 910 } 911 } 912 for _, s := range types { 913 t.Log("test binop named", s) 914 src := strings.Replace(tsrc, "$int", s, 1) 915 _, err := igop.RunFile("main.go", src, nil, 0) 916 if err != nil { 917 t.Fatal(err) 918 } 919 } 920 } 921 922 func TestBinOpFloat(t *testing.T) { 923 tsrc := `package main 924 925 import "fmt" 926 927 type T $float 928 929 func main() { 930 test(5.0, 6.5) 931 testConst() 932 } 933 934 func testConst() { 935 var a T = 4.0 936 var b T = 2.0 937 var c T = 4.0 938 check(a+b,6) 939 check(a-b,2) 940 check(a*b,8) 941 check(a/b,2) 942 assert(a>b) 943 assert(a>=b) 944 assert(b<a) 945 assert(a<=a) 946 assert(a==c) 947 assert(a!=b) 948 } 949 950 func test(a, b T) { 951 check(a+1, 6) 952 check(1+a, 6) 953 check(a+b, 11.5) 954 check(a-1, 4) 955 check(6-a, 1) 956 check(b-a, 1.5) 957 check(a*2, 10) 958 check(2*a, 10) 959 check(a*b, 32.5) 960 check(a/2, 2.5) 961 check(10/a, 2) 962 check(a/b, 5.0/6.5) 963 assert(a < 6) 964 assert(4 < a) 965 assert(a < b) 966 assert(a <= 5) 967 assert(4 <= a) 968 assert(a <= b) 969 assert(a > 4) 970 assert(6 > a) 971 assert(b > a) 972 assert(a >= 5) 973 assert(6 >= a) 974 assert(b >= a) 975 assert(a == 5) 976 assert(5 == a) 977 assert(a != 6) 978 assert(6 != a) 979 assert(a != b) 980 assert(a+1.5 == b) 981 } 982 983 func assert(t bool) { 984 if !t { 985 panic("error") 986 } 987 } 988 989 func check(a, b T) { 990 if a != b { 991 panic(fmt.Errorf("error %v != %v", a, b)) 992 } 993 } 994 ` 995 types := []string{ 996 "float32", 997 "float64", 998 } 999 for _, s := range types { 1000 t.Log("test binop xtype", s) 1001 src := strings.Replace(tsrc, "$float", "="+s, 1) 1002 _, err := igop.RunFile("main.go", src, nil, 0) 1003 if err != nil { 1004 t.Fatal(err) 1005 } 1006 } 1007 for _, s := range types { 1008 t.Log("test binop named", s) 1009 src := strings.Replace(tsrc, "$float", s, 1) 1010 _, err := igop.RunFile("main.go", src, nil, 0) 1011 if err != nil { 1012 t.Fatal(err) 1013 } 1014 } 1015 } 1016 1017 func TestBinOpComplex(t *testing.T) { 1018 tsrc := `package main 1019 1020 import "fmt" 1021 1022 type T $complex 1023 1024 func main() { 1025 test(1+2i, 3+4i) 1026 testConst() 1027 } 1028 1029 func testConst() { 1030 var a T = 4i 1031 var b T = 2i 1032 var c T = 4i 1033 check(a+b,6i) 1034 check(a-b,2i) 1035 check(a*b,-8) 1036 check(a/b,2) 1037 assert(a == c) 1038 assert(a != b) 1039 } 1040 1041 func test(a, b T) { 1042 check(a+1+2i, 2+4i) 1043 check(1+a, 2+2i) 1044 check(a+b, 4+6i) 1045 check(a-1, 2i) 1046 check(6-a, 5-2i) 1047 check(b-a, 2+2i) 1048 check(a*(2+3i), -4+7i) 1049 check((2-3i)*a, 8+1i) 1050 check(a*b, -5+10i) 1051 check(a/2i, 1-0.5i) 1052 check(10/a, 2-4i) 1053 check(a/b, 0.44+0.08i) 1054 assert(a == 1+2i) 1055 assert(1+2i == a) 1056 assert(a != 2+2i) 1057 assert(2+2i != a) 1058 assert(a != b) 1059 assert(a+2+2i == b) 1060 } 1061 1062 func assert(t bool) { 1063 if !t { 1064 panic("error") 1065 } 1066 } 1067 1068 func check(a, b T) { 1069 if a != b { 1070 panic(fmt.Errorf("error %v != %v", a, b)) 1071 } 1072 } 1073 1074 ` 1075 types := []string{ 1076 "complex64", 1077 "complex128", 1078 } 1079 for _, s := range types { 1080 t.Log("test binop xtype", s) 1081 src := strings.Replace(tsrc, "$complex", "="+s, 1) 1082 _, err := igop.RunFile("main.go", src, nil, 0) 1083 if err != nil { 1084 t.Fatal(err) 1085 } 1086 } 1087 for _, s := range types { 1088 t.Log("test binop named", s) 1089 src := strings.Replace(tsrc, "$complex", s, 1) 1090 _, err := igop.RunFile("main.go", src, nil, 0) 1091 if err != nil { 1092 t.Fatal(err) 1093 } 1094 } 1095 } 1096 1097 func TestBinOpString(t *testing.T) { 1098 tsrc := `package main 1099 1100 import "fmt" 1101 1102 type T = string 1103 1104 func main() { 1105 test("go", "ssa", "go") 1106 testConst() 1107 } 1108 1109 func testConst() { 1110 var a T = "hello" 1111 var b T = "world" 1112 var c T = "hello" 1113 check(a+b,"helloworld") 1114 assert(a < b) 1115 assert(a <= b) 1116 assert(b > a) 1117 assert(b >= a) 1118 assert(a == c) 1119 assert(a != b) 1120 } 1121 1122 func test(a, b, c T) { 1123 check(a+"run", "gorun") 1124 check("run"+a, "rungo") 1125 check(a+b, "gossa") 1126 assert(a < "go1") 1127 assert("ao" < a) 1128 assert(a < b) 1129 assert(a <= "go") 1130 assert("ao" <= a) 1131 assert(a <= b) 1132 assert(a > "ao") 1133 assert("go1" > a) 1134 assert(b > a) 1135 assert(a >= "go") 1136 assert("go1" >= a) 1137 assert(b >= a) 1138 assert(a == "go") 1139 assert("go" == a) 1140 assert(a != "go1") 1141 assert("go1" != a) 1142 assert(a != b) 1143 assert(a == c) 1144 } 1145 1146 func assert(t bool) { 1147 if !t { 1148 panic("error") 1149 } 1150 } 1151 1152 func check(a, b T) { 1153 if a != b { 1154 panic(fmt.Errorf("error %v != %v", a, b)) 1155 } 1156 } 1157 ` 1158 t.Log("test binop string") 1159 _, err := igop.RunFile("main.go", tsrc, nil, 0) 1160 if err != nil { 1161 t.Fatal(err) 1162 } 1163 t.Log("test binop named string") 1164 src := strings.Replace(tsrc, "= string", "string", 1) 1165 _, err = igop.RunFile("main.go", src, nil, 0) 1166 if err != nil { 1167 t.Fatal(err) 1168 } 1169 } 1170 1171 func TestBinOpShift(t *testing.T) { 1172 tsrc := `package main 1173 type T1 $T1 1174 type T2 $T2 1175 1176 func main() { 1177 test(4, 2) 1178 } 1179 func test(a T1, b T2) { 1180 assert(a << b == 16) 1181 assert(a >> b == 1) 1182 assert(a << T2(2) == 16) 1183 assert(a >> T2(2) == 1) 1184 assert(T1(4) << b == 16) 1185 assert(T1(4) >> b == 1) 1186 var c T1 = 4 1187 var d T2 = 2 1188 assert(c << d == 16) 1189 assert(c >> d == 1) 1190 } 1191 func assert(t bool) { 1192 if !t { 1193 panic("error") 1194 } 1195 } 1196 ` 1197 types := []string{ 1198 "int", "int8", "int16", "int32", "int64", 1199 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 1200 } 1201 for _, t1 := range types { 1202 t.Log("test binop shift", t1) 1203 for _, t2 := range types { 1204 r := strings.NewReplacer("$T1", "="+t1, "$T2", "="+t2) 1205 src := r.Replace(tsrc) 1206 _, err := igop.RunFile("main.go", src, nil, 0) 1207 if err != nil { 1208 t.Fatal(err) 1209 } 1210 } 1211 for _, t2 := range types { 1212 r := strings.NewReplacer("$T1", "="+t1, "$T2", t2) 1213 src := r.Replace(tsrc) 1214 _, err := igop.RunFile("main.go", src, nil, 0) 1215 if err != nil { 1216 t.Fatal(err) 1217 } 1218 } 1219 for _, t2 := range types { 1220 r := strings.NewReplacer("$T1", t1, "$T2", "="+t2) 1221 src := r.Replace(tsrc) 1222 _, err := igop.RunFile("main.go", src, nil, 0) 1223 if err != nil { 1224 t.Fatal(err) 1225 } 1226 } 1227 for _, t2 := range types { 1228 r := strings.NewReplacer("$T1", t1, "$T2", t2) 1229 src := r.Replace(tsrc) 1230 _, err := igop.RunFile("main.go", src, nil, 0) 1231 if err != nil { 1232 t.Fatal(err) 1233 } 1234 } 1235 } 1236 } 1237 1238 func TestUnOpNot(t *testing.T) { 1239 src := `package main 1240 type T bool 1241 func main() { 1242 test(false,false) 1243 testConst() 1244 } 1245 func test(b1 bool, b2 T) { 1246 if v := !b1; v != true { 1247 panic("must true") 1248 } 1249 if v := !b2; v != true { 1250 panic("must true") 1251 } 1252 } 1253 func testConst() { 1254 var b1 bool 1255 var b2 T 1256 if v := !b1; v != true { 1257 panic("must true") 1258 } 1259 if v := !b2; v != true { 1260 panic("must true") 1261 } 1262 } 1263 ` 1264 _, err := igop.RunFile("main.go", src, nil, 0) 1265 if err != nil { 1266 t.Fatal(err) 1267 } 1268 } 1269 1270 func TestUnOpSubInt(t *testing.T) { 1271 tsrc := `package main 1272 type T $int 1273 1274 func main() { 1275 test(10,10) 1276 testConst() 1277 } 1278 1279 func test(a $int, b T) { 1280 if r := -a; r != -10 { 1281 panic("must -10") 1282 } 1283 if r := -b; r != -10 { 1284 panic("must -10") 1285 } 1286 } 1287 func testConst() { 1288 var a $int = 10 1289 var b T = 10 1290 if r := -a; r != -10 { 1291 panic("must -10") 1292 } 1293 if r := -b; r != -10 { 1294 panic("must -10") 1295 } 1296 } 1297 ` 1298 types := []string{ 1299 "int", "int8", "int16", "int32", "int64", 1300 } 1301 1302 for _, s := range types { 1303 t.Log("test unop sub", s) 1304 src := strings.Replace(tsrc, "$int", s, -1) 1305 _, err := igop.RunFile("main.go", src, nil, 0) 1306 if err != nil { 1307 t.Fatal(err) 1308 } 1309 } 1310 } 1311 1312 func TestUnOpSubUint(t *testing.T) { 1313 tsrc := `package main 1314 1315 type T $uint 1316 1317 func main() { 1318 test(0b1010, 0b1011) 1319 testConst() 1320 } 1321 1322 func test(a $uint, b T) { 1323 if r := -a; r&0xff != 0b11110110 { 1324 panic(r) 1325 } 1326 if r := -b; r&0xff != 0b11110101 { 1327 panic(r) 1328 } 1329 } 1330 func testConst() { 1331 var a $uint = 0b1010 1332 var b T = 0b1011 1333 if r := -a; r&0xff != 0b11110110 { 1334 panic(r) 1335 } 1336 if r := -b; r&0xff != 0b11110101 { 1337 panic(r) 1338 } 1339 } 1340 ` 1341 types := []string{ 1342 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 1343 } 1344 for _, s := range types { 1345 src := strings.Replace(tsrc, "$uint", s, -1) 1346 _, err := igop.RunFile("main.go", src, nil, 0) 1347 if err != nil { 1348 t.Fatal(err) 1349 } 1350 } 1351 } 1352 1353 func TestUnOpSubFloat(t *testing.T) { 1354 tsrc := `package main 1355 1356 type T $float 1357 1358 func main() { 1359 test(5.0, 6.5) 1360 testConst() 1361 } 1362 1363 func test(a $float, b T) { 1364 if r := -a; r != -5.0 { 1365 panic(r) 1366 } 1367 if r := -b; r != -6.5 { 1368 panic(r) 1369 } 1370 } 1371 func testConst() { 1372 var a $float = 5.0 1373 var b T = 6.5 1374 if r := -a; r != -5.0 { 1375 panic(r) 1376 } 1377 if r := -b; r != -6.5 { 1378 panic(r) 1379 } 1380 } 1381 ` 1382 types := []string{ 1383 "float32", "float64", 1384 } 1385 for _, s := range types { 1386 t.Log("test unop sub", s) 1387 src := strings.Replace(tsrc, "$float", s, -1) 1388 _, err := igop.RunFile("main.go", src, nil, 0) 1389 if err != nil { 1390 t.Fatal(err) 1391 } 1392 } 1393 } 1394 1395 func TestUnOpSubComplex(t *testing.T) { 1396 tsrc := `package main 1397 1398 type T $complex 1399 1400 func main() { 1401 test(1+2i, 3+4i) 1402 testConst() 1403 } 1404 1405 func test(a $complex, b T) { 1406 if r := -a; r != -1-2i { 1407 panic(r) 1408 } 1409 if r := -b; r != -3-4i { 1410 panic(r) 1411 } 1412 } 1413 func testConst() { 1414 var a $complex = 1+2i 1415 var b T = 3+4i 1416 if r := -a; r != -1-2i { 1417 panic(r) 1418 } 1419 if r := -b; r != -3-4i { 1420 panic(r) 1421 } 1422 } 1423 ` 1424 types := []string{ 1425 "complex64", "complex128", 1426 } 1427 for _, s := range types { 1428 t.Log("test unop sub", s) 1429 src := strings.Replace(tsrc, "$complex", s, -1) 1430 _, err := igop.RunFile("main.go", src, nil, 0) 1431 if err != nil { 1432 t.Fatal(err) 1433 } 1434 } 1435 } 1436 1437 func TestUnOpXorInt(t *testing.T) { 1438 tsrc := `package main 1439 1440 type T $int 1441 1442 func main() { 1443 test(10, 11) 1444 testConst() 1445 } 1446 1447 func test(a $int, b T) { 1448 if r := ^a; r != -11 { 1449 panic(r) 1450 } 1451 if r := ^b; r != -12 { 1452 panic(r) 1453 } 1454 } 1455 func testConst() { 1456 var a $int = 10 1457 var b T = 11 1458 if r := ^a; r != -11 { 1459 panic(r) 1460 } 1461 if r := ^b; r != -12 { 1462 panic(r) 1463 } 1464 } 1465 ` 1466 types := []string{ 1467 "int", "int8", "int16", "int32", "int64", 1468 } 1469 1470 for _, s := range types { 1471 t.Log("test unop xor", s) 1472 src := strings.Replace(tsrc, "$int", s, -1) 1473 _, err := igop.RunFile("main.go", src, nil, 0) 1474 if err != nil { 1475 t.Fatal(err) 1476 } 1477 } 1478 } 1479 1480 func TestUnOpXorUint(t *testing.T) { 1481 tsrc := `package main 1482 1483 type T $uint 1484 1485 func main() { 1486 test(0b1010, 0b1011) 1487 testConst() 1488 } 1489 1490 func test(a $uint, b T) { 1491 if r := ^a; r&0xff != 0b11110101 { 1492 panic(r) 1493 } 1494 if r := ^b; r&0xff != 0b11110100 { 1495 panic(r) 1496 } 1497 } 1498 func testConst() { 1499 var a $uint = 0b1010 1500 var b T = 0b1011 1501 if r := ^a; r&0xff != 0b11110101 { 1502 panic(r) 1503 } 1504 if r := ^b; r&0xff != 0b11110100 { 1505 panic(r) 1506 } 1507 } 1508 ` 1509 types := []string{ 1510 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 1511 } 1512 1513 for _, s := range types { 1514 t.Log("test unop xor", s) 1515 src := strings.Replace(tsrc, "$uint", s, -1) 1516 _, err := igop.RunFile("main.go", src, nil, 0) 1517 if err != nil { 1518 t.Fatal(err) 1519 } 1520 } 1521 } 1522 1523 func TestBinOpEQ(t *testing.T) { 1524 src := `package main 1525 1526 import "unsafe" 1527 1528 type T struct { 1529 a int 1530 b int 1531 _ int 1532 _ int 1533 } 1534 1535 func main() { 1536 // array 1537 ar1 := [2]int{10,20} 1538 ar2 := [2]int{10,20} 1539 if ar1 != ar2 { 1540 panic("error array") 1541 } 1542 ar1[0] = 1 1543 if ar1 == ar2 { 1544 panic("error array") 1545 } 1546 // struct & interface{} 1547 t1 := T{1,2,3,4} 1548 t2 := T{1,2,7,8} 1549 if t1 != t2 { 1550 panic("error struct") 1551 } 1552 if (interface{})(t1) != (interface{})(t2) { 1553 panic("error interface") 1554 } 1555 t1.a = 10 1556 if t1 == t2 { 1557 panic("error struct") 1558 } 1559 if (interface{})(t1) == (interface{})(t2) { 1560 panic("error interface") 1561 } 1562 // ptr 1563 ptr1 := &t1 1564 ptr2 := &t2 1565 if ptr1 == ptr2 { 1566 panic("error ptr") 1567 } 1568 ptr2 = &t1 1569 if ptr1 != ptr2 { 1570 panic("error ptr") 1571 } 1572 // unsafe pointer 1573 p1 := unsafe.Pointer(&t1) 1574 p2 := unsafe.Pointer(&t2) 1575 if p1 == p2 { 1576 panic("error unsafe pointer") 1577 } 1578 p2 = unsafe.Pointer(ptr2) 1579 if p1 != p2 { 1580 panic("error unsafe pointer") 1581 } 1582 // chan 1583 ch1 := make(chan int) 1584 ch2 := make(chan int) 1585 if ch1 == ch2 { 1586 panic("error chan") 1587 } 1588 ch3 := ch1 1589 if ch1 != ch3 { 1590 panic("error chan") 1591 } 1592 ch4 := (<-chan int)(ch1) 1593 ch5 := (chan<- int)(ch1) 1594 if ch1 != ch4 { 1595 panic("error chan") 1596 } 1597 if ch5 != ch1 { 1598 panic("error chan") 1599 } 1600 ch6 := (<-chan int)(ch2) 1601 ch7 := (chan<- int)(ch2) 1602 if ch6 == ch1 { 1603 panic("error chan") 1604 } 1605 if ch1 == ch7 { 1606 panic("error chan") 1607 } 1608 } 1609 ` 1610 _, err := igop.RunFile("main.go", src, nil, 0) 1611 if err != nil { 1612 t.Fatal(err) 1613 } 1614 } 1615 1616 func TestOpTypeChangeBasic(t *testing.T) { 1617 src := `package main 1618 1619 import ( 1620 "bytes" 1621 "fmt" 1622 ) 1623 1624 func main() { 1625 testNil() 1626 testConst() 1627 testFunc() 1628 testPtr() 1629 testSlice() 1630 testMap() 1631 testStruct() 1632 testArray() 1633 testChan() 1634 testInterface() 1635 } 1636 1637 func testNil() { 1638 var p *int 1639 type Ptr *int 1640 v := Ptr(p) 1641 if s := fmt.Sprintf("%T %v", v, v); s != "main.Ptr <nil>" { 1642 panic(s) 1643 } 1644 } 1645 1646 func testConst() { 1647 var n int = 10 1648 type T int 1649 v := T(n) 1650 if s := fmt.Sprintf("%T %v", v, v); s != "main.T 10" { 1651 panic(s) 1652 } 1653 } 1654 1655 func myfunc(int) {} 1656 1657 type Func func(int) 1658 1659 func testFunc() { 1660 v := Func(myfunc) 1661 if s := fmt.Sprintf("%T %v", v, v == nil); s != "main.Func false" { 1662 panic(s) 1663 } 1664 } 1665 1666 func testPtr() { 1667 i := 10 1668 p := &i 1669 type T *int 1670 v := T(p) 1671 i = 20 1672 if s := fmt.Sprintf("%T %v", v, *v); s != "main.T 20" { 1673 panic(s) 1674 } 1675 p2 := (*int)(v) 1676 i = 30 1677 if s := fmt.Sprintf("%T %v", p2, *p2); s != "*int 30" { 1678 panic(s) 1679 } 1680 } 1681 1682 func testSlice() { 1683 i := []int{100, 200, 300} 1684 type T []int 1685 v := T(i) 1686 if s := fmt.Sprintf("%T %v", v, v); s != "main.T [100 200 300]" { 1687 panic(s) 1688 } 1689 p := []int(v) 1690 v[0] = 1 1691 if s := fmt.Sprintf("%T %v", p, p); s != "[]int [1 200 300]" { 1692 panic(s) 1693 } 1694 } 1695 1696 func testMap() { 1697 i := map[int]string{1: "hello", 2: "world"} 1698 type T map[int]string 1699 v := T(i) 1700 if s := fmt.Sprintf("%T %v", v, v); s != "main.T map[1:hello 2:world]" { 1701 panic(s) 1702 } 1703 type T2 map[int]string 1704 v2 := T(v) 1705 i[1] = "hello2" 1706 if s := fmt.Sprintf("%T %v", v2, v2); s != "main.T map[1:hello2 2:world]" { 1707 panic(s) 1708 } 1709 } 1710 1711 func testStruct() { 1712 type Pt struct { 1713 x int 1714 y int 1715 } 1716 type T Pt 1717 i := Pt{10, 20} 1718 v := T(i) 1719 i.x = 1 1720 if s := fmt.Sprintf("%T %v", v, v); s != "main.T {10 20}" { 1721 panic(s) 1722 } 1723 } 1724 1725 func testArray() { 1726 ar := [3]int{100, 200, 300} 1727 type T [3]int 1728 v := T(ar) 1729 ar[0] = 1 1730 if s := fmt.Sprintf("%T %v", v, v); s != "main.T [100 200 300]" { 1731 panic(s) 1732 } 1733 } 1734 1735 func testChan() { 1736 ch := make(chan int) 1737 v := (chan<- int)(ch) 1738 if s := fmt.Sprintf("%T", v); s != "chan<- int" { 1739 panic(s) 1740 } 1741 type T1 chan int 1742 v1 := T1(ch) 1743 if s := fmt.Sprintf("%T", v1); s != "main.T1" { 1744 panic(s) 1745 } 1746 type T2 <-chan int 1747 v2 := T2(ch) 1748 if s := fmt.Sprintf("%T", v2); s != "main.T2" { 1749 panic(s) 1750 } 1751 type T3 chan<- int 1752 v3 := T3(ch) 1753 if s := fmt.Sprintf("%T", v3); s != "main.T3" { 1754 panic(s) 1755 } 1756 } 1757 1758 func testInterface() { 1759 var buf fmt.Stringer = bytes.NewBufferString("hello") 1760 type T fmt.Stringer 1761 v := T(buf) 1762 if s := fmt.Sprintf("%T %v", v, v.String()); s != "*bytes.Buffer hello" { 1763 panic(s) 1764 } 1765 } 1766 ` 1767 _, err := igop.RunFile("main.go", src, nil, 0) 1768 if err != nil { 1769 t.Fatal(err) 1770 } 1771 } 1772 1773 func TestOpTypeChange3(t *testing.T) { 1774 tsrc := `package main 1775 import "fmt" 1776 type T $int 1777 type T2 $int 1778 func main() { 1779 test($value) 1780 } 1781 func test(v $int) { 1782 r := T(v) 1783 if s := fmt.Sprintf("%T", r); s != "main.T" { 1784 panic(s) 1785 } 1786 r2 := T2(r) 1787 if s := fmt.Sprintf("%T", r2); s != "main.T2" { 1788 panic(s) 1789 } 1790 n := $int(r2) 1791 if s := fmt.Sprintf("%T", n); s != "$int" { 1792 panic(s) 1793 } 1794 if n != v { 1795 panic("error") 1796 } 1797 } 1798 ` 1799 ints := []string{ 1800 "int", "int8", "int16", "int32", "int64", 1801 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 1802 } 1803 for _, s := range ints { 1804 t.Log("test changetype xtype", s) 1805 r := strings.NewReplacer("$int", s, "$value", "10") 1806 src := r.Replace(tsrc) 1807 _, err := igop.RunFile("main.go", src, nil, 0) 1808 if err != nil { 1809 t.Fatal(err) 1810 } 1811 } 1812 floats := []string{"float32", "float64"} 1813 for _, s := range floats { 1814 t.Log("test changetype xtype", s) 1815 r := strings.NewReplacer("$int", s, "$value", "100.5") 1816 src := r.Replace(tsrc) 1817 _, err := igop.RunFile("main.go", src, nil, 0) 1818 if err != nil { 1819 t.Fatal(err) 1820 } 1821 } 1822 comps := []string{"complex64", "complex128"} 1823 for _, s := range comps { 1824 t.Log("test changetype xtype", s) 1825 r := strings.NewReplacer("$int", s, "$value", "1+2i") 1826 src := r.Replace(tsrc) 1827 _, err := igop.RunFile("main.go", src, nil, 0) 1828 if err != nil { 1829 t.Fatal(err) 1830 } 1831 } 1832 { 1833 t.Log("test changetype xtype", "bool") 1834 r := strings.NewReplacer("$int", "bool", "$value", "true") 1835 src := r.Replace(tsrc) 1836 _, err := igop.RunFile("main.go", src, nil, 0) 1837 if err != nil { 1838 t.Fatal(err) 1839 } 1840 } 1841 { 1842 t.Log("test changetype xtype", "string") 1843 r := strings.NewReplacer("$int", "string", "$value", `"hello"`) 1844 src := r.Replace(tsrc) 1845 _, err := igop.RunFile("main.go", src, nil, 0) 1846 if err != nil { 1847 t.Fatal(err) 1848 } 1849 } 1850 } 1851 1852 func TestOpConvert(t *testing.T) { 1853 tsrc := `package main 1854 1855 type T = $int 1856 1857 const ( 1858 V = $V 1859 N = $N 1860 F = $F 1861 ) 1862 1863 func main() { 1864 test1(V) 1865 test2(V) 1866 } 1867 1868 func test1(n T) { 1869 if int(n) != N { 1870 panic("error") 1871 } 1872 if int8(n) != N { 1873 panic("error") 1874 } 1875 if int16(n) != N { 1876 panic("error") 1877 } 1878 if int32(n) != N { 1879 panic("error") 1880 } 1881 if int64(n) != N { 1882 panic("error") 1883 } 1884 if uint(n) != N { 1885 panic("error") 1886 } 1887 if uint8(n) != N { 1888 panic("error") 1889 } 1890 if uint16(n) != N { 1891 panic("error") 1892 } 1893 if uint32(n) != N { 1894 panic("error") 1895 } 1896 if uint64(n) != N { 1897 panic("error") 1898 } 1899 if uintptr(n) != N { 1900 panic("error") 1901 } 1902 if float32(n) != F { 1903 panic("error") 1904 } 1905 if float64(n) != F { 1906 panic("error") 1907 } 1908 } 1909 1910 type Int int 1911 type Int8 int8 1912 type Int16 int16 1913 type Int32 int32 1914 type Int64 int64 1915 type Uint uint 1916 type Uint8 uint8 1917 type Uint16 uint16 1918 type Uint32 uint32 1919 type Uint64 uint64 1920 type Uintptr uintptr 1921 type Float32 float32 1922 type Float64 float64 1923 1924 func test2(n T) { 1925 if Int(n) != N { 1926 panic("error") 1927 } 1928 if Int8(n) != N { 1929 panic("error") 1930 } 1931 if Int16(n) != N { 1932 panic("error") 1933 } 1934 if Int32(n) != N { 1935 panic("error") 1936 } 1937 if Int64(n) != N { 1938 panic("error") 1939 } 1940 if Uint(n) != N { 1941 panic("error") 1942 } 1943 if Uint8(n) != N { 1944 panic("error") 1945 } 1946 if Uint16(n) != N { 1947 panic("error") 1948 } 1949 if Uint32(n) != N { 1950 panic("error") 1951 } 1952 if Uint64(n) != N { 1953 panic("error") 1954 } 1955 if Uintptr(n) != N { 1956 panic("error") 1957 } 1958 if Float32(n) != F { 1959 panic("error") 1960 } 1961 if Float64(n) != F { 1962 panic("error") 1963 } 1964 } 1965 ` 1966 csrc := `package main 1967 1968 type T = $complex 1969 1970 const ( 1971 N = $N 1972 ) 1973 1974 func main() { 1975 test1(N) 1976 test2(N) 1977 } 1978 1979 func test1(n T) { 1980 if complex64(n) != N { 1981 panic("error") 1982 } 1983 if complex128(n) != N { 1984 panic("error") 1985 } 1986 } 1987 1988 type Complex64 complex64 1989 type Complex128 complex128 1990 1991 1992 func test2(n T) { 1993 if Complex64(n) != N { 1994 panic("error") 1995 } 1996 if Complex128(n) != N { 1997 panic("error") 1998 } 1999 } 2000 ` 2001 ints := []string{ 2002 "int", "int8", "int16", "int32", "int64", 2003 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 2004 } 2005 floats := []string{"float32", "float64"} 2006 comps := []string{"complex64", "complex128"} 2007 for _, s := range ints { 2008 t.Log("test convert xtype", s) 2009 r := strings.NewReplacer("$int", s, "$V", "100", "$N", "100", "$F", "100") 2010 src := r.Replace(tsrc) 2011 _, err := igop.RunFile("main.go", src, nil, 0) 2012 if err != nil { 2013 t.Fatal(err) 2014 } 2015 } 2016 for _, s := range ints { 2017 t.Log("test convert typed", s) 2018 r := strings.NewReplacer("= $int", s, "$V", "100", "$N", "100", "$F", "100") 2019 src := r.Replace(tsrc) 2020 _, err := igop.RunFile("main.go", src, nil, 0) 2021 if err != nil { 2022 t.Fatal(err) 2023 } 2024 } 2025 for _, s := range floats { 2026 t.Log("test convert xtype", s) 2027 r := strings.NewReplacer("$int", s, "$V", "100.5", "$N", "100", "$F", "100.5") 2028 src := r.Replace(tsrc) 2029 _, err := igop.RunFile("main.go", src, nil, 0) 2030 if err != nil { 2031 t.Fatal(err) 2032 } 2033 } 2034 for _, s := range floats { 2035 t.Log("test convert typed", s) 2036 r := strings.NewReplacer("= $int", s, "$V", "100.5", "$N", "100", "$F", "100.5") 2037 src := r.Replace(tsrc) 2038 _, err := igop.RunFile("main.go", src, nil, 0) 2039 if err != nil { 2040 t.Fatal(err) 2041 } 2042 } 2043 for _, s := range comps { 2044 t.Log("test convert xtype", s) 2045 r := strings.NewReplacer("$complex", s, "$N", "1+2i") 2046 src := r.Replace(csrc) 2047 _, err := igop.RunFile("main.go", src, nil, 0) 2048 if err != nil { 2049 t.Fatal(err) 2050 } 2051 } 2052 for _, s := range comps { 2053 t.Log("test convert typed", s) 2054 r := strings.NewReplacer("= $complex", s, "$N", "1+2i") 2055 src := r.Replace(csrc) 2056 _, err := igop.RunFile("main.go", src, nil, 0) 2057 if err != nil { 2058 t.Fatal(err) 2059 } 2060 } 2061 } 2062 2063 func TestOpIf(t *testing.T) { 2064 src := `package main 2065 2066 type Bool bool 2067 2068 func main() { 2069 test1(true) 2070 test1(false) 2071 test2(true) 2072 test2(false) 2073 testConst1() 2074 testConst2() 2075 } 2076 2077 func test1(b bool) { 2078 if b { 2079 println(true) 2080 } else { 2081 println(false) 2082 } 2083 } 2084 func test2(b Bool) { 2085 if b { 2086 println(true) 2087 } else { 2088 println(false) 2089 } 2090 } 2091 func testConst1() { 2092 var b bool 2093 if !b { 2094 println(false) 2095 } 2096 b = true 2097 if b { 2098 println(true) 2099 } 2100 } 2101 func testConst2() { 2102 var b Bool 2103 if !b { 2104 println(false) 2105 } 2106 b = true 2107 if b { 2108 println(true) 2109 } 2110 } 2111 ` 2112 out := `true 2113 false 2114 true 2115 false 2116 false 2117 true 2118 false 2119 true 2120 ` 2121 ctx := igop.NewContext(0) 2122 var buf bytes.Buffer 2123 ctx.SetPrintOutput(&buf) 2124 _, err := ctx.RunFile("main.go", src, nil) 2125 if err != nil { 2126 t.Fatal(err) 2127 } 2128 if buf.String() != out { 2129 t.Fatal("error") 2130 } 2131 } 2132 2133 func TestGoexitDeadlock(t *testing.T) { 2134 src := `package main 2135 import ( 2136 "os" 2137 "runtime" 2138 ) 2139 2140 func init() { 2141 runtime.Goexit() 2142 os.Exit(-1) 2143 } 2144 2145 func main() { 2146 os.Exit(-2) 2147 } 2148 ` 2149 _, err := igop.RunFile("main.go", src, nil, 0) 2150 if err == nil { 2151 t.Fatal("must panic") 2152 } 2153 if err.Error() != igop.ErrGoexitDeadlock.Error() { 2154 t.Fatal(err) 2155 } 2156 } 2157 2158 func TestGlobalExtFunc(t *testing.T) { 2159 src := `package main 2160 import "math" 2161 var ( 2162 max = math.Max 2163 ) 2164 func main() { 2165 if max(1,3) != 3 { 2166 panic("error") 2167 } 2168 } 2169 ` 2170 _, err := igop.RunFile("main.go", src, nil, 0) 2171 if err != nil { 2172 t.Fatal(err) 2173 } 2174 } 2175 2176 func TestRegisterBuiltin(t *testing.T) { 2177 src := `package main 2178 2179 func main() { 2180 dump_info(typeof("hello")) 2181 dump_ints(20,30,50) 2182 } 2183 ` 2184 igop.RegisterCustomBuiltin("typeof", reflect.TypeOf) 2185 var info interface{} 2186 igop.RegisterCustomBuiltin("dump_info", func(v interface{}) { 2187 info = v 2188 }) 2189 var all int 2190 igop.RegisterCustomBuiltin("dump_ints", func(a ...int) { 2191 for _, v := range a { 2192 all += v 2193 } 2194 }) 2195 _, err := igop.RunFile("main.go", src, nil, 0) 2196 if err != nil { 2197 panic(err) 2198 } 2199 if info != reflect.TypeOf("hello") { 2200 panic("error") 2201 } 2202 if all != 100 { 2203 panic(all) 2204 } 2205 } 2206 2207 func TestVariadicFunc(t *testing.T) { 2208 src := `package main 2209 type Context struct{} 2210 type ClientConn struct{} 2211 type CallOption struct{} 2212 2213 type UnaryInvoker func(ctx Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error 2214 2215 func main() { 2216 } 2217 ` 2218 _, err := igop.RunFile("main.go", src, nil, 0) 2219 if err != nil { 2220 t.Fatal(err) 2221 } 2222 } 2223 2224 func TestUnsafePointer(t *testing.T) { 2225 src := `package main 2226 2227 import ( 2228 "unsafe" 2229 ) 2230 2231 func main() { 2232 type T1 unsafe.Pointer 2233 type T2 unsafe.Pointer 2234 i := 10 2235 p := unsafe.Pointer(&i) 2236 p1 := T1(uintptr(unsafe.Pointer(&i))) 2237 p2 := T2(&i) 2238 if T1(p) != p1 { 2239 panic("error T1") 2240 } 2241 if T2(p1) != (p2) { 2242 panic("error T2") 2243 } 2244 if unsafe.Pointer(p1) != unsafe.Pointer(p2) { 2245 panic("error unsafe") 2246 } 2247 } 2248 ` 2249 _, err := igop.RunFile("main.go", src, nil, 0) 2250 if err != nil { 2251 t.Fatal(err) 2252 } 2253 } 2254 2255 func TestAddImport(t *testing.T) { 2256 pkg := `package pkg 2257 import "fmt" 2258 2259 func Add(i, j int) int { 2260 return i+j 2261 } 2262 2263 func Println(a ...interface{}) { 2264 fmt.Println(a...) 2265 } 2266 ` 2267 src := `package main 2268 import "pkg" 2269 2270 func main() { 2271 if pkg.Add(100, 200) != 300 { 2272 panic("error pkg.Add") 2273 } 2274 pkg.Println("Hello") 2275 } 2276 ` 2277 ctx := igop.NewContext(0) 2278 err := ctx.AddImportFile("pkg", "pkg.go", pkg) 2279 if err != nil { 2280 t.Fatal(err) 2281 } 2282 _, err = ctx.RunFile("main.go", src, nil) 2283 if err != nil { 2284 t.Fatal(err) 2285 } 2286 } 2287 2288 func TestAddImportDir(t *testing.T) { 2289 src := `package main 2290 import "igop/pkg" 2291 2292 func main() { 2293 if pkg.Add(100, 200) != 300 { 2294 panic("error pkg.Add") 2295 } 2296 pkg.Println("Hello") 2297 } 2298 ` 2299 ctx := igop.NewContext(0) 2300 err := ctx.AddImport("igop/pkg", "./testdata/pkg") 2301 if err != nil { 2302 t.Fatal(err) 2303 } 2304 _, err = ctx.RunFile("main.go", src, nil) 2305 if err != nil { 2306 t.Fatal(err) 2307 } 2308 } 2309 2310 func TestLoadImport(t *testing.T) { 2311 if runtime.GOOS == "darwin" { 2312 switch runtime.Version()[:6] { 2313 case "go1.14", "go1.15": 2314 t.Skip("skip for workflows") 2315 } 2316 } 2317 src := `package main 2318 import "github.com/goplus/igop/testdata/pkg" 2319 2320 func main() { 2321 if pkg.Add(100, 200) != 300 { 2322 panic("error pkg.Add") 2323 } 2324 pkg.Println("Hello") 2325 } 2326 ` 2327 ctx := igop.NewContext(0) 2328 _, err := ctx.RunFile("main.go", src, nil) 2329 if err != nil { 2330 t.Fatal(err) 2331 } 2332 } 2333 2334 func TestAppend(t *testing.T) { 2335 src := `package main 2336 2337 type T string 2338 2339 func main() { 2340 a := []uint8("hello") 2341 b := "world" 2342 c := T("world") 2343 _ = append(a,b...) 2344 _ = append(a,c...) 2345 } 2346 ` 2347 ctx := igop.NewContext(0) 2348 _, err := ctx.RunFile("main.go", src, nil) 2349 if err != nil { 2350 t.Fatal(err) 2351 } 2352 } 2353 2354 func TestStructEmbed(t *testing.T) { 2355 p := &igop.Package{ 2356 Name: "info", 2357 Path: "github.com/goplus/igop/testdata/info", 2358 Interfaces: map[string]reflect.Type{ 2359 "Info": reflect.TypeOf((*info.Info)(nil)).Elem(), 2360 }, 2361 NamedTypes: map[string]reflect.Type{ 2362 "MyInfo": reflect.TypeOf((*info.MyInfo)(nil)).Elem(), 2363 }, 2364 Funcs: map[string]reflect.Value{ 2365 "NewInfo": reflect.ValueOf(info.NewInfo), 2366 }, 2367 } 2368 igop.RegisterPackage(p) 2369 2370 src := `package main 2371 2372 import ( 2373 "github.com/goplus/igop/testdata/info" 2374 ) 2375 2376 type MyInfo struct { 2377 *info.MyInfo 2378 } 2379 2380 type MyInfo2 struct { 2381 info.Info 2382 } 2383 2384 func main() { 2385 info := info.NewInfo(1) 2386 m := &MyInfo{info} 2387 check(m) 2388 m2 := &MyInfo2{info} 2389 check(m2) 2390 } 2391 2392 func check(info info.Info) { 2393 info.SetMode(-1) 2394 if info.Mode() != -1 { 2395 panic("mode") 2396 } 2397 if info.Count(1, 2, 3) != 3 { 2398 panic("count") 2399 } 2400 } 2401 ` 2402 _, err := igop.RunFile("main.go", src, nil, 0) 2403 if err != nil { 2404 t.Fatal(err) 2405 } 2406 } 2407 2408 func TestBuildTags(t *testing.T) { 2409 if runtime.GOOS == "darwin" { 2410 switch runtime.Version()[:6] { 2411 case "go1.14", "go1.15": 2412 t.Skip("skip for workflows") 2413 } 2414 } 2415 src1 := `package main 2416 2417 import ( 2418 "github.com/goplus/igop/testdata/msg" 2419 ) 2420 2421 func main() { 2422 if msg.Info != "nomsg" { 2423 panic(msg.Info) 2424 } 2425 } 2426 ` 2427 ctx1 := igop.NewContext(0) 2428 _, err := ctx1.RunFile("main.go", src1, nil) 2429 if err != nil { 2430 t.Fatal(err) 2431 } 2432 2433 src2 := `package main 2434 2435 import ( 2436 "github.com/goplus/igop/testdata/msg" 2437 ) 2438 2439 func main() { 2440 if msg.Info != "msg" { 2441 panic(msg.Info) 2442 } 2443 } 2444 ` 2445 ctx2 := igop.NewContext(0) 2446 ctx2.BuildContext.BuildTags = []string{"msg"} 2447 _, err = ctx2.RunFile("main.go", src2, nil) 2448 if err != nil { 2449 t.Fatal(err) 2450 } 2451 } 2452 2453 func TestEqualChan(t *testing.T) { 2454 src := `package main 2455 2456 func main() { 2457 ch := make(chan bool) 2458 ch1 := (<-chan bool)(ch) 2459 ch2 := (chan<- bool)(ch) 2460 var i interface{} = ch 2461 var i1 interface{} = ch1 2462 var i2 interface{} = ch2 2463 2464 check(ch == ch1, true) 2465 check(ch == ch2, true) 2466 check(i == i1, false) 2467 check(i == i2, false) 2468 check(i1 == i2, false) 2469 2470 check(ch != ch1, false) 2471 check(ch != ch2, false) 2472 check(i != i1, true) 2473 check(i != i2, true) 2474 check(i1 != i2, true) 2475 } 2476 2477 func check(b1 bool, b2 bool) { 2478 if b1 != b2 { 2479 panic("error") 2480 } 2481 } 2482 ` 2483 ctx := igop.NewContext(0) 2484 _, err := ctx.RunFile("main.go", src, nil) 2485 if err != nil { 2486 t.Fatal(err) 2487 } 2488 } 2489 2490 func TestIssue23545(t *testing.T) { 2491 src := `package main 2492 2493 func main() { 2494 if a := Get(); a != dummyID(1234) { 2495 panic("FAIL") 2496 } 2497 var i1 interface{} = Get() 2498 var i2 interface{} = dummyID(1234) 2499 if i1 == i2 { 2500 panic("FAIL") 2501 } 2502 } 2503 2504 func dummyID(x int) [Size]interface{} { 2505 var out [Size]interface{} 2506 out[0] = x 2507 return out 2508 } 2509 2510 const Size = 32 2511 2512 type OutputID [Size]interface{} 2513 2514 //go:noinline 2515 func Get() OutputID { 2516 return dummyID(1234) 2517 } 2518 ` 2519 ctx := igop.NewContext(0) 2520 _, err := ctx.RunFile("main.go", src, nil) 2521 if err != nil { 2522 t.Fatal(err) 2523 } 2524 } 2525 2526 func TestMakeChan(t *testing.T) { 2527 src := `package main 2528 2529 type Send chan<- int 2530 type Recv <-chan int 2531 2532 func main() { 2533 _ = make(chan int) 2534 _ = make(<-chan int) 2535 _ = make(chan<- int) 2536 _ = make(Send) 2537 _ = make(Recv) 2538 } 2539 ` 2540 _, err := igop.RunFile("main.go", src, nil, 0) 2541 if err != nil { 2542 t.Fatal(err) 2543 } 2544 } 2545 2546 func TestNoStrictMode(t *testing.T) { 2547 src := `package main 2548 import "fmt" 2549 2550 func f() int 2551 2552 func main() { 2553 var a int 2554 println(100) 2555 } 2556 ` 2557 ctx := igop.NewContext(igop.EnableNoStrict) 2558 _, err := ctx.RunFile("main.go", src, nil) 2559 if err != nil { 2560 t.Fatal(err) 2561 } 2562 } 2563 2564 func TestUserFuncConvert(t *testing.T) { 2565 src := `package main 2566 2567 import "fmt" 2568 2569 type myint int 2570 type point struct { 2571 x int 2572 y int 2573 } 2574 2575 func mytest1(n myint, pt point) myint 2576 func mytest2(n myint, pt *point) myint 2577 2578 func main() { 2579 n := mytest1(100, point{100,200}) 2580 if n != 400 { 2581 panic(fmt.Errorf("error mytest1, must 400, have %v",n)) 2582 } 2583 n = mytest2(100, &point{100,200}) 2584 if n != 30000 { 2585 panic(fmt.Errorf("error mytest2, must 30000, have %v",n)) 2586 } 2587 } 2588 ` 2589 ctx := igop.NewContext(0) 2590 igop.RegisterExternal("main.mytest1", func(n int, pt struct { 2591 x int 2592 y int 2593 }) int { 2594 return n + pt.x + pt.y 2595 }) 2596 ctx.RegisterExternal("main.mytest2", func(n int, pt *struct { 2597 x int 2598 y int 2599 }) int { 2600 return n * (pt.x + pt.y) 2601 }) 2602 _, err := ctx.RunFile("main.go", src, nil) 2603 if err != nil { 2604 t.Fatal(err) 2605 } 2606 } 2607 2608 func TestRunContext(t *testing.T) { 2609 var src string = ` 2610 package main 2611 2612 import "time" 2613 2614 func main() { 2615 println("hello world") 2616 ch := make(chan int) 2617 go func() { 2618 for i := 0; i < 10; i++ { 2619 timeout := time.After(time.Second * 1) 2620 select { 2621 case <-timeout: 2622 println("work") 2623 } 2624 } 2625 ch <- 1 2626 }() 2627 <-ch 2628 println("exit") 2629 } 2630 ` 2631 ctx := igop.NewContext(0) 2632 ctx.RunContext, _ = context.WithTimeout(context.Background(), 1e9) 2633 code, err := ctx.RunFile("main.go", src, nil) 2634 if code != 2 { 2635 t.Fatalf("exit code must 2") 2636 } 2637 t.Log("cancel context:", err) 2638 } 2639 2640 func TestReflectArray(t *testing.T) { 2641 var src = `package main 2642 2643 import ( 2644 "reflect" 2645 "fmt" 2646 ) 2647 2648 type IntArray [2]int 2649 2650 func (i IntArray) String() string { 2651 return fmt.Sprintf("(%v,%v)", i[0], i[1]) 2652 } 2653 2654 func (i *IntArray) Set(x, y int) { 2655 *(*int)(&i[0]), *(*int)(&i[1]) = x, y 2656 } 2657 2658 func (i IntArray) Get() (int, int) { 2659 return i[0], i[1] 2660 } 2661 2662 func (i IntArray) Scale(v int) IntArray { 2663 return IntArray{i[0] * v, i[1] * v} 2664 } 2665 2666 func main() { 2667 var a IntArray 2668 a.Set(100,200) 2669 b := a.Scale(5) 2670 if b[0] != 500 || b[1] != 1000 { 2671 panic("error") 2672 } 2673 typ := reflect.TypeOf((*IntArray)(nil)).Elem() 2674 v := reflect.New(typ).Elem() 2675 v.Addr().MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(100),reflect.ValueOf(200)}) 2676 x := v.MethodByName("Scale").Call([]reflect.Value{reflect.ValueOf(5)}) 2677 if x[0].Index(0).Int() != 500 || x[0].Index(1).Int() != 1000 { 2678 panic("error reflect") 2679 } 2680 } 2681 ` 2682 ctx := igop.NewContext(0) 2683 _, err := ctx.RunFile("main.go", src, nil) 2684 if err != nil { 2685 t.Fatal(err) 2686 } 2687 }