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  }