|  | package matchers | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "reflect" | 
|  |  | 
|  | "github.com/onsi/gomega/format" | 
|  | ) | 
|  |  | 
|  | type BeSentMatcher struct { | 
|  | Arg           interface{} | 
|  | channelClosed bool | 
|  | } | 
|  |  | 
|  | func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error) { | 
|  | if !isChan(actual) { | 
|  | return false, fmt.Errorf("BeSent expects a channel.  Got:\n%s", format.Object(actual, 1)) | 
|  | } | 
|  |  | 
|  | channelType := reflect.TypeOf(actual) | 
|  | channelValue := reflect.ValueOf(actual) | 
|  |  | 
|  | if channelType.ChanDir() == reflect.RecvDir { | 
|  | return false, fmt.Errorf("BeSent matcher cannot be passed a receive-only channel.  Got:\n%s", format.Object(actual, 1)) | 
|  | } | 
|  |  | 
|  | argType := reflect.TypeOf(matcher.Arg) | 
|  | assignable := argType.AssignableTo(channelType.Elem()) | 
|  |  | 
|  | if !assignable { | 
|  | 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)) | 
|  | } | 
|  |  | 
|  | argValue := reflect.ValueOf(matcher.Arg) | 
|  |  | 
|  | defer func() { | 
|  | if e := recover(); e != nil { | 
|  | success = false | 
|  | err = fmt.Errorf("Cannot send to a closed channel") | 
|  | matcher.channelClosed = true | 
|  | } | 
|  | }() | 
|  |  | 
|  | winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{ | 
|  | reflect.SelectCase{Dir: reflect.SelectSend, Chan: channelValue, Send: argValue}, | 
|  | reflect.SelectCase{Dir: reflect.SelectDefault}, | 
|  | }) | 
|  |  | 
|  | var didSend bool | 
|  | if winnerIndex == 0 { | 
|  | didSend = true | 
|  | } | 
|  |  | 
|  | return didSend, nil | 
|  | } | 
|  |  | 
|  | func (matcher *BeSentMatcher) FailureMessage(actual interface{}) (message string) { | 
|  | return format.Message(actual, "to send:", matcher.Arg) | 
|  | } | 
|  |  | 
|  | func (matcher *BeSentMatcher) NegatedFailureMessage(actual interface{}) (message string) { | 
|  | return format.Message(actual, "not to send:", matcher.Arg) | 
|  | } | 
|  |  | 
|  | func (matcher *BeSentMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { | 
|  | if !isChan(actual) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | return !matcher.channelClosed | 
|  | } |