Skip to content

Instantly share code, notes, and snippets.

@ianfoo
Created December 10, 2018 23:50
Show Gist options
  • Select an option

  • Save ianfoo/fc7e37b837de883159a258581785e71f to your computer and use it in GitHub Desktop.

Select an option

Save ianfoo/fc7e37b837de883159a258581785e71f to your computer and use it in GitHub Desktop.
Gomock matcher for a set of arguments
package matchers
import (
"fmt"
"reflect"
)
// SetMatcher matches values from a set of options. When an option is matched,
// it is removed from the set of acceptable options and will not be matched
// again on following calls to Match. This matcher can be useful when a number
// of calls will be made with specific arguments, but the order is not known,
// and a minimum and/or maximum number needs to be set.
//
// For example, given a set of three concurrent calls, where the arguments for
// each call are known and different for at least one of the calls, and it is
// known that at least one call will be made, but not known how many will end
// up called (e.g., the first call triggers an error that should cancel
// processing, but more calls may have been made before the cancellation).
// Without this matcher, a test writer can either match arguments explicitly
// but not test for the number of invocations:
//
// mocked.EXPECT().Method("arg1").AnyTimes()
// mocked.EXPECT().Method("arg2").AnyTimes()
// mocked.EXPECT().Method("arg3").AnyTimes()
//
// or can test for the number of invocations, but not the arguments:
//
// mocked.EXPECT().Method(gomock.Any()).MaxTimes(1).MinTimes(3)
//
// With SetMatcher, both can be tested:
//
// mocked.EXPECT().Method(NewSetMatcher("arg1", "arg2", "arg3")).MaxTimes(3).MinTimes(1)
type SetMatcher struct {
args []interface{}
}
// NewSetMatcher creates a new SetMatcher.
func NewSetMatcher(args ...interface{}) *SetMatcher {
return &SetMatcher{args: args}
}
// Matches implements https://godoc.org/github.com/golang/mock/gomock#Matcher
// Matches method.
func (sm *SetMatcher) Matches(x interface{}) bool {
for i, y := range sm.args {
if reflect.DeepEqual(x, y) {
sm.args = append(sm.args[:i], sm.args[i+1:]...)
return true
}
}
return false
}
// String implements https://godoc.org/github.com/golang/mock/gomock#Matcher
// String method.
func (sm SetMatcher) String() string {
switch len(sm.args) {
case 0:
return "<no possible match>"
case 1:
return fmt.Sprintf("%v", sm.args[0])
default:
return fmt.Sprintf("any of %v", sm.args)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment