github.com/onsi/gomega@v1.32.0/matchers/be_sent_matcher.go (about) 1 // untested sections: 3 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 }