Passing a member function as an argument compile error - go

I'm modeling the state machine implementation outlined in this talk by Rob Pike https://www.youtube.com/watch?v=HxaD_trXwRE&t=1830s
and I'm not able to get it to compile. I've provided a small sample that fails.
The call: m := New(foo)
fails with
./main.go:31:11: undefined: foo
I've tried
m := New(M.foo)
m := New(foo(*M))
I don't know the proper syntax for this.
package main
type StateFunc func(*M) StateFunc
type M struct {
start StateFunc
}
func New(start StateFunc) *M {
return &M{
start: start,
}
}
func (m *M) foo() StateFunc {
return nil
}
func (m *M) Start() {
go m.run()
}
func (m *M) run() {
state := m.start
for state != nil {
state = state(m)
}
}
func main() {
m := New(foo)
}
I would expect it to compile but I don't know the proper syntax to make this work.

the method (m *M) foo() doesn't match the signature of type StateFunc func(*M) StateFunc
foo is a method, it has a receiver *M, you can't use it without the receiver.
my suggestion is to modify foo:
func foo(*M) StateFunc {
return nil
}

Related

Can I mock a function with pointer parameter which need to be used

Let's say we have a library provide a function Double to double the integer, we use pointer i to get the result value not by return:
package api
type Action interface {
Double(i *int) error
}
type NUM struct{}
func (n NUM) Double(i *int) error {
*i *= 2
return nil
}
in our main function we use this library to do our task. like this:
package app
import (
"fmt"
"github.com/hotsnow/api"
)
func main() {
j := job{a: &api.NUM{}}
d := j.task(3)
fmt.Println(3, d)
}
type job struct {
a api.Action
}
// double me
func (j job) task(i int) int {
j.a.Double(&i)
return i
}
Now we need to test the task() function, how can we get the pointer return bye mock the Double function?
Here is the test:
package app
import (
"github.com/golang/mock/gomock"
"github.com/hotsnow/mocks"
"testing"
)
func TestReq(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := mocks.NewMockAction(ctrl)
m.EXPECT().Double(gomock.Any()).Return(nil)
j := job{a: m}
got := j.task(3)
if got != 6 {
t.Errorf("got = %#v; want 6", got)
}
}
The code here: https://github.com/hotsnow/mock.git (stackoverflow branch)
you can use gomock setarg function for this
yourPackage.EXPECT().insert(&pointer).SetArg(0, newPointer)
You can achieve this with the provided Eq() matcher, which internally calls reflect.DeepEqual() on the expected and actual values; as per the documentation for this method:
Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.
Say we have a function that depends upon an interface method that takes a pointer parameter:
package resource
type ServiceRequest struct {
Name string
Owner *string // this is a pointer so it can be omitted with `nil`
}
type Model struct {
// resource model...
}
type ResourceService interface {
Fetch(req *ServiceRequest) (Model, error)
}
type getResourceHandler struct {
resourceService ResourceService
}
type GetResourceEvent struct {
Resource string
Owner *string
}
func NewResourceHandler(resourceService ResourceService) *getResourceHandler {
return &getResourceHandler{resourceService}
}
func (h *getResourceHandler) Handle(event GetResourceEvent) (Model, error) {
return h.resourceService.Fetch(&ServiceRequest{event.Resource, event.Owner})
}
We can use the Eq() matcher when setting up the expectation against our generated mock of the ResourceService interface:
package test
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/org/repo/internal/mock"
"github.com/org/repo/internal/resource"
)
func optionalString(str string) *string {
return &str
}
func Test_GetResourceHandler_ReturnsResultFromService(t *testing.T) {
resourceName := "my-resource"
owner := optionalString("Joe Bloggs")
resourceReq := &resource.ServiceRequest{resourceName, owner}
event := resource.GetResourceEvent{resourceName, owner}
model := resource.Model{ /* fields here... */ }
ctrl := gomock.NewController(t)
mockResourceService := mock.NewMockResourceService(ctrl)
handler := resource.NewResourceHandler(mockResourceService)
mockResourceService.EXPECT().Fetch(gomock.Eq(resourceReq)).Return(model, nil)
res, err := handler.Handle(event)
assert.Nil(t, err)
assert.Equal(t, model, res)
}
If you change the contents of the service request in either the test or the unit under test, you'll see that the test no longer passes. Otherwise, it will pass in spite of the test and the unit under test having their own respective pointers to separate ServiceRequest{} values.
It seems you don't have to use gomock to test the task method.
Since you have an interface, why not just create a mock implementation of the interface, for example:
type dummy struct{
callCount int
}
func (d *dummy) Double(i *int) error {
d.callCount++
return nil
}
d := dummy{}
j := job{a: &d}
got := j.task(3)
if d.callCount != 1 {
// XXX
}

