github.com/switchupcb/yaegi@v0.10.2/interp/interp_export_test.go (about) 1 package interp_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/switchupcb/yaegi/interp" 8 ) 9 10 type Helloer interface { 11 Hello() 12 } 13 14 func Hi(h Helloer) { 15 println("In Hi:") 16 h.Hello() 17 } 18 19 // A Wrap represents the wrapper which allows to use objects created by 20 // the interpreter as Go interfaces (despite limitations in reflect which 21 // forbid dynamic method creation). 22 // 23 // All the struct fields are functions, where the fied name corresponds to 24 // the method name prefixed by "Do". The function signature must be the 25 // same as the interface one. 26 // 27 // A corresponding Wrap method Xyz which satisfies the interface must exist and 28 // must invoke the DoXyz function. 29 // 30 // To be usable, the interpreter should return a Wrap instance with the relevant 31 // function fields filled. The application can then invoke methods on it. 32 // The method calls will be forwarded to the interpreter. 33 // 34 // Only the Wrap type definition needs to be exported to the interpreter (not 35 // the interfaces and methods definitions). 36 // 37 type Wrap struct { 38 DoHello func() // related to the Hello() method. 39 // Other interface method wrappers... 40 } 41 42 func (w Wrap) Hello() { w.DoHello() } 43 44 func TestExportsSemantics(t *testing.T) { 45 Foo := &struct{}{} 46 47 t.Run("Correct", func(t *testing.T) { 48 t.Skip() 49 i := interp.New(interp.Options{}) 50 51 err := i.Use(interp.Exports{ 52 "foo/foo": {"Foo": reflect.ValueOf(Foo)}, 53 }) 54 if err != nil { 55 t.Fatal(err) 56 } 57 i.ImportUsed() 58 59 res, err := i.Eval("foo.Foo") 60 if err != nil { 61 t.Fatal(err) 62 } 63 if res.Interface() != Foo { 64 t.Fatalf("expected foo.Foo to equal local Foo") 65 } 66 }) 67 68 t.Run("Incorrect", func(t *testing.T) { 69 i := interp.New(interp.Options{}) 70 71 err := i.Use(interp.Exports{ 72 "foo": {"Foo": reflect.ValueOf(Foo)}, 73 }) 74 if err == nil { 75 t.Fatal("expected error for incorrect Use semantics") 76 } 77 }) 78 } 79 80 func TestInterface(t *testing.T) { 81 i := interp.New(interp.Options{}) 82 // export the Wrap type to the interpreter under virtual "wrap" package 83 err := i.Use(interp.Exports{ 84 "wrap/wrap": { 85 "Wrap": reflect.ValueOf((*Wrap)(nil)), 86 }, 87 }) 88 if err != nil { 89 t.Fatal(err) 90 } 91 92 eval(t, i, ` 93 import "wrap" 94 95 type MyInt int 96 97 func (m MyInt) Hello() { println("hello from Myint", m) } 98 99 func NewMyInt(i int) wrap.Wrap { 100 m := MyInt(i) 101 return wrap.Wrap{DoHello: m.Hello} 102 } 103 `) 104 NewMyInt := eval(t, i, "NewMyInt").Interface().(func(int) Wrap) 105 w := NewMyInt(4) 106 Hi(w) 107 } 108 109 type T struct{} 110 111 func (t T) Bar(s ...string) {} 112 113 func TestCallBinVariadicMethod(t *testing.T) { 114 i := interp.New(interp.Options{}) 115 err := i.Use(interp.Exports{ 116 "mypkg/mypkg": { 117 "T": reflect.ValueOf((*T)(nil)), 118 }, 119 }) 120 if err != nil { 121 t.Fatal(err) 122 } 123 eval(t, i, ` 124 package p 125 126 import "mypkg" 127 128 func Foo(x mypkg.T) { x.Bar("s") } 129 `) 130 v := eval(t, i, "p.Foo") 131 bar := v.Interface().(func(t T)) 132 bar(T{}) 133 }