Use Go 1.5 vendoring instead of Godeps

Change made by:

- running "gvt fetch" on each of the packages mentioned in
  Godeps/Godeps.json
- `rm -rf Godeps`
- tweaking the build scripts to not mention Godeps
- tweaking the build scripts to test `./lib/...`, `./cmd/...` explicitly
  (to avoid testing vendor)
- tweaking the build scripts to not juggle GOPATH for Godeps and instead
  set GO15VENDOREXPERIMENT.

This also results in some updated packages at the same time I bet.

Building with Go 1.3 and 1.4 still *works* but won't use our vendored
dependencies - the user needs to have the actual packages in their
GOPATH then, which they'll get with a normal "go get". Building with Go
1.6+ will get our vendored dependencies by default even when not using
our build script, which is nice.

By doing this we gain some freedom in that we can pick and choose
manually what to include in vendor, as it's not based on just dependency
analysis of our own code. This is also a risk as we might pick up
dependencies we are unaware of, as the build may work locally with those
packages present in GOPATH. On the other hand the build server will
detect this as it has no packages in it's GOPATH beyond what is included
in the repo.

Recommended tool to manage dependencies is github.com/FiloSottile/gvt.
This commit is contained in:
Jakob Borg
2016-03-05 21:01:58 +01:00
parent 9259425a9a
commit 65aaa607ab
694 changed files with 65763 additions and 3541 deletions

View File

@@ -0,0 +1,98 @@
package assertion
import (
"fmt"
"reflect"
"github.com/onsi/gomega/types"
)
type Assertion struct {
actualInput interface{}
fail types.GomegaFailHandler
offset int
extra []interface{}
}
func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion {
return &Assertion{
actualInput: actualInput,
fail: fail,
offset: offset,
extra: extra,
}
}
func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
switch len(optionalDescription) {
case 0:
return ""
default:
return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
}
}
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
matches, err := matcher.Match(assertion.actualInput)
description := assertion.buildDescription(optionalDescription...)
if err != nil {
assertion.fail(description+err.Error(), 2+assertion.offset)
return false
}
if matches != desiredMatch {
var message string
if desiredMatch {
message = matcher.FailureMessage(assertion.actualInput)
} else {
message = matcher.NegatedFailureMessage(assertion.actualInput)
}
assertion.fail(description+message, 2+assertion.offset)
return false
}
return true
}
func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
success, message := vetExtras(assertion.extra)
if success {
return true
}
description := assertion.buildDescription(optionalDescription...)
assertion.fail(description+message, 2+assertion.offset)
return false
}
func vetExtras(extras []interface{}) (bool, string) {
for i, extra := range extras {
if extra != nil {
zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface()
if !reflect.DeepEqual(zeroValue, extra) {
message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
return false, message
}
}
}
return true, ""
}

View File

@@ -0,0 +1,13 @@
package assertion_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestAssertion(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Assertion Suite")
}

View File

