rebase: bump the github-dependencies group with 3 updates

Bumps the github-dependencies group with 3 updates: [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo), [github.com/onsi/gomega](https://github.com/onsi/gomega) and [github.com/stretchr/testify](https://github.com/stretchr/testify).


Updates `github.com/onsi/ginkgo/v2` from 2.21.0 to 2.22.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.21.0...v2.22.0)

Updates `github.com/onsi/gomega` from 1.35.1 to 1.36.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.35.1...v1.36.0)

Updates `github.com/stretchr/testify` from 1.9.0 to 1.10.0
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-dependencies
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-dependencies
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot] 2024-11-25 20:35:48 +00:00 committed by mergify[bot]
parent 84aadc9189
commit 630c97a009
33 changed files with 1202 additions and 358 deletions

6
go.mod
View File

@ -20,11 +20,11 @@ require (
github.com/kubernetes-csi/csi-lib-utils v0.19.0 github.com/kubernetes-csi/csi-lib-utils v0.19.0
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0 github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0
github.com/libopenstorage/secrets v0.0.0-20231011182615-5f4b25ceede1 github.com/libopenstorage/secrets v0.0.0-20231011182615-5f4b25ceede1
github.com/onsi/ginkgo/v2 v2.21.0 github.com/onsi/ginkgo/v2 v2.22.0
github.com/onsi/gomega v1.35.1 github.com/onsi/gomega v1.36.0
github.com/pkg/xattr v0.4.10 github.com/pkg/xattr v0.4.10
github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_golang v1.20.5
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.29.0 golang.org/x/crypto v0.29.0
golang.org/x/net v0.31.0 golang.org/x/net v0.31.0
golang.org/x/sys v0.27.0 golang.org/x/sys v0.27.0

11
go.sum
View File

@ -2083,8 +2083,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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=
@ -2106,8 +2106,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
@ -2281,8 +2281,9 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg= github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=

View File

@ -1,3 +1,13 @@
## 2.22.0
### Features
- Add label to serial nodes [0fcaa08]
This allows serial tests to be filtered using the `label-filter`
### Maintenance
Various doc fixes
## 2.21.0 ## 2.21.0

View File

@ -241,6 +241,9 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
} }
case t == reflect.TypeOf(Serial): case t == reflect.TypeOf(Serial):
node.MarkedSerial = bool(arg.(serialType)) node.MarkedSerial = bool(arg.(serialType))
if !labelsSeen["Serial"] {
node.Labels = append(node.Labels, "Serial")
}
if !nodeType.Is(types.NodeTypesForContainerAndIt) { if !nodeType.Is(types.NodeTypesForContainerAndIt) {
appendError(types.GinkgoErrors.InvalidDecoratorForNodeType(node.CodeLocation, nodeType, "Serial")) appendError(types.GinkgoErrors.InvalidDecoratorForNodeType(node.CodeLocation, nodeType, "Serial"))
} }

View File

@ -95,7 +95,7 @@ For example:
}) })
It("should return the expected message", func() { It("should return the expected message", func() {
body, err := ioutil.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(body)).To(Equal(message)) Expect(string(body)).To(Equal(message))
}) })

View File

@ -1,3 +1,3 @@
package types package types
const VERSION = "2.21.0" const VERSION = "2.22.0"

View File

@ -1,3 +1,12 @@
## 1.36.0
### Features
- new: make collection-related matchers Go 1.23 iterator aware [4c964c6]
### Maintenance
- Replace min/max helpers with built-in min/max [ece6872]
- Fix some typos in docs [8e924d7]
## 1.35.1 ## 1.35.1
### Fixes ### Fixes

View File

@ -22,7 +22,7 @@ import (
"github.com/onsi/gomega/types" "github.com/onsi/gomega/types"
) )
const GOMEGA_VERSION = "1.35.1" const GOMEGA_VERSION = "1.36.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().

View File

