Skip to content

Commit

Permalink
Allow type-safe calls to be used in InOrder
Browse files Browse the repository at this point in the history
This modifies `InOrder` to receive variadic `any` instead of `*Call`,
allowing users to use this function with type-safe generated Calls.

This implementation uses a type assertion to check if the provided
arguments are `*Call`s or reflection to get the `*Call` when the
arguments wrap one (generated code). If neither of the two cases are
fullfiled then that argument is ignored.

Fix #70.
  • Loading branch information
EstebanOlmedo committed Sep 6, 2023
1 parent 837f20a commit bd33a98
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 1 deletion.
30 changes: 29 additions & 1 deletion gomock/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,40 @@ func (c *Call) call() []func([]any) []any {
}

// InOrder declares that the given calls should occur in order.
func InOrder(calls ...*Call) {
// Ignores every argument that isn't a *Call or wraps one.
func InOrder(args ...any) {
var calls []*Call
for i := 0; i < len(args); i++ {
if call := getCall(args[i]); call != nil {
calls = append(calls, call)
}
}
for i := 1; i < len(calls); i++ {
calls[i].After(calls[i-1])
}
}

func getCall(arg any) *Call {
if call, ok := arg.(*Call); ok {
return call
}
t := reflect.ValueOf(arg)
if t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface {
return nil
}
t = t.Elem()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !f.CanInterface() {
continue
}
if call, ok := f.Interface().(*Call); ok {
return call
}
}
return nil
}

func setSlice(arg any, v reflect.Value) {
va := reflect.ValueOf(arg)
for i := 0; i < v.Len(); i++ {
Expand Down
26 changes: 26 additions & 0 deletions gomock/call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type b struct {
foo string
}

type c struct {
*Call
}

func (testObj b) Foo() string {
return testObj.foo
}
Expand Down Expand Up @@ -616,3 +620,25 @@ func TestCall_DoAndReturn(t *testing.T) {
})
}
}

func TestInOrder(t *testing.T) {
t.Run("process only *Call or its wrappers", func(t *testing.T) {
tr1 := &mockTestReporter{}
tr2 := &mockTestReporter{}
c1 := &Call{t: tr1}
c2 := &c{Call: &Call{t: tr2}}
b := &b{foo: "bar"}
a := a{name: "Joe"}
InOrder(c1, c2) // This is the only correct relationship
InOrder("a", c1) // Should do nothing
InOrder(a, c2) // Should do nothing
InOrder(nil, c2) // Should do nothing
InOrder(b, c2) // Should do nothing
if len(c2.preReqs) != 1 {
t.Fatalf("expected 1 preReq in c2, found %d", len(c2.preReqs))
}
if len(c1.preReqs) != 0 {
t.Fatalf("expected 0 preReq in c1, found %d", len(c1.preReqs))
}
})
}
14 changes: 14 additions & 0 deletions mockgen/internal/tests/typed_inorder/input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package typed_inorder

//go:generate mockgen -package typed_inorder -source=input.go -destination=mock.go -typed
type Animal interface {
GetSound() string
Feed(string) error
}

func Interact(a Animal, food string) (string, error){
if err := a.Feed(food); err != nil {
return "", err
}
return a.GetSound(), nil
}
26 changes: 26 additions & 0 deletions mockgen/internal/tests/typed_inorder/input_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package typed_inorder

import (
"testing"
"fmt"
"go.uber.org/mock/gomock"
)

func TestInteract(t * testing.T) {
ctrl := gomock.NewController(t)

mockAnimal := NewMockAnimal(ctrl)
gomock.InOrder(
mockAnimal.EXPECT().Feed("burguir").DoAndReturn(func(s string) error {
if s != "chocolate" {
return nil
}
return fmt.Errorf("Dogs can't eat chocolate!")
}),
mockAnimal.EXPECT().GetSound().Return("Woof!"),
)
_, err := Interact(mockAnimal, "burguir")
if err != nil {
t.Fatalf("sad")
}
}
114 changes: 114 additions & 0 deletions mockgen/internal/tests/typed_inorder/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bd33a98

Please sign in to comment.