@@ -0,0 +1,252 @@
package assertion_test
import (
"errors"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/internal/assertion"
"github.com/onsi/gomega/internal/fakematcher"
)
var _ = Describe("Assertion", func() {
var (
a *Assertion
failureMessage string
failureCallerSkip int
matcher *fakematcher.FakeMatcher
)
input := "The thing I'm testing"
var fakeFailHandler = func(message string, callerSkip ...int) {
failureMessage = message
if len(callerSkip) == 1 {
failureCallerSkip = callerSkip[0]
}
}
BeforeEach(func() {
matcher = &fakematcher.FakeMatcher{}
failureMessage = ""
failureCallerSkip = 0
a = New(input, fakeFailHandler, 1)
})
Context("when called", func() {
It("should pass the provided input value to the matcher", func() {
a.Should(matcher)
Ω(matcher.ReceivedActual).Should(Equal(input))
matcher.ReceivedActual = ""
a.ShouldNot(matcher)
Ω(matcher.ReceivedActual).Should(Equal(input))
matcher.ReceivedActual = ""
a.To(matcher)
Ω(matcher.ReceivedActual).Should(Equal(input))
matcher.ReceivedActual = ""
a.ToNot(matcher)
Ω(matcher.ReceivedActual).Should(Equal(input))
matcher.ReceivedActual = ""
a.NotTo(matcher)
Ω(matcher.ReceivedActual).Should(Equal(input))
})
})
Context("when the matcher succeeds", func() {
BeforeEach(func() {
matcher.MatchesToReturn = true
matcher.ErrToReturn = nil
})
Context("and a positive assertion is being made", func() {
It("should not call the failure callback", func() {
a.Should(matcher)
Ω(failureMessage).Should(Equal(""))
})
It("should be true", func() {
Ω(a.Should(matcher)).Should(BeTrue())
})
})
Context("and a negative assertion is being made", func() {
It("should call the failure callback", func() {
a.ShouldNot(matcher)
Ω(failureMessage).Should(Equal("negative: The thing I'm testing"))
Ω(failureCallerSkip).Should(Equal(3))
})
It("should be false", func() {
Ω(a.ShouldNot(matcher)).Should(BeFalse())
})
})
})
Context("when the matcher fails", func() {
BeforeEach(func() {
matcher.MatchesToReturn = false
matcher.ErrToReturn = nil
})
Context("and a positive assertion is being made", func() {
It("should call the failure callback", func() {
a.Should(matcher)
Ω(failureMessage).Should(Equal("positive: The thing I'm testing"))
Ω(failureCallerSkip).Should(Equal(3))
})
It("should be false", func() {
Ω(a.Should(matcher)).Should(BeFalse())
})
})
Context("and a negative assertion is being made", func() {
It("should not call the failure callback", func() {
a.ShouldNot(matcher)
Ω(failureMessage).Should(Equal(""))
})
It("should be true", func() {
Ω(a.ShouldNot(matcher)).Should(BeTrue())
})
})
})
Context("When reporting a failure", func() {
BeforeEach(func() {
matcher.MatchesToReturn = false
matcher.ErrToReturn = nil
})
Context("and there is an optional description", func() {
It("should append the description to the failure message", func() {
a.Should(matcher, "A description")
Ω(failureMessage).Should(Equal("A description\npositive: The thing I'm testing"))
Ω(failureCallerSkip).Should(Equal(3))
})
})
Context("and there are multiple arguments to the optional description", func() {
It("should append the formatted description to the failure message", func() {
a.Should(matcher, "A description of [%d]", 3)
Ω(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing"))
Ω(failureCallerSkip).Should(Equal(3))
})
})
})
Context("When the matcher returns an error", func() {
BeforeEach(func() {
matcher.ErrToReturn = errors.New("Kaboom!")
})
Context("and a positive assertion is being made", func() {
It("should call the failure callback", func() {
matcher.MatchesToReturn = true
a.Should(matcher)
Ω(failureMessage).Should(Equal("Kaboom!"))
Ω(failureCallerSkip).Should(Equal(3))
})
})
Context("and a negative assertion is being made", func() {
It("should call the failure callback", func() {
matcher.MatchesToReturn = false
a.ShouldNot(matcher)
Ω(failureMessage).Should(Equal("Kaboom!"))
Ω(failureCallerSkip).Should(Equal(3))
})
})
It("should always be false", func() {
Ω(a.Should(matcher)).Should(BeFalse())
Ω(a.ShouldNot(matcher)).Should(BeFalse())
})
})
Context("when there are extra parameters", func() {
It("(a simple example)", func() {
Ω(func() (string, int, error) {
return "foo", 0, nil
}()).Should(Equal("foo"))
})
Context("when the parameters are all nil or zero", func() {
It("should invoke the matcher", func() {
matcher.MatchesToReturn = true
matcher.ErrToReturn = nil
var typedNil []string
a = New(input, fakeFailHandler, 1, 0, nil, typedNil)
result := a.Should(matcher)
Ω(result).Should(BeTrue())
Ω(matcher.ReceivedActual).Should(Equal(input))
Ω(failureMessage).Should(BeZero())
})
})
Context("when any of the parameters are not nil or zero", func() {
It("should call the failure callback", func() {
matcher.MatchesToReturn = false
matcher.ErrToReturn = nil
a = New(input, fakeFailHandler, 1, errors.New("foo"))
result := a.Should(matcher)
Ω(result).Should(BeFalse())
Ω(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called")
Ω(failureMessage).Should(ContainSubstring("foo"))
failureMessage = ""
a = New(input, fakeFailHandler, 1, nil, 1)
result = a.ShouldNot(matcher)
Ω(result).Should(BeFalse())
Ω(failureMessage).Should(ContainSubstring("1"))
failureMessage = ""
a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
result = a.To(matcher)
Ω(result).Should(BeFalse())
Ω(failureMessage).Should(ContainSubstring("foo"))
failureMessage = ""
a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
result = a.ToNot(matcher)
Ω(result).Should(BeFalse())
Ω(failureMessage).Should(ContainSubstring("foo"))
failureMessage = ""
a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
result = a.NotTo(matcher)
Ω(result).Should(BeFalse())
Ω(failureMessage).Should(ContainSubstring("foo"))
Ω(failureCallerSkip).Should(Equal(3))
})
})
})
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 occurred")
}
}()
RegisterFailHandler(nil)
Ω(true).Should(BeTrue())
})
})
})