@ -4,17 +4,31 @@ package matchers
import ( import (
"fmt" "fmt"
"reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type BeEmptyMatcher struct { type BeEmptyMatcher struct {
} }
func (matcher *BeEmptyMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *BeEmptyMatcher) Match(actual interface{}) (success bool, err error) {
// short-circuit the iterator case, as we only need to see the first
// element, if any.
if miter.IsIter(actual) {
var length int
if miter.IsSeq2(actual) {
miter.IterateKV(actual, func(k, v reflect.Value) bool { length++; return false })
} else {
miter.IterateV(actual, func(v reflect.Value) bool { length++; return false })
}
return length == 0, nil
}
length, ok := lengthOf(actual) length, ok := lengthOf(actual)
if !ok { if !ok {
return false, fmt.Errorf("BeEmpty matcher expects a string/array/map/channel/slice. Got:\n%s", format.Object(actual, 1)) return false, fmt.Errorf("BeEmpty matcher expects a string/array/map/channel/slice/iterator. Got:\n%s", format.Object(actual, 1))
} }
return length == 0, nil return length == 0, nil

View File

@ -7,6 +7,7 @@ import (
"reflect" "reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
"github.com/onsi/gomega/matchers/support/goraph/bipartitegraph" "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph"
) )
@ -17,8 +18,8 @@ type ConsistOfMatcher struct {
} }
func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) {
if !isArrayOrSlice(actual) && !isMap(actual) { if !isArrayOrSlice(actual) && !isMap(actual) && !miter.IsIter(actual) {
return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map/iter.Seq/iter.Seq2. Got:\n%s", format.Object(actual, 1))
} }
matchers := matchers(matcher.Elements) matchers := matchers(matcher.Elements)
@ -60,10 +61,21 @@ func equalMatchersToElements(matchers []interface{}) (elements []interface{}) {
} }
func flatten(elems []interface{}) []interface{} { func flatten(elems []interface{}) []interface{} {
if len(elems) != 1 || !isArrayOrSlice(elems[0]) { if len(elems) != 1 ||
!(isArrayOrSlice(elems[0]) ||
(miter.IsIter(elems[0]) && !miter.IsSeq2(elems[0]))) {
return elems return elems
} }
if miter.IsIter(elems[0]) {
flattened := []any{}
miter.IterateV(elems[0], func(v reflect.Value) bool {
flattened = append(flattened, v.Interface())
return true
})
return flattened
}
value := reflect.ValueOf(elems[0]) value := reflect.ValueOf(elems[0])
flattened := make([]interface{}, value.Len()) flattened := make([]interface{}, value.Len())
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
@ -116,7 +128,19 @@ func presentable(elems []interface{}) interface{} {
func valuesOf(actual interface{}) []interface{} { func valuesOf(actual interface{}) []interface{} {
value := reflect.ValueOf(actual) value := reflect.ValueOf(actual)
values := []interface{}{} values := []interface{}{}
if isMap(actual) { if miter.IsIter(actual) {
if miter.IsSeq2(actual) {
miter.IterateKV(actual, func(k, v reflect.Value) bool {
values = append(values, v.Interface())
return true
})
} else {
miter.IterateV(actual, func(v reflect.Value) bool {
values = append(values, v.Interface())
return true
})
}
} else if isMap(actual) {
keys := value.MapKeys() keys := value.MapKeys()
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
values = append(values, value.MapIndex(keys[i]).Interface()) values = append(values, value.MapIndex(keys[i]).Interface())

View File

@ -8,6 +8,7 @@ import (
"reflect" "reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type ContainElementMatcher struct { type ContainElementMatcher struct {
@ -16,16 +17,18 @@ type ContainElementMatcher struct {
} }
func (matcher *ContainElementMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *ContainElementMatcher) Match(actual interface{}) (success bool, err error) {
if !isArrayOrSlice(actual) && !isMap(actual) { if !isArrayOrSlice(actual) && !isMap(actual) && !miter.IsIter(actual) {
return false, fmt.Errorf("ContainElement matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) return false, fmt.Errorf("ContainElement matcher expects an array/slice/map/iterator. Got:\n%s", format.Object(actual, 1))
} }
var actualT reflect.Type var actualT reflect.Type
var result reflect.Value var result reflect.Value
switch l := len(matcher.Result); { switch numResultArgs := len(matcher.Result); {
case l > 1: case numResultArgs > 1:
return false, errors.New("ContainElement matcher expects at most a single optional pointer to store its findings at") return false, errors.New("ContainElement matcher expects at most a single optional pointer to store its findings at")
case l == 1: case numResultArgs == 1:
// Check the optional result arg to point to a single value/array/slice/map
// of a type compatible with the actual value.
if reflect.ValueOf(matcher.Result[0]).Kind() != reflect.Ptr { if reflect.ValueOf(matcher.Result[0]).Kind() != reflect.Ptr {
return false, fmt.Errorf("ContainElement matcher expects a non-nil pointer to store its findings at. Got\n%s", return false, fmt.Errorf("ContainElement matcher expects a non-nil pointer to store its findings at. Got\n%s",
format.Object(matcher.Result[0], 1)) format.Object(matcher.Result[0], 1))
@ -34,93 +37,209 @@ func (matcher *ContainElementMatcher) Match(actual interface{}) (success bool, e
resultReference := matcher.Result[0] resultReference := matcher.Result[0]
result = reflect.ValueOf(resultReference).Elem() // what ResultReference points to, to stash away our findings result = reflect.ValueOf(resultReference).Elem() // what ResultReference points to, to stash away our findings
switch result.Kind() { switch result.Kind() {
case reflect.Array: case reflect.Array: // result arrays are not supported, as they cannot be dynamically sized.
if miter.IsIter(actual) {
_, actualvT := miter.IterKVTypes(actual)
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
reflect.SliceOf(actualvT), result.Type().String())
}
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
reflect.SliceOf(actualT.Elem()).String(), result.Type().String()) reflect.SliceOf(actualT.Elem()).String(), result.Type().String())
case reflect.Slice:
if !isArrayOrSlice(actual) { case reflect.Slice: // result slice
// can we assign elements in actual to elements in what the result
// arg points to?
// - ✔ actual is an array or slice
// - ✔ actual is an iter.Seq producing "v" elements
// - ✔ actual is an iter.Seq2 producing "v" elements, ignoring
// the "k" elements.
switch {
case isArrayOrSlice(actual):
if !actualT.Elem().AssignableTo(result.Type().Elem()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualT.String(), result.Type().String())
}
case miter.IsIter(actual):
_, actualvT := miter.IterKVTypes(actual)
if !actualvT.AssignableTo(result.Type().Elem()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualvT.String(), result.Type().String())
}
default: // incompatible result reference
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
reflect.MapOf(actualT.Key(), actualT.Elem()).String(), result.Type().String()) reflect.MapOf(actualT.Key(), actualT.Elem()).String(), result.Type().String())
} }
if !actualT.Elem().AssignableTo(result.Type().Elem()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", case reflect.Map: // result map
actualT.String(), result.Type().String()) // can we assign elements in actual to elements in what the result
} // arg points to?
case reflect.Map: // - ✔ actual is a map
if !isMap(actual) { // - ✔ actual is an iter.Seq2 (iter.Seq doesn't fit though)
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", switch {
actualT.String(), result.Type().String()) case isMap(actual):
} if !actualT.AssignableTo(result.Type()) {
if !actualT.AssignableTo(result.Type()) { return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualT.String(), result.Type().String())
}
case miter.IsIter(actual):
actualkT, actualvT := miter.IterKVTypes(actual)
if actualkT == nil {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
reflect.SliceOf(actualvT).String(), result.Type().String())
}
if !reflect.MapOf(actualkT, actualvT).AssignableTo(result.Type()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
reflect.MapOf(actualkT, actualvT), result.Type().String())
}
default: // incompatible result reference
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualT.String(), result.Type().String()) actualT.String(), result.Type().String())
} }
default: default:
if !actualT.Elem().AssignableTo(result.Type()) { // can we assign a (single) element in actual to what the result arg
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s", // points to?
actualT.Elem().String(), result.Type().String()) switch {
case miter.IsIter(actual):
_, actualvT := miter.IterKVTypes(actual)
if !actualvT.AssignableTo(result.Type()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualvT.String(), result.Type().String())
}
default:
if !actualT.Elem().AssignableTo(result.Type()) {
return false, fmt.Errorf("ContainElement cannot return findings. Need *%s, got *%s",
actualT.Elem().String(), result.Type().String())
}
} }
} }
} }
// If the supplied matcher isn't an Omega matcher, default to the Equal
// matcher.
elemMatcher, elementIsMatcher := matcher.Element.(omegaMatcher) elemMatcher, elementIsMatcher := matcher.Element.(omegaMatcher)
if !elementIsMatcher { if !elementIsMatcher {
elemMatcher = &EqualMatcher{Expected: matcher.Element} elemMatcher = &EqualMatcher{Expected: matcher.Element}
} }
value := reflect.ValueOf(actual) value := reflect.ValueOf(actual)
var valueAt func(int) interface{}
var getFindings func() reflect.Value var getFindings func() reflect.Value // abstracts how the findings are collected and stored
var foundAt func(int) var lastError error
if isMap(actual) { if !miter.IsIter(actual) {
keys := value.MapKeys() var valueAt func(int) interface{}
valueAt = func(i int) interface{} { var foundAt func(int)
return value.MapIndex(keys[i]).Interface() // We're dealing with an array/slice/map, so in all cases we can iterate
} // over the elements in actual using indices (that can be considered
if result.Kind() != reflect.Invalid { // keys in case of maps).
fm := reflect.MakeMap(actualT) if isMap(actual) {
getFindings = func() reflect.Value { keys := value.MapKeys()
return fm valueAt = func(i int) interface{} {
return value.MapIndex(keys[i]).Interface()
} }
foundAt = func(i int) { if result.Kind() != reflect.Invalid {
fm.SetMapIndex(keys[i], value.MapIndex(keys[i])) fm := reflect.MakeMap(actualT)
getFindings = func() reflect.Value { return fm }
foundAt = func(i int) {
fm.SetMapIndex(keys[i], value.MapIndex(keys[i]))
}
}
} else {
valueAt = func(i int) interface{} {
return value.Index(i).Interface()
}
if result.Kind() != reflect.Invalid {
var fsl reflect.Value
if result.Kind() == reflect.Slice {
fsl = reflect.MakeSlice(result.Type(), 0, 0)
} else {
fsl = reflect.MakeSlice(reflect.SliceOf(result.Type()), 0, 0)
}
getFindings = func() reflect.Value { return fsl }
foundAt = func(i int) {
fsl = reflect.Append(fsl, value.Index(i))
}
}
}
for i := 0; i < value.Len(); i++ {
elem := valueAt(i)
success, err := elemMatcher.Match(elem)
if err != nil {
lastError = err
continue
}
if success {
if result.Kind() == reflect.Invalid {
return true, nil
}
foundAt(i)
} }
} }
} else { } else {
valueAt = func(i int) interface{} { // We're dealing with an iterator as a first-class construct, so things
return value.Index(i).Interface() // are slightly different: there is no index defined as in case of
} // arrays/slices/maps, just "ooooorder"
var found func(k, v reflect.Value)
if result.Kind() != reflect.Invalid { if result.Kind() != reflect.Invalid {
var f reflect.Value if result.Kind() == reflect.Map {
if result.Kind() == reflect.Slice { fm := reflect.MakeMap(result.Type())
f = reflect.MakeSlice(result.Type(), 0, 0) getFindings = func() reflect.Value { return fm }
found = func(k, v reflect.Value) { fm.SetMapIndex(k, v) }
} else { } else {
f = reflect.MakeSlice(reflect.SliceOf(result.Type()), 0, 0) var fsl reflect.Value
} if result.Kind() == reflect.Slice {
getFindings = func() reflect.Value { fsl = reflect.MakeSlice(result.Type(), 0, 0)
return f } else {
} fsl = reflect.MakeSlice(reflect.SliceOf(result.Type()), 0, 0)
foundAt = func(i int) { }
f = reflect.Append(f, value.Index(i)) getFindings = func() reflect.Value { return fsl }
found = func(_, v reflect.Value) { fsl = reflect.Append(fsl, v) }
} }
} }
}
var lastError error success := false
for i := 0; i < value.Len(); i++ { actualkT, _ := miter.IterKVTypes(actual)
elem := valueAt(i) if actualkT == nil {
success, err := elemMatcher.Match(elem) miter.IterateV(actual, func(v reflect.Value) bool {
if err != nil { var err error
lastError = err success, err = elemMatcher.Match(v.Interface())
continue if err != nil {
lastError = err
return true // iterate on...
}
if success {
if result.Kind() == reflect.Invalid {
return false // a match and no result needed, so we're done
}
found(reflect.Value{}, v)
}
return true // iterate on...
})
} else {
miter.IterateKV(actual, func(k, v reflect.Value) bool {
var err error
success, err = elemMatcher.Match(v.Interface())
if err != nil {
lastError = err
return true // iterate on...
}
if success {
if result.Kind() == reflect.Invalid {
return false // a match and no result needed, so we're done
}
found(k, v)
}
return true // iterate on...
})
} }
if success { if success && result.Kind() == reflect.Invalid {
if result.Kind() == reflect.Invalid { return true, nil
return true, nil
}
foundAt(i)
} }
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
"github.com/onsi/gomega/matchers/support/goraph/bipartitegraph" "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph"
) )
@ -13,8 +14,8 @@ type ContainElementsMatcher struct {
} }
func (matcher *ContainElementsMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *ContainElementsMatcher) Match(actual interface{}) (success bool, err error) {
if !isArrayOrSlice(actual) && !isMap(actual) { if !isArrayOrSlice(actual) && !isMap(actual) && !miter.IsIter(actual) {
return false, fmt.Errorf("ContainElements matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) return false, fmt.Errorf("ContainElements matcher expects an array/slice/map/iter.Seq/iter.Seq2. Got:\n%s", format.Object(actual, 1))
} }
matchers := matchers(matcher.Elements) matchers := matchers(matcher.Elements)

View File

@ -5,6 +5,7 @@ import (
"reflect" "reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type HaveEachMatcher struct { type HaveEachMatcher struct {
@ -12,8 +13,8 @@ type HaveEachMatcher struct {
} }
func (matcher *HaveEachMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *HaveEachMatcher) Match(actual interface{}) (success bool, err error) {
if !isArrayOrSlice(actual) && !isMap(actual) { if !isArrayOrSlice(actual) && !isMap(actual) && !miter.IsIter(actual) {
return false, fmt.Errorf("HaveEach matcher expects an array/slice/map. Got:\n%s", return false, fmt.Errorf("HaveEach matcher expects an array/slice/map/iter.Seq/iter.Seq2. Got:\n%s",
format.Object(actual, 1)) format.Object(actual, 1))
} }
@ -22,6 +23,38 @@ func (matcher *HaveEachMatcher) Match(actual interface{}) (success bool, err err
elemMatcher = &EqualMatcher{Expected: matcher.Element} elemMatcher = &EqualMatcher{Expected: matcher.Element}
} }
if miter.IsIter(actual) {
// rejecting the non-elements case works different for iterators as we
// don't want to fetch all elements into a slice first.
count := 0
var success bool
var err error
if miter.IsSeq2(actual) {
miter.IterateKV(actual, func(k, v reflect.Value) bool {
count++
success, err = elemMatcher.Match(v.Interface())
if err != nil {
return false
}
return success
})
} else {
miter.IterateV(actual, func(v reflect.Value) bool {
count++
success, err = elemMatcher.Match(v.Interface())
if err != nil {
return false
}
return success
})
}
if count == 0 {
return false, fmt.Errorf("HaveEach matcher expects a non-empty iter.Seq/iter.Seq2. Got:\n%s",
format.Object(actual, 1))
}
return success, err
}
value := reflect.ValueOf(actual) value := reflect.ValueOf(actual)
if value.Len() == 0 { if value.Len() == 0 {
return false, fmt.Errorf("HaveEach matcher expects a non-empty array/slice/map. Got:\n%s", return false, fmt.Errorf("HaveEach matcher expects a non-empty array/slice/map. Got:\n%s",
@ -40,7 +73,8 @@ func (matcher *HaveEachMatcher) Match(actual interface{}) (success bool, err err
} }
} }
// if there are no elements, then HaveEach will match. // if we never failed then we succeed; the empty/nil cases have already been
// rejected above.
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
success, err := elemMatcher.Match(valueAt(i)) success, err := elemMatcher.Match(valueAt(i))
if err != nil { if err != nil {

View File

@ -2,8 +2,10 @@ package matchers
import ( import (
"fmt" "fmt"
"reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type mismatchFailure struct { type mismatchFailure struct {
@ -21,17 +23,58 @@ type HaveExactElementsMatcher struct {
func (matcher *HaveExactElementsMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *HaveExactElementsMatcher) Match(actual interface{}) (success bool, err error) {
matcher.resetState() matcher.resetState()
if isMap(actual) { if isMap(actual) || miter.IsSeq2(actual) {
return false, fmt.Errorf("error") return false, fmt.Errorf("HaveExactElements matcher doesn't work on map or iter.Seq2. Got:\n%s", format.Object(actual, 1))
} }
matchers := matchers(matcher.Elements) matchers := matchers(matcher.Elements)
values := valuesOf(actual)
lenMatchers := len(matchers) lenMatchers := len(matchers)
lenValues := len(values)
success = true success = true
if miter.IsIter(actual) {
// In the worst case, we need to see everything before we can give our
// verdict. The only exception is fast fail.
i := 0
miter.IterateV(actual, func(v reflect.Value) bool {
if i >= lenMatchers {
// the iterator produces more values than we got matchers: this
// is not good.
matcher.extraIndex = i
success = false
return false
}
elemMatcher := matchers[i].(omegaMatcher)
match, err := elemMatcher.Match(v.Interface())
if err != nil {
matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{
index: i,
failure: err.Error(),
})
success = false
} else if !match {
matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{
index: i,
failure: elemMatcher.FailureMessage(v.Interface()),
})
success = false
}
i++
return true
})
if i < len(matchers) {
// the iterator produced less values than we got matchers: this is
// no good, no no no.
matcher.missingIndex = i
success = false
}
return success, nil
}
values := valuesOf(actual)
lenValues := len(values)
for i := 0; i < lenMatchers || i < lenValues; i++ { for i := 0; i < lenMatchers || i < lenValues; i++ {
if i >= lenMatchers { if i >= lenMatchers {
matcher.extraIndex = i matcher.extraIndex = i

View File

@ -7,6 +7,7 @@ import (
"reflect" "reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type HaveKeyMatcher struct { type HaveKeyMatcher struct {
@ -14,8 +15,8 @@ type HaveKeyMatcher struct {
} }
func (matcher *HaveKeyMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *HaveKeyMatcher) Match(actual interface{}) (success bool, err error) {
if !isMap(actual) { if !isMap(actual) && !miter.IsSeq2(actual) {
return false, fmt.Errorf("HaveKey matcher expects a map. Got:%s", format.Object(actual, 1)) return false, fmt.Errorf("HaveKey matcher expects a map/iter.Seq2. Got:%s", format.Object(actual, 1))
} }
keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher) keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher)
@ -23,6 +24,20 @@ func (matcher *HaveKeyMatcher) Match(actual interface{}) (success bool, err erro
keyMatcher = &EqualMatcher{Expected: matcher.Key} keyMatcher = &EqualMatcher{Expected: matcher.Key}
} }
if miter.IsSeq2(actual) {
var success bool
var err error
miter.IterateKV(actual, func(k, v reflect.Value) bool {
success, err = keyMatcher.Match(k.Interface())
if err != nil {
err = fmt.Errorf("HaveKey's key matcher failed with:\n%s%s", format.Indent, err.Error())
return false
}
return !success
})
return success, err
}
keys := reflect.ValueOf(actual).MapKeys() keys := reflect.ValueOf(actual).MapKeys()
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
success, err := keyMatcher.Match(keys[i].Interface()) success, err := keyMatcher.Match(keys[i].Interface())

View File

@ -7,6 +7,7 @@ import (
"reflect" "reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type HaveKeyWithValueMatcher struct { type HaveKeyWithValueMatcher struct {
@ -15,8 +16,8 @@ type HaveKeyWithValueMatcher struct {
} }
func (matcher *HaveKeyWithValueMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *HaveKeyWithValueMatcher) Match(actual interface{}) (success bool, err error) {
if !isMap(actual) { if !isMap(actual) && !miter.IsSeq2(actual) {
return false, fmt.Errorf("HaveKeyWithValue matcher expects a map. Got:%s", format.Object(actual, 1)) return false, fmt.Errorf("HaveKeyWithValue matcher expects a map/iter.Seq2. Got:%s", format.Object(actual, 1))
} }
keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher) keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher)
@ -29,6 +30,27 @@ func (matcher *HaveKeyWithValueMatcher) Match(actual interface{}) (success bool,
valueMatcher = &EqualMatcher{Expected: matcher.Value} valueMatcher = &EqualMatcher{Expected: matcher.Value}
} }
if miter.IsSeq2(actual) {
var success bool
var err error
miter.IterateKV(actual, func(k, v reflect.Value) bool {
success, err = keyMatcher.Match(k.Interface())
if err != nil {
err = fmt.Errorf("HaveKey's key matcher failed with:\n%s%s", format.Indent, err.Error())
return false
}
if success {
success, err = valueMatcher.Match(v.Interface())
if err != nil {
err = fmt.Errorf("HaveKeyWithValue's value matcher failed with:\n%s%s", format.Indent, err.Error())
return false
}
}
return !success
})
return success, err
}
keys := reflect.ValueOf(actual).MapKeys() keys := reflect.ValueOf(actual).MapKeys()
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
success, err := keyMatcher.Match(keys[i].Interface()) success, err := keyMatcher.Match(keys[i].Interface())

View File

@ -13,7 +13,7 @@ type HaveLenMatcher struct {
func (matcher *HaveLenMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *HaveLenMatcher) Match(actual interface{}) (success bool, err error) {
length, ok := lengthOf(actual) length, ok := lengthOf(actual)
if !ok { if !ok {
return false, fmt.Errorf("HaveLen matcher expects a string/array/map/channel/slice. Got:\n%s", format.Object(actual, 1)) return false, fmt.Errorf("HaveLen matcher expects a string/array/map/channel/slice/iterator. Got:\n%s", format.Object(actual, 1))
} }
return length == matcher.Count, nil return length == matcher.Count, nil

View File

@ -0,0 +1,128 @@
//go:build go1.23
package miter
import (
"reflect"
)
// HasIterators always returns false for Go versions before 1.23.
func HasIterators() bool { return true }
// IsIter returns true if the specified value is a function type that can be
// range-d over, otherwise false.
//
// We don't use reflect's CanSeq and CanSeq2 directly, as these would return
// true also for other value types that are range-able, such as integers,
// slices, et cetera. Here, we aim only at range-able (iterator) functions.
func IsIter(it any) bool {
if it == nil { // on purpose we only test for untyped nil.
return false
}
// reject all non-iterator-func values, even if they're range-able.
t := reflect.TypeOf(it)
if t.Kind() != reflect.Func {
return false
}
return t.CanSeq() || t.CanSeq2()
}
// IterKVTypes returns the reflection types of an iterator's yield function's K
// and optional V arguments, otherwise nil K and V reflection types.
func IterKVTypes(it any) (k, v reflect.Type) {
if it == nil {
return
}
// reject all non-iterator-func values, even if they're range-able.
t := reflect.TypeOf(it)
if t.Kind() != reflect.Func {
return
}
// get the reflection types for V, and where applicable, K.
switch {
case t.CanSeq():
v = t. /*iterator fn*/ In(0). /*yield fn*/ In(0)
case t.CanSeq2():
yieldfn := t. /*iterator fn*/ In(0)
k = yieldfn.In(0)
v = yieldfn.In(1)
}
return
}
// IsSeq2 returns true if the passed iterator function is compatible with
// iter.Seq2, otherwise false.
//
// IsSeq2 hides the Go 1.23+ specific reflect.Type.CanSeq2 behind a facade which
// is empty for Go versions before 1.23.
func IsSeq2(it any) bool {
if it == nil {
return false
}
t := reflect.TypeOf(it)
return t.Kind() == reflect.Func && t.CanSeq2()
}
// isNilly returns true if v is either an untyped nil, or is a nil function (not
// necessarily an iterator function).
func isNilly(v any) bool {
if v == nil {
return true
}
rv := reflect.ValueOf(v)
return rv.Kind() == reflect.Func && rv.IsNil()
}
// IterateV loops over the elements produced by an iterator function, passing
// the elements to the specified yield function individually and stopping only
// when either the iterator function runs out of elements or the yield function
// tell us to stop it.
//
// IterateV works very much like reflect.Value.Seq but hides the Go 1.23+
// specific parts behind a facade which is empty for Go versions before 1.23, in
// order to simplify code maintenance for matchers when using older Go versions.
func IterateV(it any, yield func(v reflect.Value) bool) {
if isNilly(it) {
return
}
// reject all non-iterator-func values, even if they're range-able.
t := reflect.TypeOf(it)
if t.Kind() != reflect.Func || !t.CanSeq() {
return
}
// Call the specified iterator function, handing it our adaptor to call the
// specified generic reflection yield function.
reflectedYield := reflect.MakeFunc(
t. /*iterator fn*/ In(0),
func(args []reflect.Value) []reflect.Value {
return []reflect.Value{reflect.ValueOf(yield(args[0]))}
})
reflect.ValueOf(it).Call([]reflect.Value{reflectedYield})
}
// IterateKV loops over the key-value elements produced by an iterator function,
// passing the elements to the specified yield function individually and
// stopping only when either the iterator function runs out of elements or the
// yield function tell us to stop it.
//
// IterateKV works very much like reflect.Value.Seq2 but hides the Go 1.23+
// specific parts behind a facade which is empty for Go versions before 1.23, in
// order to simplify code maintenance for matchers when using older Go versions.
func IterateKV(it any, yield func(k, v reflect.Value) bool) {
if isNilly(it) {
return
}
// reject all non-iterator-func values, even if they're range-able.
t := reflect.TypeOf(it)
if t.Kind() != reflect.Func || !t.CanSeq2() {
return
}
// Call the specified iterator function, handing it our adaptor to call the
// specified generic reflection yield function.
reflectedYield := reflect.MakeFunc(
t. /*iterator fn*/ In(0),
func(args []reflect.Value) []reflect.Value {
return []reflect.Value{reflect.ValueOf(yield(args[0], args[1]))}
})
reflect.ValueOf(it).Call([]reflect.Value{reflectedYield})
}

View File

@ -0,0 +1,44 @@
//go:build !go1.23
/*
Gomega matchers
This package implements the Gomega matchers and does not typically need to be imported.
See the docs for Gomega for documentation on the matchers
http://onsi.github.io/gomega/
*/
package miter
import "reflect"
// HasIterators always returns false for Go versions before 1.23.
func HasIterators() bool { return false }
// IsIter always returns false for Go versions before 1.23 as there is no
// iterator (function) pattern defined yet; see also:
// https://tip.golang.org/blog/range-functions.
func IsIter(i any) bool { return false }
// IsSeq2 always returns false for Go versions before 1.23 as there is no
// iterator (function) pattern defined yet; see also:
// https://tip.golang.org/blog/range-functions.
func IsSeq2(it any) bool { return false }
// IterKVTypes always returns nil reflection types for Go versions before 1.23
// as there is no iterator (function) pattern defined yet; see also:
// https://tip.golang.org/blog/range-functions.
func IterKVTypes(i any) (k, v reflect.Type) {
return
}
// IterateV never loops over what has been passed to it as an iterator for Go
// versions before 1.23 as there is no iterator (function) pattern defined yet;
// see also: https://tip.golang.org/blog/range-functions.
func IterateV(it any, yield func(v reflect.Value) bool) {}
// IterateKV never loops over what has been passed to it as an iterator for Go
// versions before 1.23 as there is no iterator (function) pattern defined yet;
// see also: https://tip.golang.org/blog/range-functions.
func IterateKV(it any, yield func(k, v reflect.Value) bool) {}

View File

@ -15,6 +15,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"github.com/onsi/gomega/matchers/internal/miter"
) )
type omegaMatcher interface { type omegaMatcher interface {
@ -152,6 +154,17 @@ func lengthOf(a interface{}) (int, bool) {
switch reflect.TypeOf(a).Kind() { switch reflect.TypeOf(a).Kind() {
case reflect.Map, reflect.Array, reflect.String, reflect.Chan, reflect.Slice: case reflect.Map, reflect.Array, reflect.String, reflect.Chan, reflect.Slice:
return reflect.ValueOf(a).Len(), true return reflect.ValueOf(a).Len(), true
case reflect.Func:
if !miter.IsIter(a) {
return 0, false
}
var l int
if miter.IsSeq2(a) {
miter.IterateKV(a, func(k, v reflect.Value) bool { l++; return true })
} else {
miter.IterateV(a, func(v reflect.Value) bool { l++; return true })
}
return l, true
default: default:
return 0, false return 0, false
} }

View File

@ -7,10 +7,13 @@ import (
"time" "time"
) )
type CompareType int // Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it.
type CompareType = compareResult
type compareResult int
const ( const (
compareLess CompareType = iota - 1 compareLess compareResult = iota - 1
compareEqual compareEqual
compareGreater compareGreater
) )
@ -39,7 +42,7 @@ var (
bytesType = reflect.TypeOf([]byte{}) bytesType = reflect.TypeOf([]byte{})
) )
func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) {
obj1Value := reflect.ValueOf(obj1) obj1Value := reflect.ValueOf(obj1)
obj2Value := reflect.ValueOf(obj2) obj2Value := reflect.ValueOf(obj2)
@ -325,7 +328,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
} }
return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64) if timeObj1.Before(timeObj2) {
return compareLess, true
}
if timeObj1.Equal(timeObj2) {
return compareEqual, true
}
return compareGreater, true
} }
case reflect.Slice: case reflect.Slice:
{ {
@ -345,7 +354,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
} }
return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true
} }
case reflect.Uintptr: case reflect.Uintptr:
{ {
@ -381,7 +390,7 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) return compareTwoValues(t, e1, e2, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
} }
// GreaterOrEqual asserts that the first element is greater than or equal to the second // GreaterOrEqual asserts that the first element is greater than or equal to the second
@ -394,7 +403,7 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) return compareTwoValues(t, e1, e2, []compareResult{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
} }
// Less asserts that the first element is less than the second // Less asserts that the first element is less than the second
@ -406,7 +415,7 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{})
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) return compareTwoValues(t, e1, e2, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
} }
// LessOrEqual asserts that the first element is less than or equal to the second // LessOrEqual asserts that the first element is less than or equal to the second
@ -419,7 +428,7 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) return compareTwoValues(t, e1, e2, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
} }
// Positive asserts that the specified element is positive // Positive asserts that the specified element is positive
@ -431,7 +440,7 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
h.Helper() h.Helper()
} }
zero := reflect.Zero(reflect.TypeOf(e)) zero := reflect.Zero(reflect.TypeOf(e))
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...) return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, "\"%v\" is not positive", msgAndArgs...)
} }
// Negative asserts that the specified element is negative // Negative asserts that the specified element is negative
@ -443,10 +452,10 @@ func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
h.Helper() h.Helper()
} }
zero := reflect.Zero(reflect.TypeOf(e)) zero := reflect.Zero(reflect.TypeOf(e))
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...) return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, "\"%v\" is not negative", msgAndArgs...)
} }
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
@ -469,7 +478,7 @@ func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedCompare
return true return true
} }
func containsValue(values []CompareType, value CompareType) bool { func containsValue(values []compareResult, value compareResult) bool {
for _, v := range values { for _, v := range values {
if v == value { if v == value {
return true return true

View File

@ -104,8 +104,8 @@ func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{},
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...) return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
// EqualValuesf asserts that two objects are equal or convertible to the same types // EqualValuesf asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") // assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
@ -186,7 +186,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { // assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -568,6 +568,23 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...) return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
} }
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// assert.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
}
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
@ -604,7 +621,16 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
// NotErrorIsf asserts that at none of the errors in err's chain matches target. // NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
}
// NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {

View File

@ -186,8 +186,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
return EqualExportedValuesf(a.t, expected, actual, msg, args...) return EqualExportedValuesf(a.t, expected, actual, msg, args...)
} }
// EqualValues asserts that two objects are equal or convertible to the same types // EqualValues asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// a.EqualValues(uint32(123), int32(123)) // a.EqualValues(uint32(123), int32(123))
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
@ -197,8 +197,8 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
return EqualValues(a.t, expected, actual, msgAndArgs...) return EqualValues(a.t, expected, actual, msgAndArgs...)
} }
// EqualValuesf asserts that two objects are equal or convertible to the same types // EqualValuesf asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") // a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
@ -336,7 +336,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
// a.EventuallyWithT(func(c *assert.CollectT) { // a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
h.Helper() h.Helper()
@ -361,7 +361,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { // a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
h.Helper() h.Helper()
@ -1128,6 +1128,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
return NotContainsf(a.t, s, contains, msg, args...) return NotContainsf(a.t, s, contains, msg, args...)
} }
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
//
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotElementsMatchf(a.t, listA, listB, msg, args...)
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
@ -1200,7 +1234,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
return NotEqualf(a.t, expected, actual, msg, args...) return NotEqualf(a.t, expected, actual, msg, args...)
} }
// NotErrorIs asserts that at none of the errors in err's chain matches target. // NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorAs(a.t, err, target, msgAndArgs...)
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorAsf(a.t, err, target, msg, args...)
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
@ -1209,7 +1261,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
return NotErrorIs(a.t, err, target, msgAndArgs...) return NotErrorIs(a.t, err, target, msgAndArgs...)
} }
// NotErrorIsf asserts that at none of the errors in err's chain matches target. // NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {

