...
1
2
3 package matchers
4
5 import (
6 "fmt"
7 "reflect"
8
9 "github.com/onsi/gomega/format"
10 )
11
12 type BeSentMatcher struct {
13 Arg interface{}
14 channelClosed bool
15 }
16
17 func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error) {
18 if !isChan(actual) {
19 return false, fmt.Errorf("BeSent expects a channel. Got:\n%s", format.Object(actual, 1))
20 }
21
22 channelType := reflect.TypeOf(actual)
23 channelValue := reflect.ValueOf(actual)
24
25 if channelType.ChanDir() == reflect.RecvDir {
26 return false, fmt.Errorf("BeSent matcher cannot be passed a receive-only channel. Got:\n%s", format.Object(actual, 1))
27 }
28
29 argType := reflect.TypeOf(matcher.Arg)
30 assignable := argType.AssignableTo(channelType.Elem())
31
32 if !assignable {
33 return false, fmt.Errorf("Cannot pass:\n%s to the channel:\n%s\nThe types don't match.", format.Object(matcher.Arg, 1), format.Object(actual, 1))
34 }
35
36 argValue := reflect.ValueOf(matcher.Arg)
37
38 defer func() {
39 if e := recover(); e != nil {
40 success = false
41 err = fmt.Errorf("Cannot send to a closed channel")
42 matcher.channelClosed = true
43 }
44 }()
45
46 winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{
47 {Dir: reflect.SelectSend, Chan: channelValue, Send: argValue},
48 {Dir: reflect.SelectDefault},
49 })
50
51 var didSend bool
52 if winnerIndex == 0 {
53 didSend = true
54 }
55
56 return didSend, nil
57 }
58
59 func (matcher *BeSentMatcher) FailureMessage(actual interface{}) (message string) {
60 return format.Message(actual, "to send:", matcher.Arg)
61 }
62
63 func (matcher *BeSentMatcher) NegatedFailureMessage(actual interface{}) (message string) {
64 return format.Message(actual, "not to send:", matcher.Arg)
65 }
66
67 func (matcher *BeSentMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
68 if !isChan(actual) {
69 return false
70 }
71
72 return !matcher.channelClosed
73 }
74
View as plain text