2019-09-20 10:45:13 +00:00
// untested sections: 3
2019-05-31 09:45:11 +00:00
package matchers
import (
"fmt"
"reflect"
"github.com/onsi/gomega/format"
)
type ReceiveMatcher struct {
Arg interface { }
receivedValue reflect . Value
channelClosed bool
}
func ( matcher * ReceiveMatcher ) Match ( actual interface { } ) ( success bool , err error ) {
if ! isChan ( actual ) {
return false , fmt . Errorf ( "ReceiveMatcher expects a channel. Got:\n%s" , format . Object ( actual , 1 ) )
}
channelType := reflect . TypeOf ( actual )
channelValue := reflect . ValueOf ( actual )
if channelType . ChanDir ( ) == reflect . SendDir {
return false , fmt . Errorf ( "ReceiveMatcher matcher cannot be passed a send-only channel. Got:\n%s" , format . Object ( actual , 1 ) )
}
var subMatcher omegaMatcher
var hasSubMatcher bool
if matcher . Arg != nil {
subMatcher , hasSubMatcher = ( matcher . Arg ) . ( omegaMatcher )
if ! hasSubMatcher {
argType := reflect . TypeOf ( matcher . Arg )
if argType . Kind ( ) != reflect . Ptr {
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 ( matcher . Arg , 1 ) )
}
}
}
winnerIndex , value , open := reflect . Select ( [ ] reflect . SelectCase {
{ Dir : reflect . SelectRecv , Chan : channelValue } ,
{ Dir : reflect . SelectDefault } ,
} )
var closed bool
var didReceive bool
if winnerIndex == 0 {
closed = ! open
didReceive = open
}
matcher . channelClosed = closed
if closed {
return false , nil
}
if hasSubMatcher {
if didReceive {
matcher . receivedValue = value
return subMatcher . Match ( matcher . receivedValue . Interface ( ) )
}
return false , nil
}
if didReceive {
if matcher . Arg != nil {
outValue := reflect . ValueOf ( matcher . Arg )
if value . Type ( ) . AssignableTo ( outValue . Elem ( ) . Type ( ) ) {
outValue . Elem ( ) . Set ( value )
return true , nil
}
if value . Type ( ) . Kind ( ) == reflect . Interface && value . Elem ( ) . Type ( ) . AssignableTo ( outValue . Elem ( ) . Type ( ) ) {
outValue . Elem ( ) . Set ( value . Elem ( ) )
return true , nil
} else {
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 ( matcher . Arg , 1 ) )
}
}
return true , nil
}
return false , nil
}
func ( matcher * ReceiveMatcher ) FailureMessage ( actual interface { } ) ( message string ) {
subMatcher , hasSubMatcher := ( matcher . Arg ) . ( omegaMatcher )
closedAddendum := ""
if matcher . channelClosed {
closedAddendum = " The channel is closed."
}
if hasSubMatcher {
if matcher . receivedValue . IsValid ( ) {
return subMatcher . FailureMessage ( matcher . receivedValue . Interface ( ) )
}
return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
}
return format . Message ( actual , "to receive something." + closedAddendum )
}
func ( matcher * ReceiveMatcher ) NegatedFailureMessage ( actual interface { } ) ( message string ) {
subMatcher , hasSubMatcher := ( matcher . Arg ) . ( omegaMatcher )
closedAddendum := ""
if matcher . channelClosed {
closedAddendum = " The channel is closed."
}
if hasSubMatcher {
if matcher . receivedValue . IsValid ( ) {
return subMatcher . NegatedFailureMessage ( matcher . receivedValue . Interface ( ) )
}
return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
}
return format . Message ( actual , "not to receive anything." + closedAddendum )
}
func ( matcher * ReceiveMatcher ) MatchMayChangeInTheFuture ( actual interface { } ) bool {
if ! isChan ( actual ) {
return false
}
return ! matcher . channelClosed
}