View File

@ -6,7 +6,7 @@ import (
) )
// isOrdered checks that collection contains orderable elements. // isOrdered checks that collection contains orderable elements.
func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
objKind := reflect.TypeOf(object).Kind() objKind := reflect.TypeOf(object).Kind()
if objKind != reflect.Slice && objKind != reflect.Array { if objKind != reflect.Slice && objKind != reflect.Array {
return false return false
@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
// assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []float{1, 2})
// assert.IsIncreasing(t, []string{"a", "b"}) // assert.IsIncreasing(t, []string{"a", "b"})
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
} }
// IsNonIncreasing asserts that the collection is not increasing // IsNonIncreasing asserts that the collection is not increasing
@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
// assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []float{2, 1})
// assert.IsNonIncreasing(t, []string{"b", "a"}) // assert.IsNonIncreasing(t, []string{"b", "a"})
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
} }
// IsDecreasing asserts that the collection is decreasing // IsDecreasing asserts that the collection is decreasing
@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{})
// assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []float{2, 1})
// assert.IsDecreasing(t, []string{"b", "a"}) // assert.IsDecreasing(t, []string{"b", "a"})
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
} }
// IsNonDecreasing asserts that the collection is not decreasing // IsNonDecreasing asserts that the collection is not decreasing
@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
// assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []float{1, 2})
// assert.IsNonDecreasing(t, []string{"a", "b"}) // assert.IsNonDecreasing(t, []string{"a", "b"})
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
} }

