...
1 package matchers
2
3 import (
4 "fmt"
5 "reflect"
6
7 "github.com/onsi/gomega/types"
8 )
9
10 type WithTransformMatcher struct {
11
12 Transform interface{}
13 Matcher types.GomegaMatcher
14
15
16 transformArgType reflect.Type
17
18
19 transformedValue interface{}
20 }
21
22
23 var errorT = reflect.TypeOf((*error)(nil)).Elem()
24
25 func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher) *WithTransformMatcher {
26 if transform == nil {
27 panic("transform function cannot be nil")
28 }
29 txType := reflect.TypeOf(transform)
30 if txType.NumIn() != 1 {
31 panic("transform function must have 1 argument")
32 }
33 if numout := txType.NumOut(); numout != 1 {
34 if numout != 2 || !txType.Out(1).AssignableTo(errorT) {
35 panic("transform function must either have 1 return value, or 1 return value plus 1 error value")
36 }
37 }
38
39 return &WithTransformMatcher{
40 Transform: transform,
41 Matcher: matcher,
42 transformArgType: reflect.TypeOf(transform).In(0),
43 }
44 }
45
46 func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) {
47
48 var param reflect.Value
49 if actual != nil && reflect.TypeOf(actual).AssignableTo(m.transformArgType) {
50
51 param = reflect.ValueOf(actual)
52
53 } else if actual == nil && m.transformArgType.Kind() == reflect.Interface {
54
55
56 param = reflect.Zero(m.transformArgType)
57
58 } else {
59 return false, fmt.Errorf("Transform function expects '%s' but we have '%T'", m.transformArgType, actual)
60 }
61
62
63 fn := reflect.ValueOf(m.Transform)
64 result := fn.Call([]reflect.Value{param})
65 if len(result) == 2 {
66 if !result[1].IsNil() {
67 return false, fmt.Errorf("Transform function failed: %s", result[1].Interface().(error).Error())
68 }
69 }
70 m.transformedValue = result[0].Interface()
71
72 return m.Matcher.Match(m.transformedValue)
73 }
74
75 func (m *WithTransformMatcher) FailureMessage(_ interface{}) (message string) {
76 return m.Matcher.FailureMessage(m.transformedValue)
77 }
78
79 func (m *WithTransformMatcher) NegatedFailureMessage(_ interface{}) (message string) {
80 return m.Matcher.NegatedFailureMessage(m.transformedValue)
81 }
82
83 func (m *WithTransformMatcher) MatchMayChangeInTheFuture(_ interface{}) bool {
84
85
86
87
88
89 return types.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue)
90 }
91
View as plain text