receive_matcher.go 3.4 KB

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