github.com/onsi/gomega@v1.32.0/matchers/satisfy_matcher.go (about) 1 package matchers 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/onsi/gomega/format" 8 ) 9 10 type SatisfyMatcher struct { 11 Predicate interface{} 12 13 // cached type 14 predicateArgType reflect.Type 15 } 16 17 func NewSatisfyMatcher(predicate interface{}) *SatisfyMatcher { 18 if predicate == nil { 19 panic("predicate cannot be nil") 20 } 21 predicateType := reflect.TypeOf(predicate) 22 if predicateType.Kind() != reflect.Func { 23 panic("predicate must be a function") 24 } 25 if predicateType.NumIn() != 1 { 26 panic("predicate must have 1 argument") 27 } 28 if predicateType.NumOut() != 1 || predicateType.Out(0).Kind() != reflect.Bool { 29 panic("predicate must return bool") 30 } 31 32 return &SatisfyMatcher{ 33 Predicate: predicate, 34 predicateArgType: predicateType.In(0), 35 } 36 } 37 38 func (m *SatisfyMatcher) Match(actual interface{}) (success bool, err error) { 39 // prepare a parameter to pass to the predicate 40 var param reflect.Value 41 if actual != nil && reflect.TypeOf(actual).AssignableTo(m.predicateArgType) { 42 // The dynamic type of actual is compatible with the predicate argument. 43 param = reflect.ValueOf(actual) 44 45 } else if actual == nil && m.predicateArgType.Kind() == reflect.Interface { 46 // The dynamic type of actual is unknown, so there's no way to make its 47 // reflect.Value. Create a nil of the predicate argument, which is known. 48 param = reflect.Zero(m.predicateArgType) 49 50 } else { 51 return false, fmt.Errorf("predicate expects '%s' but we have '%T'", m.predicateArgType, actual) 52 } 53 54 // call the predicate with `actual` 55 fn := reflect.ValueOf(m.Predicate) 56 result := fn.Call([]reflect.Value{param}) 57 return result[0].Bool(), nil 58 } 59 60 func (m *SatisfyMatcher) FailureMessage(actual interface{}) (message string) { 61 return format.Message(actual, "to satisfy predicate", m.Predicate) 62 } 63 64 func (m *SatisfyMatcher) NegatedFailureMessage(actual interface{}) (message string) { 65 return format.Message(actual, "to not satisfy predicate", m.Predicate) 66 }