bump gomega to 1.29.0

This commit is contained in:
carlory
2023-10-26 09:47:49 +08:00
parent ebf46ce1b4
commit 760abc2a82
76 changed files with 368 additions and 296 deletions

View File

@@ -1,3 +1,17 @@
## 1.29.0
### Features
- MatchError can now take an optional func(error) bool + description [2b39142]
## 1.28.1
### Maintenance
- Bump github.com/onsi/ginkgo/v2 from 2.12.0 to 2.13.0 [635d196]
- Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 [14f8859]
- Bump golang.org/x/net from 0.14.0 to 0.17.0 [d8a6508]
- #703 doc(matchers): HaveEach() doc comment updated [2705bdb]
- Minor typos (#699) [375648c]
## 1.28.0
### Features

View File

@@ -22,7 +22,7 @@ import (
"github.com/onsi/gomega/types"
)
const GOMEGA_VERSION = "1.28.0"
const GOMEGA_VERSION = "1.29.0"
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
@@ -242,7 +242,7 @@ func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Asse
Eventually enables making assertions on asynchronous behavior.
Eventually checks that an assertion *eventually* passes. Eventually blocks when called and attempts an assertion periodically until it passes or a timeout occurs. Both the timeout and polling interval are configurable as optional arguments.
The first optional argument is the timeout (which defaults to 1s), the second is the polling interval (which defaults to 10ms). Both intervals can be specified as time.Duration, parsable duration strings or floats/integers (in which case they are interpreted as seconds). In addition an optional context.Context can be passed in - Eventually will keep trying until either the timeout epxires or the context is cancelled, whichever comes first.
The first optional argument is the timeout (which defaults to 1s), the second is the polling interval (which defaults to 10ms). Both intervals can be specified as time.Duration, parsable duration strings or floats/integers (in which case they are interpreted as seconds). In addition an optional context.Context can be passed in - Eventually will keep trying until either the timeout expires or the context is cancelled, whichever comes first.
Eventually works with any Gomega compatible matcher and supports making assertions against three categories of actual value:
@@ -313,13 +313,13 @@ It is important to note that the function passed into Eventually is invoked *syn
}).Should(BeNumerically(">=", 17))
}, SpecTimeout(time.Second))
you an also use Eventually().WithContext(ctx) to pass in the context. Passed-in contexts play nicely with paseed-in arguments as long as the context appears first. You can rewrite the above example as:
you an also use Eventually().WithContext(ctx) to pass in the context. Passed-in contexts play nicely with passed-in arguments as long as the context appears first. You can rewrite the above example as:
It("fetches the correct count", func(ctx SpecContext) {
Eventually(client.FetchCount).WithContext(ctx).WithArguments("/users").Should(BeNumerically(">=", 17))
}, SpecTimeout(time.Second))
Either way the context passd to Eventually is also passed to the underlying funciton. Now, when Ginkgo cancels the context both the FetchCount client and Gomega will be informed and can exit.
Either way the context passd to Eventually is also passed to the underlying function. Now, when Ginkgo cancels the context both the FetchCount client and Gomega will be informed and can exit.
**Category 3: Making assertions _in_ the function passed into Eventually**
@@ -349,7 +349,7 @@ For example:
will rerun the function until all assertions pass.
You can also pass additional arugments to functions that take a Gomega. The only rule is that the Gomega argument must be first. If you also want to pass the context attached to Eventually you must ensure that is the second argument. For example:
You can also pass additional arguments to functions that take a Gomega. The only rule is that the Gomega argument must be first. If you also want to pass the context attached to Eventually you must ensure that is the second argument. For example:
Eventually(func(g Gomega, ctx context.Context, path string, expected ...string){
tok, err := client.GetToken(ctx)

View File

@@ -88,19 +88,44 @@ func Succeed() types.GomegaMatcher {
}
// MatchError succeeds if actual is a non-nil error that matches the passed in
// string, error, or matcher.
// string, error, function, or matcher.
//
// These are valid use-cases:
//
// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
// Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that err.Error() contains substring "sprocket not found"
// When passed a string:
//
// Expect(err).To(MatchError("an error"))
//
// asserts that err.Error() == "an error"
//
// When passed an error:
//
// Expect(err).To(MatchError(SomeError))
//
// First checks if errors.Is(err, SomeError).
// If that fails then it checks if reflect.DeepEqual(err, SomeError) repeatedly for err and any errors wrapped by err
//
// When passed a matcher:
//
// Expect(err).To(MatchError(ContainSubstring("sprocket not found")))
//
// the matcher is passed err.Error(). In this case it asserts that err.Error() contains substring "sprocket not found"
//
// When passed a func(err) bool and a description:
//
// Expect(err).To(MatchError(os.IsNotExist, "IsNotExist"))
//
// the function is passed err and matches if the return value is true. The description is required to allow Gomega
// to print a useful error message.
//
// It is an error for err to be nil or an object that does not implement the
// Error interface
func MatchError(expected interface{}) types.GomegaMatcher {
//
// The optional second argument is a description of the error function, if used. This is required when passing a function but is ignored in all other cases.
func MatchError(expected interface{}, functionErrorDescription ...any) types.GomegaMatcher {
return &matchers.MatchErrorMatcher{
Expected: expected,
Expected: expected,
FuncErrDescription: functionErrorDescription,
}
}
@@ -381,7 +406,7 @@ func ContainElements(elements ...interface{}) types.GomegaMatcher {
}
// HaveEach succeeds if actual solely contains elements that match the passed in element.
// Please note that if actual is empty, HaveEach always will succeed.
// Please note that if actual is empty, HaveEach always will fail.
// By default HaveEach() uses Equal() to perform the match, however a
// matcher can be passed in instead:
//

View File

@@ -9,10 +9,14 @@ import (
)
type MatchErrorMatcher struct {
Expected interface{}
Expected any
FuncErrDescription []any
isFunc bool
}
func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err error) {
func (matcher *MatchErrorMatcher) Match(actual any) (success bool, err error) {
matcher.isFunc = false
if isNil(actual) {
return false, fmt.Errorf("Expected an error, got nil")
}
@@ -42,6 +46,17 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e
return actualErr.Error() == expected, nil
}
v := reflect.ValueOf(expected)
t := v.Type()
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
if t.Kind() == reflect.Func && t.NumIn() == 1 && t.In(0).Implements(errorInterface) && t.NumOut() == 1 && t.Out(0).Kind() == reflect.Bool {
if len(matcher.FuncErrDescription) == 0 {
return false, fmt.Errorf("MatchError requires an additional description when passed a function")
}
matcher.isFunc = true
return v.Call([]reflect.Value{reflect.ValueOf(actualErr)})[0].Bool(), nil
}
var subMatcher omegaMatcher
var hasSubMatcher bool
if expected != nil {
@@ -57,9 +72,15 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e
}
func (matcher *MatchErrorMatcher) FailureMessage(actual interface{}) (message string) {
if matcher.isFunc {
return format.Message(actual, fmt.Sprintf("to match error function %s", matcher.FuncErrDescription[0]))
}
return format.Message(actual, "to match error", matcher.Expected)
}
func (matcher *MatchErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) {
if matcher.isFunc {
return format.Message(actual, fmt.Sprintf("not to match error function %s", matcher.FuncErrDescription[0]))
}
return format.Message(actual, "not to match error", matcher.Expected)
}