rebase: bump github.com/onsi/gomega from 1.16.0 to 1.17.0

Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot] 2021-11-08 20:26:59 +00:00 committed by mergify[bot]
parent 335c945d97
commit 50832f4f06
14 changed files with 252 additions and 40 deletions

2
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0
github.com/libopenstorage/secrets v0.0.0-20210908194121-a1d19aa9713a github.com/libopenstorage/secrets v0.0.0-20210908194121-a1d19aa9713a
github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.16.0 github.com/onsi/gomega v1.17.0
github.com/pborman/uuid v1.2.1 github.com/pborman/uuid v1.2.1
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0

4
go.sum
View File

@ -826,8 +826,8 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=

View File

@ -1,3 +1,15 @@
## 1.17.0
### Features
- Add HaveField matcher [3a26311]
- add Error() assertions on the final error value of multi-return values (#480) [2f96943]
- separate out offsets and timeouts (#478) [18a4723]
- fix transformation error reporting (#479) [e001fab]
- allow transform functions to report errors (#472) [bf93408]
### Fixes
Stop using deprecated ioutil package (#467) [07f405d]
## 1.16.0 ## 1.16.0
### Features ### Features

View File

@ -22,7 +22,7 @@ import (
"github.com/onsi/gomega/types" "github.com/onsi/gomega/types"
) )
const GOMEGA_VERSION = "1.16.0" const GOMEGA_VERSION = "1.17.0"
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler. 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(). If you're using Ginkgo then you probably forgot to put your assertion in an It().
@ -204,7 +204,8 @@ func Expect(actual interface{}, extra ...interface{}) Assertion {
// ExpectWithOffset(1, "foo").To(Equal("foo")) // ExpectWithOffset(1, "foo").To(Equal("foo"))
// //
// Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument // Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument
// that is used to modify the call-stack offset when computing line numbers. // that is used to modify the call-stack offset when computing line numbers. It is
// the same as `Expect(...).WithOffset`.
// //
// This is most useful in helper functions that make assertions. If you want Gomega's // This is most useful in helper functions that make assertions. If you want Gomega's
// error message to refer to the calling line in the test (as opposed to the line in the helper function) // error message to refer to the calling line in the test (as opposed to the line in the helper function)
@ -300,6 +301,9 @@ For example:
}).Should(Succeed()) }).Should(Succeed())
will rerun the function until all assertions pass. will rerun the function until all assertions pass.
`Eventually` specifying a timeout interval (and an optional polling interval) are
the same as `Eventually(...).WithTimeout` or `Eventually(...).WithTimeout(...).WithPolling`.
*/ */
func Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion { func Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
ensureDefaultGomegaIsConfigured() ensureDefaultGomegaIsConfigured()
@ -309,6 +313,12 @@ func Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
// EventuallyWithOffset operates like Eventually but takes an additional // EventuallyWithOffset operates like Eventually but takes an additional
// initial argument to indicate an offset in the call stack. This is useful when building helper // initial argument to indicate an offset in the call stack. This is useful when building helper
// functions that contain matchers. To learn more, read about `ExpectWithOffset`. // functions that contain matchers. To learn more, read about `ExpectWithOffset`.
//
// `EventuallyWithOffset` is the same as `Eventually(...).WithOffset`.
//
// `EventuallyWithOffset` specifying a timeout interval (and an optional polling interval) are
// the same as `Eventually(...).WithOffset(...).WithTimeout` or
// `Eventually(...).WithOffset(...).WithTimeout(...).WithPolling`.
func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion { func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
ensureDefaultGomegaIsConfigured() ensureDefaultGomegaIsConfigured()
return Default.EventuallyWithOffset(offset, actual, intervals...) return Default.EventuallyWithOffset(offset, actual, intervals...)
@ -337,6 +347,9 @@ func Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
// ConsistentlyWithOffset operates like Consistently but takes an additional // ConsistentlyWithOffset operates like Consistently but takes an additional
// initial argument to indicate an offset in the call stack. This is useful when building helper // initial argument to indicate an offset in the call stack. This is useful when building helper
// functions that contain matchers. To learn more, read about `ExpectWithOffset`. // functions that contain matchers. To learn more, read about `ExpectWithOffset`.
//
// `ConsistentlyWithOffset` is the same as `Consistently(...).WithOffset` and
// optional `WithTimeout` and `WithPolling`.
func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion { func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
ensureDefaultGomegaIsConfigured() ensureDefaultGomegaIsConfigured()
return Default.ConsistentlyWithOffset(offset, actual, intervals...) return Default.ConsistentlyWithOffset(offset, actual, intervals...)

View File

@ -8,44 +8,64 @@ import (
) )
type Assertion struct { type Assertion struct {
actualInput interface{} actuals []interface{} // actual value plus all extra values
actualIndex int // value to pass to the matcher
vet vetinari // the vet to call before calling Gomega matcher
offset int offset int
extra []interface{}
g *Gomega g *Gomega
} }
// ...obligatory discworld reference, as "vetineer" doesn't sound ... quite right.
type vetinari func(assertion *Assertion, optionalDescription ...interface{}) bool
func NewAssertion(actualInput interface{}, g *Gomega, offset int, extra ...interface{}) *Assertion { func NewAssertion(actualInput interface{}, g *Gomega, offset int, extra ...interface{}) *Assertion {
return &Assertion{ return &Assertion{
actualInput: actualInput, actuals: append([]interface{}{actualInput}, extra...),
actualIndex: 0,
vet: (*Assertion).vetActuals,
offset: offset, offset: offset,
extra: extra,
g: g, g: g,
} }
} }
func (assertion *Assertion) WithOffset(offset int) types.Assertion {
assertion.offset = offset
return assertion
}
func (assertion *Assertion) Error() types.Assertion {
return &Assertion{
actuals: assertion.actuals,
actualIndex: len(assertion.actuals) - 1,
vet: (*Assertion).vetError,
offset: assertion.offset,
g: assertion.g,
}
}
func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
} }
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
} }
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string { func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
@ -61,7 +81,8 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{})
} }
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
matches, err := matcher.Match(assertion.actualInput) actualInput := assertion.actuals[assertion.actualIndex]
matches, err := matcher.Match(actualInput)
assertion.g.THelper() assertion.g.THelper()
if err != nil { if err != nil {
description := assertion.buildDescription(optionalDescription...) description := assertion.buildDescription(optionalDescription...)
@ -71,9 +92,9 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool
if matches != desiredMatch { if matches != desiredMatch {
var message string var message string
if desiredMatch { if desiredMatch {
message = matcher.FailureMessage(assertion.actualInput) message = matcher.FailureMessage(actualInput)
} else { } else {
message = matcher.NegatedFailureMessage(assertion.actualInput) message = matcher.NegatedFailureMessage(actualInput)
} }
description := assertion.buildDescription(optionalDescription...) description := assertion.buildDescription(optionalDescription...)
assertion.g.Fail(description+message, 2+assertion.offset) assertion.g.Fail(description+message, 2+assertion.offset)
@ -83,8 +104,11 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool
return true return true
} }
func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool { // vetActuals vets the actual values, with the (optional) exception of a
success, message := vetExtras(assertion.extra) // specific value, such as the first value in case non-error assertions, or the
// last value in case of Error()-based assertions.
func (assertion *Assertion) vetActuals(optionalDescription ...interface{}) bool {
success, message := vetActuals(assertion.actuals, assertion.actualIndex)
if success { if success {
return true return true
} }
@ -95,12 +119,29 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
return false return false
} }
func vetExtras(extras []interface{}) (bool, string) { // vetError vets the actual values, except for the final error value, in case
for i, extra := range extras { // the final error value is non-zero. Otherwise, it doesn't vet the actual
if extra != nil { // values, as these are allowed to take on any values unless there is a non-zero
zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface() // error value.
if !reflect.DeepEqual(zeroValue, extra) { func (assertion *Assertion) vetError(optionalDescription ...interface{}) bool {
message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra) if err := assertion.actuals[assertion.actualIndex]; err != nil {
// Go error result idiom: all other actual values must be zero values.
return assertion.vetActuals(optionalDescription...)
}
return true
}
// vetActuals vets a slice of actual values, optionally skipping a particular
// value slice element, such as the first or last value slice element.
func vetActuals(actuals []interface{}, skipIndex int) (bool, string) {
for i, actual := range actuals {
if i == skipIndex {
continue
}
if actual != nil {
zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface()
if !reflect.DeepEqual(zeroValue, actual) {
message := fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
return false, message return false, message
} }
} }

View File

@ -87,6 +87,21 @@ func NewAsyncAssertion(asyncType AsyncAssertionType, actualInput interface{}, g
return out return out
} }
func (assertion *AsyncAssertion) WithOffset(offset int) types.AsyncAssertion {
assertion.offset = offset
return assertion
}
func (assertion *AsyncAssertion) WithTimeout(interval time.Duration) types.AsyncAssertion {
assertion.timeoutInterval = interval
return assertion
}
func (assertion *AsyncAssertion) WithPolling(interval time.Duration) types.AsyncAssertion {
assertion.pollingInterval = interval
return assertion
}
func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper() assertion.g.THelper()
return assertion.match(matcher, true, optionalDescription...) return assertion.match(matcher, true, optionalDescription...)
@ -118,11 +133,11 @@ func (assertion *AsyncAssertion) pollActual() (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
extras := []interface{}{} extras := []interface{}{nil}
for _, value := range values[1:] { for _, value := range values[1:] {
extras = append(extras, value.Interface()) extras = append(extras, value.Interface())
} }
success, message := vetExtras(extras) success, message := vetActuals(extras, 0)
if !success { if !success {
return nil, errors.New(message) return nil, errors.New(message)
} }

View File

@ -39,12 +39,12 @@ func (g *Gomega) ConfigureWithT(t types.GomegaTestingT) *Gomega {
return g return g
} }
func (g *Gomega) Ω(atual interface{}, extra ...interface{}) types.Assertion { func (g *Gomega) Ω(actual interface{}, extra ...interface{}) types.Assertion {
return g.ExpectWithOffset(0, atual, extra...) return g.ExpectWithOffset(0, actual, extra...)
} }
func (g *Gomega) Expect(atual interface{}, extra ...interface{}) types.Assertion { func (g *Gomega) Expect(actual interface{}, extra ...interface{}) types.Assertion {
return g.ExpectWithOffset(0, atual, extra...) return g.ExpectWithOffset(0, actual, extra...)
} }
func (g *Gomega) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) types.Assertion { func (g *Gomega) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) types.Assertion {

View File

@ -342,6 +342,34 @@ func HaveKeyWithValue(key interface{}, value interface{}) types.GomegaMatcher {
} }
} }
//HaveField succeeds if actual is a struct and the value at the passed in field
//matches the passed in matcher. By default HaveField used Equal() to perform the match,
//however a matcher can be passed in in stead.
//
//The field must be a string that resolves to the name of a field in the struct. Structs can be traversed
//using the '.' delimiter. If the field ends with '()' a method named field is assumed to exist on the struct and is invoked.
//Such methods must take no arguments and return a single value:
//
// type Book struct {
// Title string
// Author Person
// }
// type Person struct {
// FirstName string
// LastName string
// DOB time.Time
// }
// Expect(book).To(HaveField("Title", "Les Miserables"))
// Expect(book).To(HaveField("Title", ContainSubstring("Les"))
// Expect(book).To(HaveField("Person.FirstName", Equal("Victor"))
// Expect(book).To(HaveField("Person.DOB.Year()", BeNumerically("<", 1900))
func HaveField(field string, expected interface{}) types.GomegaMatcher {
return &matchers.HaveFieldMatcher{
Field: field,
Expected: expected,
}
}
//BeNumerically performs numerical assertions in a type-agnostic way. //BeNumerically performs numerical assertions in a type-agnostic way.
//Actual and expected should be numbers, though the specific type of //Actual and expected should be numbers, though the specific type of
//number is irrelevant (float32, float64, uint8, etc...). //number is irrelevant (float32, float64, uint8, etc...).
@ -485,10 +513,15 @@ func Not(matcher types.GomegaMatcher) types.GomegaMatcher {
} }
//WithTransform applies the `transform` to the actual value and matches it against `matcher`. //WithTransform applies the `transform` to the actual value and matches it against `matcher`.
//The given transform must be a function of one parameter that returns one value. //The given transform must be either a function of one parameter that returns one value or a
// function of one parameter that returns two values, where the second value must be of the
// error type.
// var plus1 = func(i int) int { return i + 1 } // var plus1 = func(i int) int { return i + 1 }
// Expect(1).To(WithTransform(plus1, Equal(2)) // Expect(1).To(WithTransform(plus1, Equal(2))
// //
// var failingplus1 = func(i int) (int, error) { return 42, "this does not compute" }
// Expect(1).To(WithTransform(failingplus1, Equal(2)))
//
//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions. //And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher { func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher {
return matchers.NewWithTransformMatcher(transform, matcher) return matchers.NewWithTransformMatcher(transform, matcher)

