...
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
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
40 var param reflect.Value
41 if actual != nil && reflect.TypeOf(actual).AssignableTo(m.predicateArgType) {
42
43 param = reflect.ValueOf(actual)
44
45 } else if actual == nil && m.predicateArgType.Kind() == reflect.Interface {
46
47
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
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 }
67
View as plain text