github.com/traefik/yaegi@v0.15.1/interp/interp_export_test.go (about) 1 package interp_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/traefik/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 type Wrap struct { 37 DoHello func() // related to the Hello() method. 38 // Other interface method wrappers... 39 } 40 41 func (w Wrap) Hello() { w.DoHello() } 42 43 func TestExportsSemantics(t *testing.T) { 44 Foo := &struct{}{} 45 46 t.Run("Correct", func(t *testing.T) { 47 t.Skip() 48 i := interp.New(interp.Options{}) 49 50 err := i.Use(interp.Exports{ 51 "foo/foo": {"Foo": reflect.ValueOf(Foo)}, 52 }) 53 if err != nil { 54 t.Fatal(err) 55 } 56 i.ImportUsed() 57 58 res, err := i.Eval("foo.Foo") 59 if err != nil { 60 t.Fatal(err) 61 } 62 if res.Interface() != Foo { 63 t.Fatalf("expected foo.Foo to equal local Foo") 64 } 65 }) 66 67 t.Run("Incorrect", func(t *testing.T) { 68 i := interp.New(interp.Options{}) 69 70 err := i.Use(interp.Exports{ 71 "foo": {"Foo": reflect.ValueOf(Foo)}, 72 }) 73 if err == nil { 74 t.Fatal("expected error for incorrect Use semantics") 75 } 76 }) 77 } 78 79 func TestInterface(t *testing.T) { 80 i := interp.New(interp.Options{}) 81 // export the Wrap type to the interpreter under virtual "wrap" package 82 err := i.Use(interp.Exports{ 83 "wrap/wrap": { 84 "Wrap": reflect.ValueOf((*Wrap)(nil)), 85 }, 86 }) 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 eval(t, i, ` 92 import "wrap" 93 94 type MyInt int 95 96 func (m MyInt) Hello() { println("hello from Myint", m) } 97 98 func NewMyInt(i int) wrap.Wrap { 99 m := MyInt(i) 100 return wrap.Wrap{DoHello: m.Hello} 101 } 102 `) 103 NewMyInt := eval(t, i, "NewMyInt").Interface().(func(int) Wrap) 104 w := NewMyInt(4) 105 Hi(w) 106 } 107 108 type T struct{} 109 110 func (t T) Bar(s ...string) {} 111 112 func TestCallBinVariadicMethod(t *testing.T) { 113 i := interp.New(interp.Options{}) 114 err := i.Use(interp.Exports{ 115 "mypkg/mypkg": { 116 "T": reflect.ValueOf((*T)(nil)), 117 }, 118 }) 119 if err != nil { 120 t.Fatal(err) 121 } 122 eval(t, i, ` 123 package p 124 125 import "mypkg" 126 127 func Foo(x mypkg.T) { x.Bar("s") } 128 `) 129 v := eval(t, i, "p.Foo") 130 bar := v.Interface().(func(t T)) 131 bar(T{}) 132 }