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  }