View File

@ -19,7 +19,9 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib" "github.com/pmezard/go-difflib/difflib"
"gopkg.in/yaml.v3"
// Wrapper around gopkg.in/yaml.v3
"github.com/stretchr/testify/assert/yaml"
) )
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
@ -45,6 +47,10 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
// for table driven tests. // for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful
// for table driven tests.
type PanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool
// Comparison is a custom function that returns true on success and false on failure // Comparison is a custom function that returns true on success and false on failure
type Comparison func() (success bool) type Comparison func() (success bool)
@ -496,7 +502,13 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
h.Helper() h.Helper()
} }
if !samePointers(expected, actual) { same, ok := samePointers(expected, actual)
if !ok {
return Fail(t, "Both arguments must be pointers", msgAndArgs...)
}
if !same {
// both are pointers but not the same type & pointing to the same address
return Fail(t, fmt.Sprintf("Not same: \n"+ return Fail(t, fmt.Sprintf("Not same: \n"+
"expected: %p %#v\n"+ "expected: %p %#v\n"+
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
@ -516,7 +528,13 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
h.Helper() h.Helper()
} }
if samePointers(expected, actual) { same, ok := samePointers(expected, actual)
if !ok {
//fails when the arguments are not pointers
return !(Fail(t, "Both arguments must be pointers", msgAndArgs...))
}
if same {
return Fail(t, fmt.Sprintf( return Fail(t, fmt.Sprintf(
"Expected and actual point to the same object: %p %#v", "Expected and actual point to the same object: %p %#v",
expected, expected), msgAndArgs...) expected, expected), msgAndArgs...)
@ -524,21 +542,23 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
return true return true
} }
// samePointers compares two generic interface objects and returns whether // samePointers checks if two generic interface objects are pointers of the same
// they point to the same object // type pointing to the same object. It returns two values: same indicating if
func samePointers(first, second interface{}) bool { // they are the same type and point to the same object, and ok indicating that
// both inputs are pointers.
func samePointers(first, second interface{}) (same bool, ok bool) {
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
return false return false, false //not both are pointers
} }
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
if firstType != secondType { if firstType != secondType {
return false return false, true // both are pointers, but of different types
} }
// compare pointer addresses // compare pointer addresses
return first == second return first == second, true
} }
// formatUnequalValues takes two values of arbitrary types and returns string // formatUnequalValues takes two values of arbitrary types and returns string
@ -572,8 +592,8 @@ func truncatingFormat(data interface{}) string {
return value return value
} }
// EqualValues asserts that two objects are equal or convertible to the same types // EqualValues asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// assert.EqualValues(t, uint32(123), int32(123)) // assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
@ -615,21 +635,6 @@ func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ..
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
} }
if aType.Kind() == reflect.Ptr {
aType = aType.Elem()
}
if bType.Kind() == reflect.Ptr {
bType = bType.Elem()
}
if aType.Kind() != reflect.Struct {
return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", aType.Kind(), reflect.Struct), msgAndArgs...)
}
if bType.Kind() != reflect.Struct {
return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...)
}
expected = copyExportedFields(expected) expected = copyExportedFields(expected)
actual = copyExportedFields(actual) actual = copyExportedFields(actual)
@ -1170,6 +1175,39 @@ func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) stri
return msg.String() return msg.String()
} }
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
//
// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isEmpty(listA) && isEmpty(listB) {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}
if !isList(t, listA, msgAndArgs...) {
return Fail(t, "listA is not a list type", msgAndArgs...)
}
if !isList(t, listB, msgAndArgs...) {
return Fail(t, "listB is not a list type", msgAndArgs...)
}
extraA, extraB := diffLists(listA, listB)
if len(extraA) == 0 && len(extraB) == 0 {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}
return true
}
// Condition uses a Comparison to assert a complex condition. // Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -1488,6 +1526,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
if err != nil { if err != nil {
return Fail(t, err.Error(), msgAndArgs...) return Fail(t, err.Error(), msgAndArgs...)
} }
if math.IsNaN(actualEpsilon) {
return Fail(t, "relative error is NaN", msgAndArgs...)
}
if actualEpsilon > epsilon { if actualEpsilon > epsilon {
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...) " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
@ -1611,7 +1652,6 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in
// matchRegexp return true if a specified regexp matches a string. // matchRegexp return true if a specified regexp matches a string.
func matchRegexp(rx interface{}, str interface{}) bool { func matchRegexp(rx interface{}, str interface{}) bool {
var r *regexp.Regexp var r *regexp.Regexp
if rr, ok := rx.(*regexp.Regexp); ok { if rr, ok := rx.(*regexp.Regexp); ok {
r = rr r = rr
@ -1619,7 +1659,14 @@ func matchRegexp(rx interface{}, str interface{}) bool {
r = regexp.MustCompile(fmt.Sprint(rx)) r = regexp.MustCompile(fmt.Sprint(rx))
} }
return (r.FindStringIndex(fmt.Sprint(str)) != nil) switch v := str.(type) {
case []byte:
return r.Match(v)
case string:
return r.MatchString(v)
default:
return r.MatchString(fmt.Sprint(v))
}
} }
@ -1872,7 +1919,7 @@ var spewConfigStringerEnabled = spew.ConfigState{
MaxDepth: 10, MaxDepth: 10,
} }
type tHelper interface { type tHelper = interface {
Helper() Helper()
} }
@ -1911,6 +1958,9 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
// CollectT implements the TestingT interface and collects all errors. // CollectT implements the TestingT interface and collects all errors.
type CollectT struct { type CollectT struct {
// A slice of errors. Non-nil slice denotes a failure.
// If it's non-nil but len(c.errors) == 0, this is also a failure
// obtained by direct c.FailNow() call.
errors []error errors []error
} }
@ -1919,9 +1969,10 @@ func (c *CollectT) Errorf(format string, args ...interface{}) {
c.errors = append(c.errors, fmt.Errorf(format, args...)) c.errors = append(c.errors, fmt.Errorf(format, args...))
} }
// FailNow panics. // FailNow stops execution by calling runtime.Goexit.
func (*CollectT) FailNow() { func (c *CollectT) FailNow() {
panic("Assertion failed") c.fail()
runtime.Goexit()
} }
// Deprecated: That was a method for internal usage that should not have been published. Now just panics. // Deprecated: That was a method for internal usage that should not have been published. Now just panics.
@ -1934,6 +1985,16 @@ func (*CollectT) Copy(TestingT) {
panic("Copy() is deprecated") panic("Copy() is deprecated")
} }
func (c *CollectT) fail() {
if !c.failed() {
c.errors = []error{} // Make it non-nil to mark a failure.
}
}
func (c *CollectT) failed() bool {
return c.errors != nil
}
// EventuallyWithT asserts that given condition will be met in waitFor time, // EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually, // periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition // it supplies a CollectT to the condition function, so that the condition
@ -1951,14 +2012,14 @@ func (*CollectT) Copy(TestingT) {
// assert.EventuallyWithT(t, func(c *assert.CollectT) { // assert.EventuallyWithT(t, func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
var lastFinishedTickErrs []error var lastFinishedTickErrs []error
ch := make(chan []error, 1) ch := make(chan *CollectT, 1)
timer := time.NewTimer(waitFor) timer := time.NewTimer(waitFor)
defer timer.Stop() defer timer.Stop()
@ -1978,16 +2039,16 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
go func() { go func() {
collect := new(CollectT) collect := new(CollectT)
defer func() { defer func() {
ch <- collect.errors ch <- collect
}() }()
condition(collect) condition(collect)
}() }()
case errs := <-ch: case collect := <-ch:
if len(errs) == 0 { if !collect.failed() {
return true return true
} }
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
lastFinishedTickErrs = errs lastFinishedTickErrs = collect.errors
tick = ticker.C tick = ticker.C
} }
} }
@ -2049,7 +2110,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
), msgAndArgs...) ), msgAndArgs...)
} }
// NotErrorIs asserts that at none of the errors in err's chain matches target. // NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -2090,6 +2151,24 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
), msgAndArgs...) ), msgAndArgs...)
} }
// NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !errors.As(err, target) {
return true
}
chain := buildErrorChainString(err)
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
"found: %q\n"+
"in chain: %s", target, chain,
), msgAndArgs...)
}
func buildErrorChainString(err error) string { func buildErrorChainString(err error) string {
if err == nil { if err == nil {
return "" return ""

View File

@ -0,0 +1,25 @@
//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
// +build testify_yaml_custom,!testify_yaml_fail,!testify_yaml_default
// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
//
// This implementation is selected with the testify_yaml_custom build tag.
//
// go test -tags testify_yaml_custom
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3].
//
// In your test package:
//
// import assertYaml "github.com/stretchr/testify/assert/yaml"
//
// func init() {
// assertYaml.Unmarshal = func (in []byte, out interface{}) error {
// // ...
// return nil
// }
// }
package yaml
var Unmarshal func(in []byte, out interface{}) error

View File

@ -0,0 +1,37 @@
//go:build !testify_yaml_fail && !testify_yaml_custom
// +build !testify_yaml_fail,!testify_yaml_custom
// Package yaml is just an indirection to handle YAML deserialization.
//
// This package is just an indirection that allows the builder to override the
// indirection with an alternative implementation of this package that uses
// another implementation of YAML deserialization. This allows to not either not
// use YAML deserialization at all, or to use another implementation than
// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
//
// Alternative implementations are selected using build tags:
//
// - testify_yaml_fail: [Unmarshal] always fails with an error
// - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
// before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
// [github.com/stretchr/testify/assert.YAMLEqf].
//
// Usage:
//
// go test -tags testify_yaml_fail
//
// You can check with "go list" which implementation is linked:
//
// go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
//
// [PR #1120]: https://github.com/stretchr/testify/pull/1120
package yaml
import goyaml "gopkg.in/yaml.v3"
// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
func Unmarshal(in []byte, out interface{}) error {
return goyaml.Unmarshal(in, out)
}

View File

@ -0,0 +1,18 @@
//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
// +build testify_yaml_fail,!testify_yaml_custom,!testify_yaml_default
// Package yaml is an implementation of YAML functions that always fail.
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3]:
//
// go test -tags testify_yaml_fail
package yaml
import "errors"
var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")
func Unmarshal([]byte, interface{}) error {
return errNotImplemented
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
{{.Comment}} {{ replace .Comment "assert." "require."}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
if h, ok := t.(tHelper); ok { h.Helper() } if h, ok := t.(tHelper); ok { h.Helper() }
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }

View File

@ -187,8 +187,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
EqualExportedValuesf(a.t, expected, actual, msg, args...) EqualExportedValuesf(a.t, expected, actual, msg, args...)
} }
// EqualValues asserts that two objects are equal or convertible to the same types // EqualValues asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// a.EqualValues(uint32(123), int32(123)) // a.EqualValues(uint32(123), int32(123))
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
@ -198,8 +198,8 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
EqualValues(a.t, expected, actual, msgAndArgs...) EqualValues(a.t, expected, actual, msgAndArgs...)
} }
// EqualValuesf asserts that two objects are equal or convertible to the same types // EqualValuesf asserts that two objects are equal or convertible to the larger
// and equal. // type and equal.
// //
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") // a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
@ -337,7 +337,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
// a.EventuallyWithT(func(c *assert.CollectT) { // a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
h.Helper() h.Helper()
@ -362,7 +362,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), w
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { // a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick // // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true") // assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
h.Helper() h.Helper()
@ -1129,6 +1129,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
NotContainsf(a.t, s, contains, msg, args...) NotContainsf(a.t, s, contains, msg, args...)
} }
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
//
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotElementsMatchf(a.t, listA, listB, msg, args...)
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
@ -1201,7 +1235,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
NotEqualf(a.t, expected, actual, msg, args...) NotEqualf(a.t, expected, actual, msg, args...)
} }
// NotErrorIs asserts that at none of the errors in err's chain matches target. // NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorAs(a.t, err, target, msgAndArgs...)
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorAsf(a.t, err, target, msg, args...)
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {
@ -1210,7 +1262,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
NotErrorIs(a.t, err, target, msgAndArgs...) NotErrorIs(a.t, err, target, msgAndArgs...)
} }
// NotErrorIsf asserts that at none of the errors in err's chain matches target. // NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is. // This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok { if h, ok := a.t.(tHelper); ok {