Test whether a function was called

Given this struct and function:
type ExampleModule struct {
DB *database.Store
AnotherModule AnotherModuleInterface
}
func(m *ExampleModule) A (i int, id int[]) error{
err := m.AnotherModuke.SomeFunc(i, id)
}
How can I make a unit test to make sure that SomeFunc is called when I run the function A?
you can mock implementation of the interface, like
globalIndex
type Mock struct{}
func (m Mock) SomeFunc(){
globalIndex++
}
func testA(t *testing.T) {
a := ExampleModule{
AnotherModule: Mock{},
}
a.A()
assert(globalIndex == 1)
}
try testify. AssertExpectations can help you
https://github.com/stretchr/testify#mock-package

golang test spy incorrectly comparing equality

I'm in the process of learning go and am adapting a Java Game of Life example from testdouble. However, the test spy I have written incorrectly compares equality of my World struct - the test passes when it should fail, since output(world) is not being called. What am I doing incorrectly?
Test:
package gameoflife
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestZeroGenerations(t *testing.T) {
generatesSeedWorldStub := GeneratesSeedWorldStub{}
outputsWorldSpy := OutputsWorldSpy{}
conway := NewSimulatesConway(&generatesSeedWorldStub, &outputsWorldSpy)
seedWorld := World{}
conway.simulate()
correctWorld := outputsWorldSpy.wasOutputCalledWithWorld(seedWorld)
if !correctWorld {
t.Errorf("Output called with seed world, expected: %t, got: %t", true, correctWorld)
}
}
type GeneratesSeedWorldStub struct{}
func (gsw *GeneratesSeedWorldStub) generate() World {
return World{}
}
type OutputsWorldSpy struct {
outputCalledWithWorld World
}
func (ow *OutputsWorldSpy) output(world World) {
ow.outputCalledWithWorld = world
}
func (ow *OutputsWorldSpy) wasOutputCalledWithWorld(world World) bool {
return cmp.Equal(world, ow.outputCalledWithWorld)
}
Implementation:
package gameoflife
type SimulatesConway struct {
generatesSeedWorld GeneratesSeedWorld
outputsWorld OutputsWorld
}
func NewSimulatesConway(generatesSeedWorld GeneratesSeedWorld, outputsWorld OutputsWorld) SimulatesConway {
return SimulatesConway{generatesSeedWorld: generatesSeedWorld, outputsWorld: outputsWorld}
}
func (sc *SimulatesConway) simulate() {
// seedWorld := sc.generatesSeedWorld.generate()
// sc.outputsWorld.output(seedWorld)
}
type GeneratesSeedWorld interface {
generate() World
}
type OutputsWorld interface {
output(world World)
}
type World struct{}
When called outputsWorldSpy := OutputsWorldSpy{} golang assigned default value in outputsWorldSpy.outputCalledWithWorld = World{} and you assigned seedWorld := World{}. So they are same that's why test passed. If you want to handle that case, i suggest to use pointer.
type OutputsWorldSpy struct {
outputCalledWithWorld *World
}
func (ow *OutputsWorldSpy) output(world World) {
ow.outputCalledWithWorld = &world
}
func (ow *OutputsWorldSpy) wasOutputCalledWithWorld(world World) bool {
if ow.outputCalledWithWorld == nil {
return false
}
return cmp.Equal(world, *ow.outputCalledWithWorld)
}

AssertCalled always fails with testify library

