...
1
2
3 package matchers
4
5 import (
6 "errors"
7 "fmt"
8 "reflect"
9
10 "github.com/onsi/gomega/format"
11 )
12
13 type ReceiveMatcher struct {
14 Args []interface{}
15 receivedValue reflect.Value
16 channelClosed bool
17 }
18
19 func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err error) {
20 if !isChan(actual) {
21 return false, fmt.Errorf("ReceiveMatcher expects a channel. Got:\n%s", format.Object(actual, 1))
22 }
23
24 channelType := reflect.TypeOf(actual)
25 channelValue := reflect.ValueOf(actual)
26
27 if channelType.ChanDir() == reflect.SendDir {
28 return false, fmt.Errorf("ReceiveMatcher matcher cannot be passed a send-only channel. Got:\n%s", format.Object(actual, 1))
29 }
30
31 var subMatcher omegaMatcher
32 var hasSubMatcher bool
33 var resultReference interface{}
34
35
36
37
38
39
40
41 args := matcher.Args
42 if len(args) > 0 {
43 arg := args[0]
44 _, isSubMatcher := arg.(omegaMatcher)
45 if !isSubMatcher && reflect.ValueOf(arg).Kind() == reflect.Ptr {
46
47 resultReference = arg
48 args = args[1:]
49 }
50 }
51 if len(args) > 0 {
52 arg := args[0]
53 subMatcher, hasSubMatcher = arg.(omegaMatcher)
54 if !hasSubMatcher {
55
56
57 return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(arg, 1))
58 }
59
60 args = args[1:]
61 }
62 if len(args) > 0 {
63
64 return false, errors.New("Receive matcher expects at most an optional pointer and/or an optional matcher")
65 }
66
67 winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
68 {Dir: reflect.SelectRecv, Chan: channelValue},
69 {Dir: reflect.SelectDefault},
70 })
71
72 var closed bool
73 var didReceive bool
74 if winnerIndex == 0 {
75 closed = !open
76 didReceive = open
77 }
78 matcher.channelClosed = closed
79
80 if closed {
81 return false, nil
82 }
83
84 if hasSubMatcher {
85 if !didReceive {
86 return false, nil
87 }
88 matcher.receivedValue = value
89 if match, err := subMatcher.Match(matcher.receivedValue.Interface()); err != nil || !match {
90 return match, err
91 }
92
93
94 }
95
96 if didReceive {
97 if resultReference != nil {
98 outValue := reflect.ValueOf(resultReference)
99
100 if value.Type().AssignableTo(outValue.Elem().Type()) {
101 outValue.Elem().Set(value)
102 return true, nil
103 }
104 if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
105 outValue.Elem().Set(value.Elem())
106 return true, nil
107 } else {
108 return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(resultReference, 1))
109 }
110
111 }
112
113 return true, nil
114 }
115 return false, nil
116 }
117
118 func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) {
119 var matcherArg interface{}
120 if len(matcher.Args) > 0 {
121 matcherArg = matcher.Args[len(matcher.Args)-1]
122 }
123 subMatcher, hasSubMatcher := (matcherArg).(omegaMatcher)
124
125 closedAddendum := ""
126 if matcher.channelClosed {
127 closedAddendum = " The channel is closed."
128 }
129
130 if hasSubMatcher {
131 if matcher.receivedValue.IsValid() {
132 return subMatcher.FailureMessage(matcher.receivedValue.Interface())
133 }
134 return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
135 }
136 return format.Message(actual, "to receive something."+closedAddendum)
137 }
138
139 func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) {
140 var matcherArg interface{}
141 if len(matcher.Args) > 0 {
142 matcherArg = matcher.Args[len(matcher.Args)-1]
143 }
144 subMatcher, hasSubMatcher := (matcherArg).(omegaMatcher)
145
146 closedAddendum := ""
147 if matcher.channelClosed {
148 closedAddendum = " The channel is closed."
149 }
150
151 if hasSubMatcher {
152 if matcher.receivedValue.IsValid() {
153 return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface())
154 }
155 return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
156 }
157 return format.Message(actual, "not to receive anything."+closedAddendum)
158 }
159
160 func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
161 if !isChan(actual) {
162 return false
163 }
164
165 return !matcher.channelClosed
166 }
167
View as plain text