1 package matchers_test
2
3 import (
4 "time"
5
6 . "github.com/onsi/ginkgo/v2"
7 . "github.com/onsi/gomega"
8 . "github.com/onsi/gomega/matchers"
9 )
10
11 type kungFuActor interface {
12 DrunkenMaster() bool
13 }
14
15 type jackie struct {
16 name string
17 }
18
19 func (j *jackie) DrunkenMaster() bool {
20 return true
21 }
22
23 type someError struct{ s string }
24
25 func (e *someError) Error() string { return e.s }
26
27 var _ = Describe("ReceiveMatcher", func() {
28 Context("with no argument", func() {
29 Context("for a buffered channel", func() {
30 It("should succeed", func() {
31 channel := make(chan bool, 1)
32
33 Expect(channel).ShouldNot(Receive())
34
35 channel <- true
36
37 Expect(channel).Should(Receive())
38 })
39 })
40
41 Context("for an unbuffered channel", func() {
42 It("should succeed (eventually)", func() {
43 channel := make(chan bool)
44
45 Expect(channel).ShouldNot(Receive())
46
47 go func() {
48 time.Sleep(10 * time.Millisecond)
49 channel <- true
50 }()
51
52 Eventually(channel).Should(Receive())
53 })
54 })
55 })
56
57 Context("with too many arguments", func() {
58 It("should error", func() {
59 channel := make(chan bool, 1)
60 var actual bool
61
62 channel <- true
63
64 success, err := (&ReceiveMatcher{Args: []interface{}{
65 &actual,
66 Equal(true),
67 42,
68 }}).Match(channel)
69 Expect(success).To(BeFalse())
70 Expect(err).To(HaveOccurred())
71 })
72 })
73
74 Context("with swapped arguments", func() {
75 It("should error", func() {
76 channel := make(chan bool, 1)
77 var actual bool
78
79 channel <- true
80
81 success, err := (&ReceiveMatcher{Args: []interface{}{
82 Equal(true),
83 &actual,
84 }}).Match(channel)
85 Expect(success).To(BeFalse())
86 Expect(err).To(HaveOccurred())
87 })
88 })
89
90 Context("with a pointer argument", func() {
91 Context("of the correct type", func() {
92 When("the channel has an interface type", func() {
93 It("should write the value received on the channel to the pointer", func() {
94 channel := make(chan error, 1)
95
96 var value *someError
97
98 Ω(channel).ShouldNot(Receive(&value))
99 Ω(value).Should(BeZero())
100
101 channel <- &someError{"boooom!"}
102
103 Ω(channel).Should(Receive(&value))
104 Ω(value).Should(MatchError("boooom!"))
105 })
106 })
107 })
108
109 Context("of the correct type", func() {
110 It("should write the value received on the channel to the pointer", func() {
111 channel := make(chan int, 1)
112
113 var value int
114
115 Expect(channel).ShouldNot(Receive(&value))
116 Expect(value).Should(BeZero())
117
118 channel <- 17
119
120 Expect(channel).Should(Receive(&value))
121 Expect(value).Should(Equal(17))
122 })
123 })
124
125 Context("to various types of objects", func() {
126 It("should work", func() {
127
128 stringChan := make(chan string, 1)
129 stringChan <- "foo"
130
131 var s string
132 Expect(stringChan).Should(Receive(&s))
133 Expect(s).Should(Equal("foo"))
134
135
136 sliceChan := make(chan []bool, 1)
137 sliceChan <- []bool{true, true, false}
138
139 var sl []bool
140 Expect(sliceChan).Should(Receive(&sl))
141 Expect(sl).Should(Equal([]bool{true, true, false}))
142
143
144 chanChan := make(chan chan bool, 1)
145 c := make(chan bool)
146 chanChan <- c
147
148 var receivedC chan bool
149 Expect(chanChan).Should(Receive(&receivedC))
150 Expect(receivedC).Should(Equal(c))
151
152
153 jackieChan := make(chan kungFuActor, 1)
154 aJackie := &jackie{name: "Jackie Chan"}
155 jackieChan <- aJackie
156
157 var theJackie kungFuActor
158 Expect(jackieChan).Should(Receive(&theJackie))
159 Expect(theJackie).Should(Equal(aJackie))
160 })
161 })
162
163 Context("of the wrong type", func() {
164 It("should error", func() {
165 channel := make(chan int, 1)
166 channel <- 10
167
168 var incorrectType bool
169
170 success, err := (&ReceiveMatcher{Args: []interface{}{&incorrectType}}).Match(channel)
171 Expect(success).Should(BeFalse())
172 Expect(err).Should(HaveOccurred())
173
174 var notAPointer int
175 success, err = (&ReceiveMatcher{Args: []interface{}{notAPointer}}).Match(channel)
176 Expect(success).Should(BeFalse())
177 Expect(err).Should(HaveOccurred())
178 })
179 })
180 })
181
182 Context("with a matcher", func() {
183 It("should defer to the underlying matcher", func() {
184 intChannel := make(chan int, 1)
185 intChannel <- 3
186 Expect(intChannel).Should(Receive(Equal(3)))
187
188 intChannel <- 2
189 Expect(intChannel).ShouldNot(Receive(Equal(3)))
190
191 stringChannel := make(chan []string, 1)
192 stringChannel <- []string{"foo", "bar", "baz"}
193 Expect(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo"))))
194
195 stringChannel <- []string{"foo", "bar", "baz"}
196 Expect(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago"))))
197 })
198
199 It("should defer to the underlying matcher for the message", func() {
200 matcher := Receive(Equal(3))
201 channel := make(chan int, 1)
202 channel <- 2
203 matcher.Match(channel)
204 Expect(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 2\s+to equal\s+<int>: 3`))
205
206 channel <- 3
207 matcher.Match(channel)
208 Expect(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 3\s+not to equal\s+<int>: 3`))
209 })
210
211 It("should work just fine with Eventually", func() {
212 stringChannel := make(chan string)
213
214 go func() {
215 time.Sleep(5 * time.Millisecond)
216 stringChannel <- "A"
217 time.Sleep(5 * time.Millisecond)
218 stringChannel <- "B"
219 }()
220
221 Eventually(stringChannel).Should(Receive(Equal("B")))
222 })
223
224 Context("if the matcher errors", func() {
225 It("should error", func() {
226 channel := make(chan int, 1)
227 channel <- 3
228 success, err := (&ReceiveMatcher{Args: []interface{}{ContainSubstring("three")}}).Match(channel)
229 Expect(success).Should(BeFalse())
230 Expect(err).Should(HaveOccurred())
231 })
232 })
233
234 Context("if nothing is received", func() {
235 It("should fail", func() {
236 channel := make(chan int, 1)
237 success, err := (&ReceiveMatcher{Args: []interface{}{Equal(1)}}).Match(channel)
238 Expect(success).Should(BeFalse())
239 Expect(err).ShouldNot(HaveOccurred())
240 })
241 })
242 })
243
244 Context("with a pointer and a matcher argument", func() {
245 It("should succeed", func() {
246 channel := make(chan bool, 1)
247 channel <- true
248
249 var received bool
250
251 Expect(channel).Should(Receive(&received, Equal(true)))
252 Expect(received).Should(BeTrue())
253 })
254 })
255
256 Context("When actual is a *closed* channel", func() {
257 Context("for a buffered channel", func() {
258 It("should work until it hits the end of the buffer", func() {
259 channel := make(chan bool, 1)
260 channel <- true
261
262 close(channel)
263
264 Expect(channel).Should(Receive())
265 Expect(channel).ShouldNot(Receive())
266 })
267 })
268
269 Context("for an unbuffered channel", func() {
270 It("should always fail", func() {
271 channel := make(chan bool)
272 close(channel)
273
274 Expect(channel).ShouldNot(Receive())
275 })
276 })
277 })
278
279 Context("When actual is a send-only channel", func() {
280 It("should error", func() {
281 channel := make(chan bool)
282
283 var writerChannel chan<- bool
284 writerChannel = channel
285
286 success, err := (&ReceiveMatcher{}).Match(writerChannel)
287 Expect(success).Should(BeFalse())
288 Expect(err).Should(HaveOccurred())
289 })
290 })
291
292 When("acutal is a non-channel", func() {
293 It("should error", func() {
294 var nilChannel chan bool
295
296 success, err := (&ReceiveMatcher{}).Match(nilChannel)
297 Expect(success).Should(BeFalse())
298 Expect(err).Should(HaveOccurred())
299
300 success, err = (&ReceiveMatcher{}).Match(nil)
301 Expect(success).Should(BeFalse())
302 Expect(err).Should(HaveOccurred())
303
304 success, err = (&ReceiveMatcher{}).Match(3)
305 Expect(success).Should(BeFalse())
306 Expect(err).Should(HaveOccurred())
307 })
308 })
309
310 Describe("when used with eventually and a custom matcher", func() {
311 It("should return the matcher's error when a failing value is received on the channel, instead of the must receive something failure", func() {
312 failures := InterceptGomegaFailures(func() {
313 c := make(chan string)
314 Eventually(c, 0.01).Should(Receive(Equal("hello")))
315 })
316 Expect(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something."))
317
318 failures = InterceptGomegaFailures(func() {
319 c := make(chan string, 1)
320 c <- "hi"
321 Eventually(c, 0.01).Should(Receive(Equal("hello")))
322 })
323 Expect(failures[0]).Should(ContainSubstring("<string>: hello"))
324 })
325 })
326
327 Describe("Bailing early", func() {
328 It("should bail early when passed a closed channel", func() {
329 c := make(chan bool)
330 close(c)
331
332 t := time.Now()
333 failures := InterceptGomegaFailures(func() {
334 Eventually(c).Should(Receive())
335 })
336 Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
337 Expect(failures).Should(HaveLen(1))
338 })
339
340 It("should bail early when passed a non-channel", func() {
341 t := time.Now()
342 failures := InterceptGomegaFailures(func() {
343 Eventually(3).Should(Receive())
344 })
345 Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
346 Expect(failures).Should(HaveLen(1))
347 })
348 })
349 })
350
View as plain text