github.com/onsi/gomega@v1.32.0/matchers/receive_matcher_test.go (about)

     1  package matchers_test
     2  
     3  import (
     4  	"time"
     5  
     6  	. "github.com/onsi/ginkgo/v2"
     7  	. "github.com/onsi/gomega"
     8  	. "github.com/onsi/gomega/matchers"
     9  )
    10  
    11  type kungFuActor interface {
    12  	DrunkenMaster() bool
    13  }
    14  
    15  type jackie struct {
    16  	name string
    17  }
    18  
    19  func (j *jackie) DrunkenMaster() bool {
    20  	return true
    21  }
    22  
    23  type someError struct{ s string }
    24  
    25  func (e *someError) Error() string { return e.s }
    26  
    27  var _ = Describe("ReceiveMatcher", func() {
    28  	Context("with no argument", func() {
    29  		Context("for a buffered channel", func() {
    30  			It("should succeed", func() {
    31  				channel := make(chan bool, 1)
    32  
    33  				Expect(channel).ShouldNot(Receive())
    34  
    35  				channel <- true
    36  
    37  				Expect(channel).Should(Receive())
    38  			})
    39  		})
    40  
    41  		Context("for an unbuffered channel", func() {
    42  			It("should succeed (eventually)", func() {
    43  				channel := make(chan bool)
    44  
    45  				Expect(channel).ShouldNot(Receive())
    46  
    47  				go func() {
    48  					time.Sleep(10 * time.Millisecond)
    49  					channel <- true
    50  				}()
    51  
    52  				Eventually(channel).Should(Receive())
    53  			})
    54  		})
    55  	})
    56  
    57  	Context("with a pointer argument", func() {
    58  		Context("of the correct type", func() {
    59  			When("the channel has an interface type", func() {
    60  				It("should write the value received on the channel to the pointer", func() {
    61  					channel := make(chan error, 1)
    62  
    63  					var value *someError
    64  
    65  					Ω(channel).ShouldNot(Receive(&value))
    66  					Ω(value).Should(BeZero())
    67  
    68  					channel <- &someError{"boooom!"}
    69  
    70  					Ω(channel).Should(Receive(&value))
    71  					Ω(value).Should(MatchError("boooom!"))
    72  				})
    73  			})
    74  		})
    75  
    76  		Context("of the correct type", func() {
    77  			It("should write the value received on the channel to the pointer", func() {
    78  				channel := make(chan int, 1)
    79  
    80  				var value int
    81  
    82  				Expect(channel).ShouldNot(Receive(&value))
    83  				Expect(value).Should(BeZero())
    84  
    85  				channel <- 17
    86  
    87  				Expect(channel).Should(Receive(&value))
    88  				Expect(value).Should(Equal(17))
    89  			})
    90  		})
    91  
    92  		Context("to various types of objects", func() {
    93  			It("should work", func() {
    94  				//channels of strings
    95  				stringChan := make(chan string, 1)
    96  				stringChan <- "foo"
    97  
    98  				var s string
    99  				Expect(stringChan).Should(Receive(&s))
   100  				Expect(s).Should(Equal("foo"))
   101  
   102  				//channels of slices
   103  				sliceChan := make(chan []bool, 1)
   104  				sliceChan <- []bool{true, true, false}
   105  
   106  				var sl []bool
   107  				Expect(sliceChan).Should(Receive(&sl))
   108  				Expect(sl).Should(Equal([]bool{true, true, false}))
   109  
   110  				//channels of channels
   111  				chanChan := make(chan chan bool, 1)
   112  				c := make(chan bool)
   113  				chanChan <- c
   114  
   115  				var receivedC chan bool
   116  				Expect(chanChan).Should(Receive(&receivedC))
   117  				Expect(receivedC).Should(Equal(c))
   118  
   119  				//channels of interfaces
   120  				jackieChan := make(chan kungFuActor, 1)
   121  				aJackie := &jackie{name: "Jackie Chan"}
   122  				jackieChan <- aJackie
   123  
   124  				var theJackie kungFuActor
   125  				Expect(jackieChan).Should(Receive(&theJackie))
   126  				Expect(theJackie).Should(Equal(aJackie))
   127  			})
   128  		})
   129  
   130  		Context("of the wrong type", func() {
   131  			It("should error", func() {
   132  				channel := make(chan int, 1)
   133  				channel <- 10
   134  
   135  				var incorrectType bool
   136  
   137  				success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel)
   138  				Expect(success).Should(BeFalse())
   139  				Expect(err).Should(HaveOccurred())
   140  
   141  				var notAPointer int
   142  				success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel)
   143  				Expect(success).Should(BeFalse())
   144  				Expect(err).Should(HaveOccurred())
   145  			})
   146  		})
   147  	})
   148  
   149  	Context("with a matcher", func() {
   150  		It("should defer to the underlying matcher", func() {
   151  			intChannel := make(chan int, 1)
   152  			intChannel <- 3
   153  			Expect(intChannel).Should(Receive(Equal(3)))
   154  
   155  			intChannel <- 2
   156  			Expect(intChannel).ShouldNot(Receive(Equal(3)))
   157  
   158  			stringChannel := make(chan []string, 1)
   159  			stringChannel <- []string{"foo", "bar", "baz"}
   160  			Expect(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo"))))
   161  
   162  			stringChannel <- []string{"foo", "bar", "baz"}
   163  			Expect(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago"))))
   164  		})
   165  
   166  		It("should defer to the underlying matcher for the message", func() {
   167  			matcher := Receive(Equal(3))
   168  			channel := make(chan int, 1)
   169  			channel <- 2
   170  			matcher.Match(channel)
   171  			Expect(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 2\s+to equal\s+<int>: 3`))
   172  
   173  			channel <- 3
   174  			matcher.Match(channel)
   175  			Expect(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 3\s+not to equal\s+<int>: 3`))
   176  		})
   177  
   178  		It("should work just fine with Eventually", func() {
   179  			stringChannel := make(chan string)
   180  
   181  			go func() {
   182  				time.Sleep(5 * time.Millisecond)
   183  				stringChannel <- "A"
   184  				time.Sleep(5 * time.Millisecond)
   185  				stringChannel <- "B"
   186  			}()
   187  
   188  			Eventually(stringChannel).Should(Receive(Equal("B")))
   189  		})
   190  
   191  		Context("if the matcher errors", func() {
   192  			It("should error", func() {
   193  				channel := make(chan int, 1)
   194  				channel <- 3
   195  				success, err := (&ReceiveMatcher{Arg: ContainSubstring("three")}).Match(channel)
   196  				Expect(success).Should(BeFalse())
   197  				Expect(err).Should(HaveOccurred())
   198  			})
   199  		})
   200  
   201  		Context("if nothing is received", func() {
   202  			It("should fail", func() {
   203  				channel := make(chan int, 1)
   204  				success, err := (&ReceiveMatcher{Arg: Equal(1)}).Match(channel)
   205  				Expect(success).Should(BeFalse())
   206  				Expect(err).ShouldNot(HaveOccurred())
   207  			})
   208  		})
   209  	})
   210  
   211  	Context("When actual is a *closed* channel", func() {
   212  		Context("for a buffered channel", func() {
   213  			It("should work until it hits the end of the buffer", func() {
   214  				channel := make(chan bool, 1)
   215  				channel <- true
   216  
   217  				close(channel)
   218  
   219  				Expect(channel).Should(Receive())
   220  				Expect(channel).ShouldNot(Receive())
   221  			})
   222  		})
   223  
   224  		Context("for an unbuffered channel", func() {
   225  			It("should always fail", func() {
   226  				channel := make(chan bool)
   227  				close(channel)
   228  
   229  				Expect(channel).ShouldNot(Receive())
   230  			})
   231  		})
   232  	})
   233  
   234  	Context("When actual is a send-only channel", func() {
   235  		It("should error", func() {
   236  			channel := make(chan bool)
   237  
   238  			var writerChannel chan<- bool
   239  			writerChannel = channel
   240  
   241  			success, err := (&ReceiveMatcher{}).Match(writerChannel)
   242  			Expect(success).Should(BeFalse())
   243  			Expect(err).Should(HaveOccurred())
   244  		})
   245  	})
   246  
   247  	When("acutal is a non-channel", func() {
   248  		It("should error", func() {
   249  			var nilChannel chan bool
   250  
   251  			success, err := (&ReceiveMatcher{}).Match(nilChannel)
   252  			Expect(success).Should(BeFalse())
   253  			Expect(err).Should(HaveOccurred())
   254  
   255  			success, err = (&ReceiveMatcher{}).Match(nil)
   256  			Expect(success).Should(BeFalse())
   257  			Expect(err).Should(HaveOccurred())
   258  
   259  			success, err = (&ReceiveMatcher{}).Match(3)
   260  			Expect(success).Should(BeFalse())
   261  			Expect(err).Should(HaveOccurred())
   262  		})
   263  	})
   264  
   265  	Describe("when used with eventually and a custom matcher", func() {
   266  		It("should return the matcher's error when a failing value is received on the channel, instead of the must receive something failure", func() {
   267  			failures := InterceptGomegaFailures(func() {
   268  				c := make(chan string)
   269  				Eventually(c, 0.01).Should(Receive(Equal("hello")))
   270  			})
   271  			Expect(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something."))
   272  
   273  			failures = InterceptGomegaFailures(func() {
   274  				c := make(chan string, 1)
   275  				c <- "hi"
   276  				Eventually(c, 0.01).Should(Receive(Equal("hello")))
   277  			})
   278  			Expect(failures[0]).Should(ContainSubstring("<string>: hello"))
   279  		})
   280  	})
   281  
   282  	Describe("Bailing early", func() {
   283  		It("should bail early when passed a closed channel", func() {
   284  			c := make(chan bool)
   285  			close(c)
   286  
   287  			t := time.Now()
   288  			failures := InterceptGomegaFailures(func() {
   289  				Eventually(c).Should(Receive())
   290  			})
   291  			Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
   292  			Expect(failures).Should(HaveLen(1))
   293  		})
   294  
   295  		It("should bail early when passed a non-channel", func() {
   296  			t := time.Now()
   297  			failures := InterceptGomegaFailures(func() {
   298  				Eventually(3).Should(Receive())
   299  			})
   300  			Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
   301  			Expect(failures).Should(HaveLen(1))
   302  		})
   303  	})
   304  })