diff options
author | Valentin Rothberg <rothberg@redhat.com> | 2019-02-05 11:51:41 +0100 |
---|---|---|
committer | Valentin Rothberg <rothberg@redhat.com> | 2019-02-06 11:14:06 +0100 |
commit | 9ac0ebb0791851aea81ecc847802db5a39bfb6e7 (patch) | |
tree | 30ad98bcc2c2dd1136f46a48cbc44d422adfa184 /vendor/github.com/onsi/gomega/gbytes | |
parent | 51714d5da7aaa19014fd67b48b79dfbd5f69c1f0 (diff) | |
download | podman-9ac0ebb0791851aea81ecc847802db5a39bfb6e7.tar.gz podman-9ac0ebb0791851aea81ecc847802db5a39bfb6e7.tar.bz2 podman-9ac0ebb0791851aea81ecc847802db5a39bfb6e7.zip |
Cirrus: add vendor_check_task
* Make sure that all vendored dependencies are in sync with the code and
the vendor.conf by running `make vendor` with a follow-up status check
of the git tree.
* Vendor ginkgo and gomega to include the test dependencies.
Signed-off-by: Chris Evic <cevich@redhat.com>
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'vendor/github.com/onsi/gomega/gbytes')
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/buffer.go | 245 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/buffer_test.go | 205 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go | 13 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/io_wrappers.go | 85 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go | 188 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/say_matcher.go | 104 | ||||
-rw-r--r-- | vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go | 169 |
7 files changed, 1009 insertions, 0 deletions
diff --git a/vendor/github.com/onsi/gomega/gbytes/buffer.go b/vendor/github.com/onsi/gomega/gbytes/buffer.go new file mode 100644 index 000000000..336086f4a --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/buffer.go @@ -0,0 +1,245 @@ +/* +Package gbytes provides a buffer that supports incrementally detecting input. + +You use gbytes.Buffer with the gbytes.Say matcher. When Say finds a match, it fastforwards the buffer's read cursor to the end of that match. + +Subsequent matches against the buffer will only operate against data that appears *after* the read cursor. + +The read cursor is an opaque implementation detail that you cannot access. You should use the Say matcher to sift through the buffer. You can always +access the entire buffer's contents with Contents(). + +*/ +package gbytes + +import ( + "errors" + "fmt" + "io" + "regexp" + "sync" + "time" +) + +/* +gbytes.Buffer implements an io.Writer and can be used with the gbytes.Say matcher. + +You should only use a gbytes.Buffer in test code. It stores all writes in an in-memory buffer - behavior that is inappropriate for production code! +*/ +type Buffer struct { + contents []byte + readCursor uint64 + lock *sync.Mutex + detectCloser chan interface{} + closed bool +} + +/* +NewBuffer returns a new gbytes.Buffer +*/ +func NewBuffer() *Buffer { + return &Buffer{ + lock: &sync.Mutex{}, + } +} + +/* +BufferWithBytes returns a new gbytes.Buffer seeded with the passed in bytes +*/ +func BufferWithBytes(bytes []byte) *Buffer { + return &Buffer{ + lock: &sync.Mutex{}, + contents: bytes, + } +} + +/* +BufferReader returns a new gbytes.Buffer that wraps a reader. The reader's contents are read into +the Buffer via io.Copy +*/ +func BufferReader(reader io.Reader) *Buffer { + b := &Buffer{ + lock: &sync.Mutex{}, + } + + go func() { + io.Copy(b, reader) + b.Close() + }() + + return b +} + +/* +Write implements the io.Writer interface +*/ +func (b *Buffer) Write(p []byte) (n int, err error) { + b.lock.Lock() + defer b.lock.Unlock() + + if b.closed { + return 0, errors.New("attempt to write to closed buffer") + } + + b.contents = append(b.contents, p...) + return len(p), nil +} + +/* +Read implements the io.Reader interface. It advances the +cursor as it reads. + +Returns an error if called after Close. +*/ +func (b *Buffer) Read(d []byte) (int, error) { + b.lock.Lock() + defer b.lock.Unlock() + + if b.closed { + return 0, errors.New("attempt to read from closed buffer") + } + + if uint64(len(b.contents)) <= b.readCursor { + return 0, io.EOF + } + + n := copy(d, b.contents[b.readCursor:]) + b.readCursor += uint64(n) + + return n, nil +} + +/* +Close signifies that the buffer will no longer be written to +*/ +func (b *Buffer) Close() error { + b.lock.Lock() + defer b.lock.Unlock() + + b.closed = true + + return nil +} + +/* +Closed returns true if the buffer has been closed +*/ +func (b *Buffer) Closed() bool { + b.lock.Lock() + defer b.lock.Unlock() + + return b.closed +} + +/* +Contents returns all data ever written to the buffer. +*/ +func (b *Buffer) Contents() []byte { + b.lock.Lock() + defer b.lock.Unlock() + + contents := make([]byte, len(b.contents)) + copy(contents, b.contents) + return contents +} + +/* +Detect takes a regular expression and returns a channel. + +The channel will receive true the first time data matching the regular expression is written to the buffer. +The channel is subsequently closed and the buffer's read-cursor is fast-forwarded to just after the matching region. + +You typically don't need to use Detect and should use the ghttp.Say matcher instead. Detect is useful, however, in cases where your code must +be branch and handle different outputs written to the buffer. + +For example, consider a buffer hooked up to the stdout of a client library. You may (or may not, depending on state outside of your control) need to authenticate the client library. + +You could do something like: + +select { +case <-buffer.Detect("You are not logged in"): + //log in +case <-buffer.Detect("Success"): + //carry on +case <-time.After(time.Second): + //welp +} +buffer.CancelDetects() + +You should always call CancelDetects after using Detect. This will close any channels that have not detected and clean up the goroutines that were spawned to support them. + +Finally, you can pass detect a format string followed by variadic arguments. This will construct the regexp using fmt.Sprintf. +*/ +func (b *Buffer) Detect(desired string, args ...interface{}) chan bool { + formattedRegexp := desired + if len(args) > 0 { + formattedRegexp = fmt.Sprintf(desired, args...) + } + re := regexp.MustCompile(formattedRegexp) + + b.lock.Lock() + defer b.lock.Unlock() + + if b.detectCloser == nil { + b.detectCloser = make(chan interface{}) + } + + closer := b.detectCloser + response := make(chan bool) + go func() { + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + defer close(response) + for { + select { + case <-ticker.C: + b.lock.Lock() + data, cursor := b.contents[b.readCursor:], b.readCursor + loc := re.FindIndex(data) + b.lock.Unlock() + + if loc != nil { + response <- true + b.lock.Lock() + newCursorPosition := cursor + uint64(loc[1]) + if newCursorPosition >= b.readCursor { + b.readCursor = newCursorPosition + } + b.lock.Unlock() + return + } + case <-closer: + return + } + } + }() + + return response +} + +/* +CancelDetects cancels any pending detects and cleans up their goroutines. You should always call this when you're done with a set of Detect channels. +*/ +func (b *Buffer) CancelDetects() { + b.lock.Lock() + defer b.lock.Unlock() + + close(b.detectCloser) + b.detectCloser = nil +} + +func (b *Buffer) didSay(re *regexp.Regexp) (bool, []byte) { + b.lock.Lock() + defer b.lock.Unlock() + + unreadBytes := b.contents[b.readCursor:] + copyOfUnreadBytes := make([]byte, len(unreadBytes)) + copy(copyOfUnreadBytes, unreadBytes) + + loc := re.FindIndex(unreadBytes) + + if loc != nil { + b.readCursor += uint64(loc[1]) + return true, copyOfUnreadBytes + } + return false, copyOfUnreadBytes +} diff --git a/vendor/github.com/onsi/gomega/gbytes/buffer_test.go b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go new file mode 100644 index 000000000..9d4e8279d --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go @@ -0,0 +1,205 @@ +package gbytes_test + +import ( + "io" + "time" + + . "github.com/onsi/gomega/gbytes" + + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type SlowReader struct { + R io.Reader + D time.Duration +} + +func (s SlowReader) Read(p []byte) (int, error) { + time.Sleep(s.D) + return s.R.Read(p) +} + +var _ = Describe("Buffer", func() { + var buffer *Buffer + + BeforeEach(func() { + buffer = NewBuffer() + }) + + Describe("dumping the entire contents of the buffer", func() { + It("should return everything that's been written", func() { + buffer.Write([]byte("abc")) + buffer.Write([]byte("def")) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) + + Expect(buffer).Should(Say("bcd")) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) + }) + }) + + Describe("creating a buffer with bytes", func() { + It("should create the buffer with the cursor set to the beginning", func() { + buffer := BufferWithBytes([]byte("abcdef")) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) + Expect(buffer).Should(Say("abc")) + Expect(buffer).ShouldNot(Say("abc")) + Expect(buffer).Should(Say("def")) + }) + }) + + Describe("creating a buffer that wraps a reader", func() { + Context("for a well-behaved reader", func() { + It("should buffer the contents of the reader", func() { + reader := bytes.NewBuffer([]byte("abcdef")) + buffer := BufferReader(reader) + Eventually(buffer).Should(Say("abc")) + Expect(buffer).ShouldNot(Say("abc")) + Eventually(buffer).Should(Say("def")) + Eventually(buffer.Closed).Should(BeTrue()) + }) + }) + + Context("for a slow reader", func() { + It("should allow Eventually to time out", func() { + slowReader := SlowReader{ + R: bytes.NewBuffer([]byte("abcdef")), + D: time.Second, + } + buffer := BufferReader(slowReader) + failures := InterceptGomegaFailures(func() { + Eventually(buffer, 100*time.Millisecond).Should(Say("abc")) + }) + Expect(failures).ShouldNot(BeEmpty()) + + fastReader := SlowReader{ + R: bytes.NewBuffer([]byte("abcdef")), + D: time.Millisecond, + } + buffer = BufferReader(fastReader) + Eventually(buffer, 100*time.Millisecond).Should(Say("abc")) + Eventually(buffer.Closed).Should(BeTrue()) + }) + }) + }) + + Describe("reading from a buffer", func() { + It("should read the current contents of the buffer", func() { + buffer := BufferWithBytes([]byte("abcde")) + + dest := make([]byte, 3) + n, err := buffer.Read(dest) + Expect(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(3)) + Expect(string(dest)).Should(Equal("abc")) + + dest = make([]byte, 3) + n, err = buffer.Read(dest) + Expect(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(2)) + Expect(string(dest[:n])).Should(Equal("de")) + + n, err = buffer.Read(dest) + Expect(err).Should(Equal(io.EOF)) + Expect(n).Should(Equal(0)) + }) + + Context("after the buffer has been closed", func() { + It("returns an error", func() { + buffer := BufferWithBytes([]byte("abcde")) + + buffer.Close() + + dest := make([]byte, 3) + n, err := buffer.Read(dest) + Expect(err).Should(HaveOccurred()) + Expect(n).Should(Equal(0)) + }) + }) + }) + + Describe("detecting regular expressions", func() { + It("should fire the appropriate channel when the passed in pattern matches, then close it", func(done Done) { + go func() { + time.Sleep(10 * time.Millisecond) + buffer.Write([]byte("abcde")) + }() + + A := buffer.Detect("%s", "a.c") + B := buffer.Detect("def") + + var gotIt bool + select { + case gotIt = <-A: + case <-B: + Fail("should not have gotten here") + } + + Expect(gotIt).Should(BeTrue()) + Eventually(A).Should(BeClosed()) + + buffer.Write([]byte("f")) + Eventually(B).Should(Receive()) + Eventually(B).Should(BeClosed()) + + close(done) + }) + + It("should fast-forward the buffer upon detection", func(done Done) { + buffer.Write([]byte("abcde")) + <-buffer.Detect("abc") + Expect(buffer).ShouldNot(Say("abc")) + Expect(buffer).Should(Say("de")) + close(done) + }) + + It("should only fast-forward the buffer when the channel is read, and only if doing so would not rewind it", func(done Done) { + buffer.Write([]byte("abcde")) + A := buffer.Detect("abc") + time.Sleep(20 * time.Millisecond) //give the goroutine a chance to detect and write to the channel + Expect(buffer).Should(Say("abcd")) + <-A + Expect(buffer).ShouldNot(Say("d")) + Expect(buffer).Should(Say("e")) + Eventually(A).Should(BeClosed()) + close(done) + }) + + It("should be possible to cancel a detection", func(done Done) { + A := buffer.Detect("abc") + B := buffer.Detect("def") + buffer.CancelDetects() + buffer.Write([]byte("abcdef")) + Eventually(A).Should(BeClosed()) + Eventually(B).Should(BeClosed()) + + Expect(buffer).Should(Say("bcde")) + <-buffer.Detect("f") + close(done) + }) + }) + + Describe("closing the buffer", func() { + It("should error when further write attempts are made", func() { + _, err := buffer.Write([]byte("abc")) + Expect(err).ShouldNot(HaveOccurred()) + + buffer.Close() + + _, err = buffer.Write([]byte("def")) + Expect(err).Should(HaveOccurred()) + + Expect(buffer.Contents()).Should(Equal([]byte("abc"))) + }) + + It("should be closed", func() { + Expect(buffer.Closed()).Should(BeFalse()) + + buffer.Close() + + Expect(buffer.Closed()).Should(BeTrue()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go b/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go new file mode 100644 index 000000000..3a7dc0612 --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go @@ -0,0 +1,13 @@ +package gbytes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestGbytes(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Gbytes Suite") +} diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go new file mode 100644 index 000000000..3caed8769 --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go @@ -0,0 +1,85 @@ +package gbytes + +import ( + "errors" + "io" + "time" +) + +// ErrTimeout is returned by TimeoutCloser, TimeoutReader, and TimeoutWriter when the underlying Closer/Reader/Writer does not return within the specified timeout +var ErrTimeout = errors.New("timeout occurred") + +// TimeoutCloser returns an io.Closer that wraps the passed-in io.Closer. If the underlying Closer fails to close within the alloted timeout ErrTimeout is returned. +func TimeoutCloser(c io.Closer, timeout time.Duration) io.Closer { + return timeoutReaderWriterCloser{c: c, d: timeout} +} + +// TimeoutReader returns an io.Reader that wraps the passed-in io.Reader. If the underlying Reader fails to read within the alloted timeout ErrTimeout is returned. +func TimeoutReader(r io.Reader, timeout time.Duration) io.Reader { + return timeoutReaderWriterCloser{r: r, d: timeout} +} + +// TimeoutWriter returns an io.Writer that wraps the passed-in io.Writer. If the underlying Writer fails to write within the alloted timeout ErrTimeout is returned. +func TimeoutWriter(w io.Writer, timeout time.Duration) io.Writer { + return timeoutReaderWriterCloser{w: w, d: timeout} +} + +type timeoutReaderWriterCloser struct { + c io.Closer + w io.Writer + r io.Reader + d time.Duration +} + +func (t timeoutReaderWriterCloser) Close() error { + done := make(chan struct{}) + var err error + + go func() { + err = t.c.Close() + close(done) + }() + + select { + case <-done: + return err + case <-time.After(t.d): + return ErrTimeout + } +} + +func (t timeoutReaderWriterCloser) Read(p []byte) (int, error) { + done := make(chan struct{}) + var n int + var err error + + go func() { + n, err = t.r.Read(p) + close(done) + }() + + select { + case <-done: + return n, err + case <-time.After(t.d): + return 0, ErrTimeout + } +} + +func (t timeoutReaderWriterCloser) Write(p []byte) (int, error) { + done := make(chan struct{}) + var n int + var err error + + go func() { + n, err = t.w.Write(p) + close(done) + }() + + select { + case <-done: + return n, err + case <-time.After(t.d): + return 0, ErrTimeout + } +} diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go new file mode 100644 index 000000000..3da973498 --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go @@ -0,0 +1,188 @@ +package gbytes_test + +import ( + "fmt" + "io" + "time" + + . "github.com/onsi/gomega/gbytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type FakeCloser struct { + err error + duration time.Duration +} + +func (f FakeCloser) Close() error { + time.Sleep(f.duration) + return f.err +} + +type FakeReader struct { + err error + duration time.Duration +} + +func (f FakeReader) Read(p []byte) (int, error) { + time.Sleep(f.duration) + if f.err != nil { + return 0, f.err + } + + for i := 0; i < len(p); i++ { + p[i] = 'a' + } + + return len(p), nil +} + +type FakeWriter struct { + err error + duration time.Duration +} + +func (f FakeWriter) Write(p []byte) (int, error) { + time.Sleep(f.duration) + if f.err != nil { + return 0, f.err + } + + return len(p), nil +} + +var _ = Describe("Io Wrappers", func() { + Describe("TimeoutCloser", func() { + var innerCloser io.Closer + var timeoutCloser io.Closer + + JustBeforeEach(func() { + timeoutCloser = TimeoutCloser(innerCloser, 20*time.Millisecond) + }) + + Context("when the underlying Closer closes with no error", func() { + BeforeEach(func() { + innerCloser = FakeCloser{} + }) + + It("returns with no error", func() { + Expect(timeoutCloser.Close()).Should(Succeed()) + }) + }) + + Context("when the underlying Closer closes with an error", func() { + BeforeEach(func() { + innerCloser = FakeCloser{err: fmt.Errorf("boom")} + }) + + It("returns the error", func() { + Expect(timeoutCloser.Close()).Should(MatchError("boom")) + }) + }) + + Context("when the underlying Closer hangs", func() { + BeforeEach(func() { + innerCloser = FakeCloser{ + err: fmt.Errorf("boom"), + duration: time.Hour, + } + }) + + It("returns ErrTimeout", func() { + Expect(timeoutCloser.Close()).Should(MatchError(ErrTimeout)) + }) + }) + }) + + Describe("TimeoutReader", func() { + var innerReader io.Reader + var timeoutReader io.Reader + + JustBeforeEach(func() { + timeoutReader = TimeoutReader(innerReader, 20*time.Millisecond) + }) + + Context("when the underlying Reader returns no error", func() { + BeforeEach(func() { + innerReader = FakeReader{} + }) + + It("returns with no error", func() { + p := make([]byte, 5) + n, err := timeoutReader.Read(p) + Expect(n).Should(Equal(5)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(p).Should(Equal([]byte("aaaaa"))) + }) + }) + + Context("when the underlying Reader returns an error", func() { + BeforeEach(func() { + innerReader = FakeReader{err: fmt.Errorf("boom")} + }) + + It("returns the error", func() { + p := make([]byte, 5) + _, err := timeoutReader.Read(p) + Expect(err).Should(MatchError("boom")) + }) + }) + + Context("when the underlying Reader hangs", func() { + BeforeEach(func() { + innerReader = FakeReader{err: fmt.Errorf("boom"), duration: time.Hour} + }) + + It("returns ErrTimeout", func() { + p := make([]byte, 5) + _, err := timeoutReader.Read(p) + Expect(err).Should(MatchError(ErrTimeout)) + }) + }) + }) + + Describe("TimeoutWriter", func() { + var innerWriter io.Writer + var timeoutWriter io.Writer + + JustBeforeEach(func() { + timeoutWriter = TimeoutWriter(innerWriter, 20*time.Millisecond) + }) + + Context("when the underlying Writer returns no error", func() { + BeforeEach(func() { + innerWriter = FakeWriter{} + }) + + It("returns with no error", func() { + n, err := timeoutWriter.Write([]byte("aaaaa")) + Expect(n).Should(Equal(5)) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + + Context("when the underlying Writer returns an error", func() { + BeforeEach(func() { + innerWriter = FakeWriter{err: fmt.Errorf("boom")} + }) + + It("returns the error", func() { + _, err := timeoutWriter.Write([]byte("aaaaa")) + Expect(err).Should(MatchError("boom")) + }) + }) + + Context("when the underlying Writer hangs", func() { + BeforeEach(func() { + innerWriter = FakeWriter{err: fmt.Errorf("boom"), duration: time.Hour} + }) + + It("returns ErrTimeout", func() { + _, err := timeoutWriter.Write([]byte("aaaaa")) + Expect(err).Should(MatchError(ErrTimeout)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go new file mode 100644 index 000000000..14317182b --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go @@ -0,0 +1,104 @@ +package gbytes + +import ( + "fmt" + "regexp" + + "github.com/onsi/gomega/format" +) + +//Objects satisfying the BufferProvider can be used with the Say matcher. +type BufferProvider interface { + Buffer() *Buffer +} + +/* +Say is a Gomega matcher that operates on gbytes.Buffers: + + Expect(buffer).Should(Say("something")) + +will succeed if the unread portion of the buffer matches the regular expression "something". + +When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the succesful match. +Thus, subsequent calls to Say will only match against the unread portion of the buffer + +Say pairs very well with Eventually. To assert that a buffer eventually receives data matching "[123]-star" within 3 seconds you can: + + Eventually(buffer, 3).Should(Say("[123]-star")) + +Ditto with consistently. To assert that a buffer does not receive data matching "never-see-this" for 1 second you can: + + Consistently(buffer, 1).ShouldNot(Say("never-see-this")) + +In addition to bytes.Buffers, Say can operate on objects that implement the gbytes.BufferProvider interface. +In such cases, Say simply operates on the *gbytes.Buffer returned by Buffer() + +If the buffer is closed, the Say matcher will tell Eventually to abort. +*/ +func Say(expected string, args ...interface{}) *sayMatcher { + if len(args) > 0 { + expected = fmt.Sprintf(expected, args...) + } + return &sayMatcher{ + re: regexp.MustCompile(expected), + } +} + +type sayMatcher struct { + re *regexp.Regexp + receivedSayings []byte +} + +func (m *sayMatcher) buffer(actual interface{}) (*Buffer, bool) { + var buffer *Buffer + + switch x := actual.(type) { + case *Buffer: + buffer = x + case BufferProvider: + buffer = x.Buffer() + default: + return nil, false + } + + return buffer, true +} + +func (m *sayMatcher) Match(actual interface{}) (success bool, err error) { + buffer, ok := m.buffer(actual) + if !ok { + return false, fmt.Errorf("Say must be passed a *gbytes.Buffer or BufferProvider. Got:\n%s", format.Object(actual, 1)) + } + + didSay, sayings := buffer.didSay(m.re) + m.receivedSayings = sayings + + return didSay, nil +} + +func (m *sayMatcher) FailureMessage(actual interface{}) (message string) { + return fmt.Sprintf( + "Got stuck at:\n%s\nWaiting for:\n%s", + format.IndentString(string(m.receivedSayings), 1), + format.IndentString(m.re.String(), 1), + ) +} + +func (m *sayMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return fmt.Sprintf( + "Saw:\n%s\nWhich matches the unexpected:\n%s", + format.IndentString(string(m.receivedSayings), 1), + format.IndentString(m.re.String(), 1), + ) +} + +func (m *sayMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { + switch x := actual.(type) { + case *Buffer: + return !x.Closed() + case BufferProvider: + return !x.Buffer().Closed() + default: + return true + } +} diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go new file mode 100644 index 000000000..0055d4a1b --- /dev/null +++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go @@ -0,0 +1,169 @@ +package gbytes_test + +import ( + "time" + + . "github.com/onsi/gomega/gbytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type speaker struct { + buffer *Buffer +} + +func (s *speaker) Buffer() *Buffer { + return s.buffer +} + +var _ = Describe("SayMatcher", func() { + var buffer *Buffer + + BeforeEach(func() { + buffer = NewBuffer() + buffer.Write([]byte("abc")) + }) + + Context("when actual is not a gexec Buffer, or a BufferProvider", func() { + It("should error", func() { + failures := InterceptGomegaFailures(func() { + Expect("foo").Should(Say("foo")) + }) + Expect(failures[0]).Should(ContainSubstring("*gbytes.Buffer")) + }) + }) + + Context("when a match is found", func() { + It("should succeed", func() { + Expect(buffer).Should(Say("abc")) + }) + + It("should support printf-like formatting", func() { + Expect(buffer).Should(Say("a%sc", "b")) + }) + + It("should match literal %", func() { + buffer.Write([]byte("%")) + Expect(buffer).Should(Say("abc%")) + }) + + It("should use a regular expression", func() { + Expect(buffer).Should(Say("a.c")) + }) + + It("should fastforward the buffer", func() { + buffer.Write([]byte("def")) + Expect(buffer).Should(Say("abcd")) + Expect(buffer).Should(Say("ef")) + Expect(buffer).ShouldNot(Say("[a-z]")) + }) + }) + + Context("when no match is found", func() { + It("should not error", func() { + Expect(buffer).ShouldNot(Say("def")) + }) + + Context("when the buffer is closed", func() { + BeforeEach(func() { + buffer.Close() + }) + + It("should abort an eventually", func() { + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(buffer).Should(Say("def")) + }) + Eventually(buffer).ShouldNot(Say("def")) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) + + t = time.Now() + Eventually(buffer).Should(Say("abc")) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + }) + + It("should abort a consistently", func() { + t := time.Now() + Consistently(buffer, 2.0).ShouldNot(Say("def")) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + }) + + It("should not error with a synchronous matcher", func() { + Expect(buffer).ShouldNot(Say("def")) + Expect(buffer).Should(Say("abc")) + }) + }) + }) + + Context("when a positive match fails", func() { + It("should report where it got stuck", func() { + Expect(buffer).Should(Say("abc")) + buffer.Write([]byte("def")) + failures := InterceptGomegaFailures(func() { + Expect(buffer).Should(Say("abc")) + }) + Expect(failures[0]).Should(ContainSubstring("Got stuck at:")) + Expect(failures[0]).Should(ContainSubstring("def")) + }) + }) + + Context("when a negative match fails", func() { + It("should report where it got stuck", func() { + failures := InterceptGomegaFailures(func() { + Expect(buffer).ShouldNot(Say("abc")) + }) + Expect(failures[0]).Should(ContainSubstring("Saw:")) + Expect(failures[0]).Should(ContainSubstring("Which matches the unexpected:")) + Expect(failures[0]).Should(ContainSubstring("abc")) + }) + }) + + Context("when a match is not found", func() { + It("should not fastforward the buffer", func() { + Expect(buffer).ShouldNot(Say("def")) + Expect(buffer).Should(Say("abc")) + }) + }) + + Context("a nice real-life example", func() { + It("should behave well", func() { + Expect(buffer).Should(Say("abc")) + go func() { + time.Sleep(10 * time.Millisecond) + buffer.Write([]byte("def")) + }() + Expect(buffer).ShouldNot(Say("def")) + Eventually(buffer).Should(Say("def")) + }) + }) + + Context("when actual is a BufferProvider", func() { + It("should use actual's buffer", func() { + s := &speaker{ + buffer: NewBuffer(), + } + + Expect(s).ShouldNot(Say("abc")) + + s.Buffer().Write([]byte("abc")) + Expect(s).Should(Say("abc")) + }) + + It("should abort an eventually", func() { + s := &speaker{ + buffer: NewBuffer(), + } + + s.buffer.Close() + + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(s).Should(Say("def")) + }) + Expect(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + }) + }) +}) |