I am using testify to test my code and I want to check if a function was called.
I am doing the following:
type Foo struct {
mock.Mock
}
func (m Foo) Bar() {
}
func TestFoo(t *testing.T) {
m := Foo{}
m.Bar()
m.AssertCalled(t, "Bar")
}
The error I am getting:
Error: Should be true
Messages: The "Bar" method should have been called with 0 argument(s), but was not.
mock.go:419: []
I call function "Bar" and immediately ask if it was called but it returns false.
What am I doing wrong?
What is the proper way to test if a function was called with testify?
I tried with this and works:
type Foo struct {
mock.Mock
}
func (m *Foo) Bar() {
m.Called()
}
func TestFoo(t *testing.T) {
m := &Foo{}
m.On("Bar").Return(nil)
m.Bar()
m.AssertCalled(t, "Bar")
}
As stated by Chris Drew, you've to use a receiver pointer on Bar method's declaration.
Additionally, you've to istantiate a new structure as pointer and mock the method to return a value.
Looking at the documentation of testify I think you have to explicitly call func (*Mock) Called to tell the mock object that a method has been called.
func (m *Foo) Bar() {
m.Called()
}
There are some examples in the testify tests.
Make sure it is pointer receiver NOT value receiver.
This will always have nil Calls
type Foo struct {
mock.Mock
}
func (m Foo) Bar()
m.Called()
}
This will have N number of Calls
type Foo struct {
mock.Mock
}
func (m *Foo) Bar()
m.Called()
}
As an additional solution for when you want/need to use a value receiver, though not as clean, specifying Mock as a pointer field worked for me.
type Foo struct {
m *mock.Mock
}
func (f Foo) Bar() {
f.m.Called()
}
func TestFoo(t *testing.T) {
f := Foo{m: &mock.Mock{}}
f.Bar()
f.m.AssertCalled(t, "Bar")
}

go virtual function simulation

Is there exists some trick to implement virtual functions behaviour in go ? I have the following example.
package main
import "fmt"
type A struct {
}
type B struct {
*A
}
func (this *A) Do() {
fmt.Println("IM DO")
this.DoVirtual()
}
func (this *A) DoVirtual() {
fmt.Println("IM DoVirtual Default implementation")
}
func (this *B) DoVirtual() {
fmt.Println("IM DoVirtual B implementation")
}
func main() {
a := &A{}
a.Do()
fmt.Println("----")
b := &B{}
b.DoVirtual()
b.Do() // How to make here B.DoVirtual call
}
And the last Do() call uses also default DoVirtual implementation what is actually not was I want. The reason why is it so is go lang iheritance model : this *B and this *A are different pointers in this case, but I wonder is it possible to make some simulation of such behaviour that DoVirtual in last call will be used from B class.
By the time the compiler has selected func (this *A) Do() { the enclosing B is gone, no longer accessible. Go does not support the is-a construct, only the has-a (composition). If one implements a func (this *B) Do() { it will supersede the Do() on *A. Of course, that's not really what you are wanting.
I think the best explanation of the implementation and motivation is here Less is exponentially more from Rob Pike.
my simple simulation, you can improve it with some reflect, code generation or even RPC. the main idea is add a virtual method table, and do dispatch yourself, just like c++ does.
package main
import "fmt"
type A struct {
virFunDispatcher func(funAndParams ... interface{})
}
func newA() *A{
return &A{func(funAndParams ... interface{}){
fun := funAndParams[0].(string)
switch(fun){
case "DoVirtual":
fmt.Println("IM DoVirtual Default implementation")
}
}}
}
type B struct {
*A
}
func newB() *B{
a := A{func(funAndParams ... interface{}){
fun := funAndParams[0].(string)
switch(fun){
case "DoVirtual":
fmt.Println("IM DoVirtual B implementation")
}
}}
return &B{&a}
}
func (this *A) Do() {
fmt.Println("IM DO")
this.virFunDispatcher("DoVirtual")
}
func (this *A) DoVirtual() {
fmt.Println("IM DoVirtual Default implementation")
}
func (this *B) DoVirtual() {
fmt.Println("IM DoVirtual B implementation")
}
func main() {
a := newA()
a.Do()
fmt.Println("----")
b := newB()
b.DoVirtual()
b.Do() // How to make here B.DoVirtual call
}
https://play.golang.org/p/Iw30lVOhuC

Resources