80
vendor/github.com/onsi/gomega/matchers/have_field.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
package matchers
import (
"fmt"
"reflect"
"strings"
"github.com/onsi/gomega/format"
)
func extractField(actual interface{}, field string) (interface{}, error) {
fields := strings.SplitN(field, ".", 2)
actualValue := reflect.ValueOf(actual)
if actualValue.Kind() != reflect.Struct {
return nil, fmt.Errorf("HaveField encountered:\n%s\nWhich is not a struct.", format.Object(actual, 1))
}
var extractedValue reflect.Value
if strings.HasSuffix(fields[0], "()") {
extractedValue = actualValue.MethodByName(strings.TrimSuffix(fields[0], "()"))
if extractedValue == (reflect.Value{}) {
return nil, fmt.Errorf("HaveField could not find method named '%s' in struct of type %T.", fields[0], actual)
}
t := extractedValue.Type()
if t.NumIn() != 0 || t.NumOut() != 1 {
return nil, fmt.Errorf("HaveField found an invalid method named '%s' in struct of type %T.\nMethods must take no arguments and return exactly one value.", fields[0], actual)
}
extractedValue = extractedValue.Call([]reflect.Value{})[0]
} else {
extractedValue = actualValue.FieldByName(fields[0])
if extractedValue == (reflect.Value{}) {
return nil, fmt.Errorf("HaveField could not find field named '%s' in struct:\n%s", fields[0], format.Object(actual, 1))
}
}
if len(fields) == 1 {
return extractedValue.Interface(), nil
} else {
return extractField(extractedValue.Interface(), fields[1])
}
}
type HaveFieldMatcher struct {
Field string
Expected interface{}
extractedField interface{}
expectedMatcher omegaMatcher
}
func (matcher *HaveFieldMatcher) Match(actual interface{}) (success bool, err error) {
matcher.extractedField, err = extractField(actual, matcher.Field)
if err != nil {
return false, err
}
var isMatcher bool
matcher.expectedMatcher, isMatcher = matcher.Expected.(omegaMatcher)
if !isMatcher {
matcher.expectedMatcher = &EqualMatcher{Expected: matcher.Expected}
}
return matcher.expectedMatcher.Match(matcher.extractedField)
}
func (matcher *HaveFieldMatcher) FailureMessage(actual interface{}) (message string) {
message = fmt.Sprintf("Value for field '%s' failed to satisfy matcher.\n", matcher.Field)
message += matcher.expectedMatcher.FailureMessage(matcher.extractedField)
return message
}
func (matcher *HaveFieldMatcher) NegatedFailureMessage(actual interface{}) (message string) {
message = fmt.Sprintf("Value for field '%s' satisfied matcher, but should not have.\n", matcher.Field)
message += matcher.expectedMatcher.NegatedFailureMessage(matcher.extractedField)
return message
}

