pull oracle matcher into its own package
diff --git a/internal/asyncassertion/async_assertion.go b/internal/asyncassertion/async_assertion.go index b007383..bce0853 100644 --- a/internal/asyncassertion/async_assertion.go +++ b/internal/asyncassertion/async_assertion.go
@@ -6,6 +6,7 @@ "reflect" "time" + "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) @@ -86,27 +87,12 @@ return assertion.actualInput, nil } -type oracleMatcher interface { - MatchMayChangeInTheFuture(actual interface{}) bool -} - func (assertion *AsyncAssertion) matcherMayChange(matcher types.GomegaMatcher, value interface{}) bool { if assertion.actualInputIsAFunction() { return true } - return MatchMayChangeInTheFuture(matcher, value) -} - -//MatchMayChangeInTheFuture is a helper to call MatchMayChangeInTheFuture on an unknown matcher. -//If matcher implements oracleMatcher, it will call the method. Otherwise just returns true. -func MatchMayChangeInTheFuture(matcher types.GomegaMatcher, value interface{}) bool { - oracleMatcher, ok := matcher.(oracleMatcher) - if !ok { - return true - } - - return oracleMatcher.MatchMayChangeInTheFuture(value) + return oraclematcher.MatchMayChangeInTheFuture(matcher, value) } func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
diff --git a/internal/oraclematcher/oracle_matcher.go b/internal/oraclematcher/oracle_matcher.go new file mode 100644 index 0000000..66cad88 --- /dev/null +++ b/internal/oraclematcher/oracle_matcher.go
@@ -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) +}
diff --git a/matchers/and.go b/matchers/and.go index 5257b76..94c42a7 100644 --- a/matchers/and.go +++ b/matchers/and.go
@@ -2,8 +2,9 @@ import ( "fmt" + "github.com/onsi/gomega/format" - "github.com/onsi/gomega/internal/asyncassertion" + "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) @@ -51,13 +52,13 @@ if m.firstFailedMatcher == nil { // so all matchers succeeded.. Any one of them changing would change the result. for _, matcher := range m.Matchers { - if asyncassertion.MatchMayChangeInTheFuture(matcher, actual) { + if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) { return true } } return false // none of were going to change } else { // one of the matchers failed.. it must be able to change in order to affect the result - return asyncassertion.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual) + return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual) } }
diff --git a/matchers/matcher_tests_suite_test.go b/matchers/matcher_tests_suite_test.go index 4bc6d9d..01b11b9 100644 --- a/matchers/matcher_tests_suite_test.go +++ b/matchers/matcher_tests_suite_test.go
@@ -2,6 +2,7 @@ import ( "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -25,5 +26,5 @@ func Test(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Gomega") + RunSpecs(t, "Gomega Matchers") }
diff --git a/matchers/not.go b/matchers/not.go index 6aed858..2c91670 100644 --- a/matchers/not.go +++ b/matchers/not.go
@@ -1,7 +1,7 @@ package matchers import ( - "github.com/onsi/gomega/internal/asyncassertion" + "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) @@ -26,5 +26,5 @@ } func (m *NotMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { - return asyncassertion.MatchMayChangeInTheFuture(m.Matcher, actual) // just return m.Matcher's value + return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, actual) // just return m.Matcher's value }
diff --git a/matchers/or.go b/matchers/or.go index 29ad5c6..3bf7998 100644 --- a/matchers/or.go +++ b/matchers/or.go
@@ -2,8 +2,9 @@ import ( "fmt" + "github.com/onsi/gomega/format" - "github.com/onsi/gomega/internal/asyncassertion" + "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) @@ -53,11 +54,11 @@ if m.firstSuccessfulMatcher != nil { // one of the matchers succeeded.. it must be able to change in order to affect the result - return asyncassertion.MatchMayChangeInTheFuture(m.firstSuccessfulMatcher, actual) + return oraclematcher.MatchMayChangeInTheFuture(m.firstSuccessfulMatcher, actual) } else { // so all matchers failed.. Any one of them changing would change the result. for _, matcher := range m.Matchers { - if asyncassertion.MatchMayChangeInTheFuture(matcher, actual) { + if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) { return true } }
diff --git a/matchers/with_transform.go b/matchers/with_transform.go index 21d9fe0..8e58d8a 100644 --- a/matchers/with_transform.go +++ b/matchers/with_transform.go
@@ -2,9 +2,10 @@ import ( "fmt" - "github.com/onsi/gomega/internal/asyncassertion" - "github.com/onsi/gomega/types" "reflect" + + "github.com/onsi/gomega/internal/oraclematcher" + "github.com/onsi/gomega/types" ) type WithTransformMatcher struct { @@ -67,5 +68,5 @@ // Querying the next matcher is fine if the transformer always will return the same value. // But if the transformer is non-deterministic and returns a different value each time, then there // is no point in querying the next matcher, since it can only comment on the last transformed value. - return asyncassertion.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue) + return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue) }