|  | package asyncassertion_test | 
|  |  | 
|  | import ( | 
|  | "errors" | 
|  | "time" | 
|  |  | 
|  | . "github.com/onsi/ginkgo" | 
|  | . "github.com/onsi/gomega" | 
|  | . "github.com/onsi/gomega/internal/asyncassertion" | 
|  | ) | 
|  |  | 
|  | var _ = Describe("Async Assertion", func() { | 
|  | var ( | 
|  | failureMessage string | 
|  | callerSkip     int | 
|  | ) | 
|  |  | 
|  | var fakeFailHandler = func(message string, skip ...int) { | 
|  | failureMessage = message | 
|  | callerSkip = skip[0] | 
|  | } | 
|  |  | 
|  | BeforeEach(func() { | 
|  | failureMessage = "" | 
|  | callerSkip = 0 | 
|  | }) | 
|  |  | 
|  | Describe("Eventually", func() { | 
|  | Context("the positive case", func() { | 
|  | It("should poll the function and matcher", func() { | 
|  | counter := 0 | 
|  | a := New(AsyncAssertionTypeEventually, func() int { | 
|  | counter++ | 
|  | return counter | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(BeNumerically("==", 5)) | 
|  | Ω(failureMessage).Should(BeZero()) | 
|  | }) | 
|  |  | 
|  | It("should continue when the matcher errors", func() { | 
|  | counter := 0 | 
|  | a := New(AsyncAssertionTypeEventually, func() interface{} { | 
|  | counter++ | 
|  | if counter == 5 { | 
|  | return "not-a-number" //this should cause the matcher to error | 
|  | } | 
|  | return counter | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(BeNumerically("==", 5), "My description %d", 2) | 
|  |  | 
|  | Ω(failureMessage).Should(ContainSubstring("Timed out after")) | 
|  | Ω(failureMessage).Should(ContainSubstring("My description 2")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  |  | 
|  | It("should be able to timeout", func() { | 
|  | counter := 0 | 
|  | a := New(AsyncAssertionTypeEventually, func() int { | 
|  | counter++ | 
|  | return counter | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(BeNumerically(">", 100), "My description %d", 2) | 
|  |  | 
|  | Ω(counter).Should(BeNumerically(">", 8)) | 
|  | Ω(counter).Should(BeNumerically("<=", 10)) | 
|  | Ω(failureMessage).Should(ContainSubstring("Timed out after")) | 
|  | Ω(failureMessage).Should(MatchRegexp(`\<int\>: \d`), "Should pass the correct value to the matcher message formatter.") | 
|  | Ω(failureMessage).Should(ContainSubstring("My description 2")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("the negative case", func() { | 
|  | It("should poll the function and matcher", func() { | 
|  | counter := 0 | 
|  | a := New(AsyncAssertionTypeEventually, func() int { | 
|  | counter += 1 | 
|  | return counter | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(BeNumerically("<", 3)) | 
|  |  | 
|  | Ω(counter).Should(Equal(3)) | 
|  | Ω(failureMessage).Should(BeZero()) | 
|  | }) | 
|  |  | 
|  | It("should timeout when the matcher errors", func() { | 
|  | a := New(AsyncAssertionTypeEventually, func() interface{} { | 
|  | return 0 //this should cause the matcher to error | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(HaveLen(0), "My description %d", 2) | 
|  |  | 
|  | Ω(failureMessage).Should(ContainSubstring("Timed out after")) | 
|  | Ω(failureMessage).Should(ContainSubstring("Error:")) | 
|  | Ω(failureMessage).Should(ContainSubstring("My description 2")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  |  | 
|  | It("should be able to timeout", func() { | 
|  | a := New(AsyncAssertionTypeEventually, func() int { | 
|  | return 0 | 
|  | }, fakeFailHandler, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(Equal(0), "My description %d", 2) | 
|  |  | 
|  | Ω(failureMessage).Should(ContainSubstring("Timed out after")) | 
|  | Ω(failureMessage).Should(ContainSubstring("<int>: 0"), "Should pass the correct value to the matcher message formatter.") | 
|  | Ω(failureMessage).Should(ContainSubstring("My description 2")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("with a function that returns multiple values", func() { | 
|  | It("should eventually succeed if the additional arguments are nil", func() { | 
|  | i := 0 | 
|  | Eventually(func() (int, error) { | 
|  | i++ | 
|  | return i, nil | 
|  | }).Should(Equal(10)) | 
|  | }) | 
|  |  | 
|  | It("should eventually timeout if the additional arguments are not nil", func() { | 
|  | i := 0 | 
|  | a := New(AsyncAssertionTypeEventually, func() (int, error) { | 
|  | i++ | 
|  | return i, errors.New("bam") | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  | a.Should(Equal(2)) | 
|  |  | 
|  | Ω(failureMessage).Should(ContainSubstring("Timed out after")) | 
|  | Ω(failureMessage).Should(ContainSubstring("Error:")) | 
|  | Ω(failureMessage).Should(ContainSubstring("bam")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("Making an assertion without a registered fail handler", func() { | 
|  | It("should panic", func() { | 
|  | defer func() { | 
|  | e := recover() | 
|  | RegisterFailHandler(Fail) | 
|  | if e == nil { | 
|  | Fail("expected a panic to have occured") | 
|  | } | 
|  | }() | 
|  |  | 
|  | RegisterFailHandler(nil) | 
|  | c := make(chan bool, 1) | 
|  | c <- true | 
|  | Eventually(c).Should(Receive()) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Consistently", func() { | 
|  | Describe("The positive case", func() { | 
|  | Context("when the matcher consistently passes for the duration", func() { | 
|  | It("should pass", func() { | 
|  | calls := 0 | 
|  | a := New(AsyncAssertionTypeConsistently, func() string { | 
|  | calls++ | 
|  | return "foo" | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(Equal("foo")) | 
|  | Ω(calls).Should(BeNumerically(">", 8)) | 
|  | Ω(calls).Should(BeNumerically("<=", 10)) | 
|  | Ω(failureMessage).Should(BeZero()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when the matcher fails at some point", func() { | 
|  | It("should fail", func() { | 
|  | calls := 0 | 
|  | a := New(AsyncAssertionTypeConsistently, func() interface{} { | 
|  | calls++ | 
|  | if calls > 5 { | 
|  | return "bar" | 
|  | } | 
|  | return "foo" | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(Equal("foo")) | 
|  | Ω(failureMessage).Should(ContainSubstring("to equal")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when the matcher errors at some point", func() { | 
|  | It("should fail", func() { | 
|  | calls := 0 | 
|  | a := New(AsyncAssertionTypeConsistently, func() interface{} { | 
|  | calls++ | 
|  | if calls > 5 { | 
|  | return 3 | 
|  | } | 
|  | return []int{1, 2, 3} | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.Should(HaveLen(3)) | 
|  | Ω(failureMessage).Should(ContainSubstring("HaveLen matcher expects")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("The negative case", func() { | 
|  | Context("when the matcher consistently passes for the duration", func() { | 
|  | It("should pass", func() { | 
|  | c := make(chan bool) | 
|  | a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(Receive()) | 
|  | Ω(failureMessage).Should(BeZero()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when the matcher fails at some point", func() { | 
|  | It("should fail", func() { | 
|  | c := make(chan bool) | 
|  | go func() { | 
|  | time.Sleep(time.Duration(100 * time.Millisecond)) | 
|  | c <- true | 
|  | }() | 
|  |  | 
|  | a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(Receive()) | 
|  | Ω(failureMessage).Should(ContainSubstring("not to receive anything")) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when the matcher errors at some point", func() { | 
|  | It("should fail", func() { | 
|  | calls := 0 | 
|  | a := New(AsyncAssertionTypeConsistently, func() interface{} { | 
|  | calls++ | 
|  | return calls | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  |  | 
|  | a.ShouldNot(BeNumerically(">", 5)) | 
|  | Ω(failureMessage).Should(ContainSubstring("not to be >")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("with a function that returns multiple values", func() { | 
|  | It("should consistently succeed if the additional arguments are nil", func() { | 
|  | i := 2 | 
|  | Consistently(func() (int, error) { | 
|  | i++ | 
|  | return i, nil | 
|  | }).Should(BeNumerically(">=", 2)) | 
|  | }) | 
|  |  | 
|  | It("should eventually timeout if the additional arguments are not nil", func() { | 
|  | i := 2 | 
|  | a := New(AsyncAssertionTypeEventually, func() (int, error) { | 
|  | i++ | 
|  | return i, errors.New("bam") | 
|  | }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) | 
|  | a.Should(BeNumerically(">=", 2)) | 
|  |  | 
|  | Ω(failureMessage).Should(ContainSubstring("Error:")) | 
|  | Ω(failureMessage).Should(ContainSubstring("bam")) | 
|  | Ω(callerSkip).Should(Equal(4)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("Making an assertion without a registered fail handler", func() { | 
|  | It("should panic", func() { | 
|  | defer func() { | 
|  | e := recover() | 
|  | RegisterFailHandler(Fail) | 
|  | if e == nil { | 
|  | Fail("expected a panic to have occured") | 
|  | } | 
|  | }() | 
|  |  | 
|  | RegisterFailHandler(nil) | 
|  | c := make(chan bool) | 
|  | Consistently(c).ShouldNot(Receive()) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when passed a function with the wrong # or arguments & returns", func() { | 
|  | It("should panic", func() { | 
|  | Ω(func() { | 
|  | New(AsyncAssertionTypeEventually, func() {}, fakeFailHandler, 0, 0, 1) | 
|  | }).Should(Panic()) | 
|  |  | 
|  | Ω(func() { | 
|  | New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailHandler, 0, 0, 1) | 
|  | }).Should(Panic()) | 
|  |  | 
|  | Ω(func() { | 
|  | New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, 0, 0, 1) | 
|  | }).ShouldNot(Panic()) | 
|  |  | 
|  | Ω(func() { | 
|  | New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailHandler, 0, 0, 1) | 
|  | }).ShouldNot(Panic()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("bailing early", func() { | 
|  | Context("when actual is a value", func() { | 
|  | It("Eventually should bail out and fail early if the matcher says to", func() { | 
|  | c := make(chan bool) | 
|  | close(c) | 
|  |  | 
|  | t := time.Now() | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | Eventually(c, 0.1).Should(Receive()) | 
|  | }) | 
|  | Ω(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond)) | 
|  |  | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when actual is a function", func() { | 
|  | It("should never bail early", func() { | 
|  | c := make(chan bool) | 
|  | close(c) | 
|  |  | 
|  | t := time.Now() | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | Eventually(func() chan bool { | 
|  | return c | 
|  | }, 0.1).Should(Receive()) | 
|  | }) | 
|  | Ω(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond)) | 
|  |  | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) |