github.com/onsi/gomega@v1.32.0/matchers/receive_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 ReceiveMatcher struct {
    13  	Arg           interface{}
    14  	receivedValue reflect.Value
    15  	channelClosed bool
    16  }
    17  
    18  func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err error) {
    19  	if !isChan(actual) {
    20  		return false, fmt.Errorf("ReceiveMatcher expects a channel.  Got:\n%s", format.Object(actual, 1))
    21  	}
    22  
    23  	channelType := reflect.TypeOf(actual)
    24  	channelValue := reflect.ValueOf(actual)
    25  
    26  	if channelType.ChanDir() == reflect.SendDir {
    27  		return false, fmt.Errorf("ReceiveMatcher matcher cannot be passed a send-only channel.  Got:\n%s", format.Object(actual, 1))
    28  	}
    29  
    30  	var subMatcher omegaMatcher
    31  	var hasSubMatcher bool
    32  
    33  	if matcher.Arg != nil {
    34  		subMatcher, hasSubMatcher = (matcher.Arg).(omegaMatcher)
    35  		if !hasSubMatcher {
    36  			argType := reflect.TypeOf(matcher.Arg)
    37  			if argType.Kind() != reflect.Ptr {
    38  				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))
    39  			}
    40  		}
    41  	}
    42  
    43  	winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
    44  		{Dir: reflect.SelectRecv, Chan: channelValue},
    45  		{Dir: reflect.SelectDefault},
    46  	})
    47  
    48  	var closed bool
    49  	var didReceive bool
    50  	if winnerIndex == 0 {
    51  		closed = !open
    52  		didReceive = open
    53  	}
    54  	matcher.channelClosed = closed
    55  
    56  	if closed {
    57  		return false, nil
    58  	}
    59  
    60  	if hasSubMatcher {
    61  		if didReceive {
    62  			matcher.receivedValue = value
    63  			return subMatcher.Match(matcher.receivedValue.Interface())
    64  		}
    65  		return false, nil
    66  	}
    67  
    68  	if didReceive {
    69  		if matcher.Arg != nil {
    70  			outValue := reflect.ValueOf(matcher.Arg)
    71  
    72  			if value.Type().AssignableTo(outValue.Elem().Type()) {
    73  				outValue.Elem().Set(value)
    74  				return true, nil
    75  			}
    76  			if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
    77  				outValue.Elem().Set(value.Elem())
    78  				return true, nil
    79  			} else {
    80  				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))
    81  			}
    82  
    83  		}
    84  
    85  		return true, nil
    86  	}
    87  	return false, nil
    88  }
    89  
    90  func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) {
    91  	subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)
    92  
    93  	closedAddendum := ""
    94  	if matcher.channelClosed {
    95  		closedAddendum = " The channel is closed."
    96  	}
    97  
    98  	if hasSubMatcher {
    99  		if matcher.receivedValue.IsValid() {
   100  			return subMatcher.FailureMessage(matcher.receivedValue.Interface())
   101  		}
   102  		return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
   103  	}
   104  	return format.Message(actual, "to receive something."+closedAddendum)
   105  }
   106  
   107  func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) {
   108  	subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)
   109  
   110  	closedAddendum := ""
   111  	if matcher.channelClosed {
   112  		closedAddendum = " The channel is closed."
   113  	}
   114  
   115  	if hasSubMatcher {
   116  		if matcher.receivedValue.IsValid() {
   117  			return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface())
   118  		}
   119  		return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
   120  	}
   121  	return format.Message(actual, "not to receive anything."+closedAddendum)
   122  }
   123  
   124  func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
   125  	if !isChan(actual) {
   126  		return false
   127  	}
   128  
   129  	return !matcher.channelClosed
   130  }