From 665220df08a50d925c1f2ffa09b0107913c40e80 Mon Sep 17 00:00:00 2001 From: Damiano Petrungaro Date: Wed, 16 Aug 2023 19:16:57 +0200 Subject: [PATCH] feat: add Cond matcher (#60) This adds `Cond`, a new `Matcher` that can match using an arbitrary function. If the function returns true for the parameter to the mock, then there's a match. --- gomock/matchers.go | 22 ++++++++++++++++++++++ gomock/matchers_test.go | 4 ++++ sample/imp4/imp4.go | 4 +++- sample/user_test.go | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/gomock/matchers.go b/gomock/matchers.go index c1edac5..bac4623 100644 --- a/gomock/matchers.go +++ b/gomock/matchers.go @@ -97,6 +97,18 @@ func (anyMatcher) String() string { return "is anything" } +type condMatcher struct { + fn func(x any) bool +} + +func (c condMatcher) Matches(x any) bool { + return c.fn(x) +} + +func (condMatcher) String() string { + return "adheres to a custom condition" +} + type eqMatcher struct { x any } @@ -280,6 +292,16 @@ func All(ms ...Matcher) Matcher { return allMatcher{ms} } // Any returns a matcher that always matches. func Any() Matcher { return anyMatcher{} } +// Cond returns a matcher that matches when the given function returns true +// after passing it the parameter to the mock function. +// This is particularly useful in case you want to match over a field of a custom struct, or dynamic logic. +// +// Example usage: +// +// Cond(func(x any){return x.(int) == 1}).Matches(1) // returns true +// Cond(func(x any){return x.(int) == 2}).Matches(1) // returns false +func Cond(fn func(x any) bool) Matcher { return condMatcher{fn} } + // Eq returns a matcher that matches on equality. // // Example usage: diff --git a/gomock/matchers_test.go b/gomock/matchers_test.go index 3966075..8de86a2 100644 --- a/gomock/matchers_test.go +++ b/gomock/matchers_test.go @@ -27,6 +27,9 @@ import ( ) type A []string +type B struct { + Name string +} func TestMatchers(t *testing.T) { type e any @@ -50,6 +53,7 @@ func TestMatchers(t *testing.T) { []e{[]string{"a", "b"}, A{"a", "b"}}, []e{[]string{"a"}, A{"b"}}, }, + {"test Cond", gomock.Cond(func(x any) bool { return x.(B).Name == "Dam" }), []e{B{Name: "Dam"}}, []e{B{Name: "Dave"}}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/sample/imp4/imp4.go b/sample/imp4/imp4.go index 30a7076..021d701 100644 --- a/sample/imp4/imp4.go +++ b/sample/imp4/imp4.go @@ -1,3 +1,5 @@ package imp_four -type Imp4 struct{} +type Imp4 struct { + Field string +} diff --git a/sample/user_test.go b/sample/user_test.go index 651e30e..55856e3 100644 --- a/sample/user_test.go +++ b/sample/user_test.go @@ -7,6 +7,7 @@ import ( "go.uber.org/mock/gomock" user "go.uber.org/mock/sample" "go.uber.org/mock/sample/imp1" + imp_four "go.uber.org/mock/sample/imp4" ) func TestRemember(t *testing.T) { @@ -193,3 +194,19 @@ func TestDoAndReturnSignature(t *testing.T) { mockIndex.Slice([]int{0}, []byte("meow")) }) } + +func TestExpectCondForeignFour(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockIndex := NewMockIndex(ctrl) + mockIndex.EXPECT().ForeignFour(gomock.Cond(func(x any) bool { + four, ok := x.(imp_four.Imp4) + if !ok { + return false + } + return four.Field == "Cool" + })) + + mockIndex.ForeignFour(imp_four.Imp4{Field: "Cool"}) +}