You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.4 KiB

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