View File

@@ -0,0 +1,189 @@
package asyncassertion
import (
"errors"
"fmt"
"reflect"
"time"
"github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
type AsyncAssertionType uint
const (
AsyncAssertionTypeEventually AsyncAssertionType = iota
AsyncAssertionTypeConsistently
)
type AsyncAssertion struct {
asyncType AsyncAssertionType
actualInput interface{}
timeoutInterval time.Duration
pollingInterval time.Duration
fail types.GomegaFailHandler
offset int
}
func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
actualType := reflect.TypeOf(actualInput)
if actualType.Kind() == reflect.Func {
if actualType.NumIn() != 0 || actualType.NumOut() == 0 {
panic("Expected a function with no arguments and one or more return values.")
}
}
return &AsyncAssertion{
asyncType: asyncType,
actualInput: actualInput,
fail: fail,
timeoutInterval: timeoutInterval,
pollingInterval: pollingInterval,
offset: offset,
}
}
func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.match(matcher, true, optionalDescription...)
}
func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
return assertion.match(matcher, false, optionalDescription...)
}
func (assertion *AsyncAssertion) buildDescription(optionalDescription ...interface{}) string {
switch len(optionalDescription) {
case 0:
return ""
default:
return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
}
}
func (assertion *AsyncAssertion) actualInputIsAFunction() bool {
actualType := reflect.TypeOf(assertion.actualInput)
return actualType.Kind() == reflect.Func && actualType.NumIn() == 0 && actualType.NumOut() > 0
}
func (assertion *AsyncAssertion) pollActual() (interface{}, error) {
if assertion.actualInputIsAFunction() {
values := reflect.ValueOf(assertion.actualInput).Call([]reflect.Value{})
extras := []interface{}{}
for _, value := range values[1:] {
extras = append(extras, value.Interface())
}
success, message := vetExtras(extras)
if !success {
return nil, errors.New(message)
}
return values[0].Interface(), nil
}
return assertion.actualInput, nil
}
func (assertion *AsyncAssertion) matcherMayChange(matcher types.GomegaMatcher, value interface{}) bool {
if assertion.actualInputIsAFunction() {
return true
}
return oraclematcher.MatchMayChangeInTheFuture(matcher, value)
}
func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
timer := time.Now()
timeout := time.After(assertion.timeoutInterval)
description := assertion.buildDescription(optionalDescription...)
var matches bool
var err error
mayChange := true
value, err := assertion.pollActual()
if err == nil {
mayChange = assertion.matcherMayChange(matcher, value)
matches, err = matcher.Match(value)
}
fail := func(preamble string) {
errMsg := ""
message := ""
if err != nil {
errMsg = "Error: " + err.Error()
} else {
if desiredMatch {
message = matcher.FailureMessage(value)
} else {
message = matcher.NegatedFailureMessage(value)
}
}
assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
}
if assertion.asyncType == AsyncAssertionTypeEventually {
for {
if err == nil && matches == desiredMatch {
return true
}
if !mayChange {
fail("No future change is possible. Bailing out early")
return false
}
select {
case <-time.After(assertion.pollingInterval):
value, err = assertion.pollActual()
if err == nil {
mayChange = assertion.matcherMayChange(matcher, value)
matches, err = matcher.Match(value)
}
case <-timeout:
fail("Timed out")
return false
}
}
} else if assertion.asyncType == AsyncAssertionTypeConsistently {
for {
if !(err == nil && matches == desiredMatch) {
fail("Failed")
return false
}
if !mayChange {
return true
}
select {
case <-time.After(assertion.pollingInterval):
value, err = assertion.pollActual()
if err == nil {
mayChange = assertion.matcherMayChange(matcher, value)
matches, err = matcher.Match(value)
}
case <-timeout:
return true
}
}
}
return false
}
func vetExtras(extras []interface{}) (bool, string) {
for i, extra := range extras {
if extra != nil {
zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface()
if !reflect.DeepEqual(zeroValue, extra) {
message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
return false, message
}
}
}
return true, ""
}