View File

@ -6,7 +6,7 @@ type TestingT interface {
FailNow() FailNow()
} }
type tHelper interface { type tHelper = interface {
Helper() Helper()
} }

8
vendor/modules.txt vendored
View File

@ -525,7 +525,7 @@ github.com/munnerz/goautoneg
# github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f # github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f
## explicit ## explicit
github.com/mxk/go-flowrate/flowrate github.com/mxk/go-flowrate/flowrate
# github.com/onsi/ginkgo/v2 v2.21.0 # github.com/onsi/ginkgo/v2 v2.22.0
## explicit; go 1.22.0 ## explicit; go 1.22.0
github.com/onsi/ginkgo/v2 github.com/onsi/ginkgo/v2
github.com/onsi/ginkgo/v2/config github.com/onsi/ginkgo/v2/config
@ -547,7 +547,7 @@ github.com/onsi/ginkgo/v2/internal/parallel_support
github.com/onsi/ginkgo/v2/internal/testingtproxy github.com/onsi/ginkgo/v2/internal/testingtproxy
github.com/onsi/ginkgo/v2/reporters github.com/onsi/ginkgo/v2/reporters
github.com/onsi/ginkgo/v2/types github.com/onsi/ginkgo/v2/types
# github.com/onsi/gomega v1.35.1 # github.com/onsi/gomega v1.36.0
## explicit; go 1.22 ## explicit; go 1.22
github.com/onsi/gomega github.com/onsi/gomega
github.com/onsi/gomega/format github.com/onsi/gomega/format
@ -555,6 +555,7 @@ github.com/onsi/gomega/gcustom
github.com/onsi/gomega/internal github.com/onsi/gomega/internal
github.com/onsi/gomega/internal/gutil github.com/onsi/gomega/internal/gutil
github.com/onsi/gomega/matchers github.com/onsi/gomega/matchers
github.com/onsi/gomega/matchers/internal/miter
github.com/onsi/gomega/matchers/support/goraph/bipartitegraph github.com/onsi/gomega/matchers/support/goraph/bipartitegraph
github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/edge
github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/node
@ -621,9 +622,10 @@ github.com/spf13/pflag
# github.com/stoewer/go-strcase v1.3.0 # github.com/stoewer/go-strcase v1.3.0
## explicit; go 1.11 ## explicit; go 1.11
github.com/stoewer/go-strcase github.com/stoewer/go-strcase
# github.com/stretchr/testify v1.9.0 # github.com/stretchr/testify v1.10.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/require github.com/stretchr/testify/require
# github.com/x448/float16 v0.8.4 # github.com/x448/float16 v0.8.4
## explicit; go 1.11 ## explicit; go 1.11