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 }