View File

@ -2,7 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -81,7 +81,7 @@ func (matcher *HaveHTTPBodyMatcher) body(actual interface{}) ([]byte, error) {
if a.Body != nil { if a.Body != nil {
defer a.Body.Close() defer a.Body.Close()
var err error var err error
matcher.cachedBody, err = ioutil.ReadAll(a.Body) matcher.cachedBody, err = io.ReadAll(a.Body)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err) return nil, fmt.Errorf("error reading response body: %w", err)
} }

View File

@ -2,7 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"reflect" "reflect"
@ -78,7 +78,7 @@ func formatHttpResponse(input interface{}) string {
body := "<nil>" body := "<nil>"
if resp.Body != nil { if resp.Body != nil {
defer resp.Body.Close() defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body) data, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
data = []byte("<error reading body>") data = []byte("<error reading body>")
} }

View File

@ -9,7 +9,7 @@ import (
type WithTransformMatcher struct { type WithTransformMatcher struct {
// input // input
Transform interface{} // must be a function of one parameter that returns one value Transform interface{} // must be a function of one parameter that returns one value and an optional error
Matcher types.GomegaMatcher Matcher types.GomegaMatcher
// cached value // cached value
@ -19,6 +19,9 @@ type WithTransformMatcher struct {
transformedValue interface{} transformedValue interface{}
} }
// reflect.Type for error
var errorT = reflect.TypeOf((*error)(nil)).Elem()
func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher) *WithTransformMatcher { func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher) *WithTransformMatcher {
if transform == nil { if transform == nil {
panic("transform function cannot be nil") panic("transform function cannot be nil")
@ -27,8 +30,10 @@ func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher)
if txType.NumIn() != 1 { if txType.NumIn() != 1 {
panic("transform function must have 1 argument") panic("transform function must have 1 argument")
} }
if txType.NumOut() != 1 { if numout := txType.NumOut(); numout != 1 {
panic("transform function must have 1 return value") if numout != 2 || !txType.Out(1).AssignableTo(errorT) {
panic("transform function must either have 1 return value, or 1 return value plus 1 error value")
}
} }
return &WithTransformMatcher{ return &WithTransformMatcher{
@ -57,6 +62,11 @@ func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) {
// call the Transform function with `actual` // call the Transform function with `actual`
fn := reflect.ValueOf(m.Transform) fn := reflect.ValueOf(m.Transform)
result := fn.Call([]reflect.Value{param}) result := fn.Call([]reflect.Value{param})
if len(result) == 2 {
if !result[1].IsNil() {
return false, fmt.Errorf("Transform function failed: %s", result[1].Interface().(error).Error())
}
}
m.transformedValue = result[0].Interface() // expect exactly one value m.transformedValue = result[0].Interface() // expect exactly one value
return m.Matcher.Match(m.transformedValue) return m.Matcher.Match(m.transformedValue)

View File

@ -66,6 +66,10 @@ func MatchMayChangeInTheFuture(matcher GomegaMatcher, value interface{}) bool {
type AsyncAssertion interface { type AsyncAssertion interface {
Should(matcher GomegaMatcher, optionalDescription ...interface{}) bool Should(matcher GomegaMatcher, optionalDescription ...interface{}) bool
ShouldNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool ShouldNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool
WithOffset(offset int) AsyncAssertion
WithTimeout(interval time.Duration) AsyncAssertion
WithPolling(interval time.Duration) AsyncAssertion
} }
// Assertions are returned by Ω and Expect and enable assertions against Gomega matchers // Assertions are returned by Ω and Expect and enable assertions against Gomega matchers
@ -76,4 +80,8 @@ type Assertion interface {
To(matcher GomegaMatcher, optionalDescription ...interface{}) bool To(matcher GomegaMatcher, optionalDescription ...interface{}) bool
ToNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool ToNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool
NotTo(matcher GomegaMatcher, optionalDescription ...interface{}) bool NotTo(matcher GomegaMatcher, optionalDescription ...interface{}) bool
WithOffset(offset int) Assertion
Error() Assertion
} }

2
vendor/modules.txt vendored
View File

@ -293,7 +293,7 @@ github.com/onsi/ginkgo/reporters/stenographer
github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable
github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty
github.com/onsi/ginkgo/types github.com/onsi/ginkgo/types
# github.com/onsi/gomega v1.16.0 # github.com/onsi/gomega v1.17.0
## explicit ## explicit
github.com/onsi/gomega github.com/onsi/gomega
github.com/onsi/gomega/format github.com/onsi/gomega/format