View File

@@ -0,0 +1,13 @@
package asyncassertion_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestAsyncAssertion(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "AsyncAssertion Suite")
}

View File

@@ -0,0 +1,345 @@
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 occurred")
}
}()
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 occurred")
}
}()
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))
})
})
})
})

View File

@@ -0,0 +1,23 @@
package fakematcher
import "fmt"
type FakeMatcher struct {
ReceivedActual interface{}
MatchesToReturn bool
ErrToReturn error
}
func (matcher *FakeMatcher) Match(actual interface{}) (bool, error) {
matcher.ReceivedActual = actual
return matcher.MatchesToReturn, matcher.ErrToReturn
}
func (matcher *FakeMatcher) FailureMessage(actual interface{}) string {
return fmt.Sprintf("positive: %v", actual)
}
func (matcher *FakeMatcher) NegatedFailureMessage(actual interface{}) string {
return fmt.Sprintf("negative: %v", actual)
}

View File

@@ -0,0 +1,25 @@
package oraclematcher
import "github.com/onsi/gomega/types"
/*
GomegaMatchers that also match the OracleMatcher interface can convey information about
whether or not their result will change upon future attempts.
This allows `Eventually` and `Consistently` to short circuit if success becomes impossible.
For example, a process' exit code can never change. So, gexec's Exit matcher returns `true`
for `MatchMayChangeInTheFuture` until the process exits, at which point it returns `false` forevermore.
*/
type OracleMatcher interface {
MatchMayChangeInTheFuture(actual interface{}) bool
}
func MatchMayChangeInTheFuture(matcher types.GomegaMatcher, value interface{}) bool {
oracleMatcher, ok := matcher.(OracleMatcher)
if !ok {
return true
}
return oracleMatcher.MatchMayChangeInTheFuture(value)
}

View File

@@ -0,0 +1,40 @@
package testingtsupport
import (
"regexp"
"runtime/debug"
"strings"
"github.com/onsi/gomega/types"
)
type gomegaTestingT interface {
Errorf(format string, args ...interface{})
}
func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler {
return func(message string, callerSkip ...int) {
skip := 1
if len(callerSkip) > 0 {
skip = callerSkip[0]
}
stackTrace := pruneStack(string(debug.Stack()), skip)
t.Errorf("\n%s\n%s", stackTrace, message)
}
}
func pruneStack(fullStackTrace string, skip int) string {
stack := strings.Split(fullStackTrace, "\n")
if len(stack) > 2*(skip+1) {
stack = stack[2*(skip+1):]
}
prunedStack := []string{}
re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
for i := 0; i < len(stack)/2; i++ {
if !re.Match([]byte(stack[i*2])) {
prunedStack = append(prunedStack, stack[i*2])
prunedStack = append(prunedStack, stack[i*2+1])
}
}
return strings.Join(prunedStack, "\n")
}

View File

@@ -0,0 +1,12 @@
package testingtsupport_test
import (
. "github.com/onsi/gomega"
"testing"
)
func TestTestingT(t *testing.T) {
RegisterTestingT(t)
Ω(true).Should(BeTrue())
}