mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-03-10 01:19:29 +00:00
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
162 lines
5.6 KiB
Go
162 lines
5.6 KiB
Go
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/onsi/gomega/format"
|
|
"github.com/onsi/gomega/types"
|
|
)
|
|
|
|
type Assertion struct {
|
|
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
|
|
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 {
|
|
return &Assertion{
|
|
actuals: append([]interface{}{actualInput}, extra...),
|
|
actualIndex: 0,
|
|
vet: (*Assertion).vetActuals,
|
|
offset: offset,
|
|
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 {
|
|
assertion.g.THelper()
|
|
vetOptionalDescription("Assertion", optionalDescription...)
|
|
return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
|
|
}
|
|
|
|
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
|
|
assertion.g.THelper()
|
|
vetOptionalDescription("Assertion", optionalDescription...)
|
|
return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
|
|
}
|
|
|
|
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
|
|
assertion.g.THelper()
|
|
vetOptionalDescription("Assertion", optionalDescription...)
|
|
return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
|
|
}
|
|
|
|
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
|
|
assertion.g.THelper()
|
|
vetOptionalDescription("Assertion", optionalDescription...)
|
|
return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
|
|
}
|
|
|
|
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
|
|
assertion.g.THelper()
|
|
vetOptionalDescription("Assertion", optionalDescription...)
|
|
return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
|
|
}
|
|
|
|
func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
|
|
switch len(optionalDescription) {
|
|
case 0:
|
|
return ""
|
|
case 1:
|
|
if describe, ok := optionalDescription[0].(func() string); ok {
|
|
return describe() + "\n"
|
|
}
|
|
}
|
|
return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
|
|
}
|
|
|
|
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
|
|
actualInput := assertion.actuals[assertion.actualIndex]
|
|
matches, err := matcher.Match(actualInput)
|
|
assertion.g.THelper()
|
|
if err != nil {
|
|
description := assertion.buildDescription(optionalDescription...)
|
|
assertion.g.Fail(description+err.Error(), 2+assertion.offset)
|
|
return false
|
|
}
|
|
if matches != desiredMatch {
|
|
var message string
|
|
if desiredMatch {
|
|
message = matcher.FailureMessage(actualInput)
|
|
} else {
|
|
message = matcher.NegatedFailureMessage(actualInput)
|
|
}
|
|
description := assertion.buildDescription(optionalDescription...)
|
|
assertion.g.Fail(description+message, 2+assertion.offset)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// vetActuals vets the actual values, with the (optional) exception of a
|
|
// 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 {
|
|
return true
|
|
}
|
|
|
|
description := assertion.buildDescription(optionalDescription...)
|
|
assertion.g.THelper()
|
|
assertion.g.Fail(description+message, 2+assertion.offset)
|
|
return false
|
|
}
|
|
|
|
// vetError vets the actual values, except for the final error value, in case
|
|
// the final error value is non-zero. Otherwise, it doesn't vet the actual
|
|
// values, as these are allowed to take on any values unless there is a non-zero
|
|
// error value.
|
|
func (assertion *Assertion) vetError(optionalDescription ...interface{}) bool {
|
|
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) {
|
|
var message string
|
|
if err, ok := actual.(error); ok {
|
|
message = fmt.Sprintf("Unexpected error: %s\n%s", err, format.Object(err, 1))
|
|
} else {
|
|
message = fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
|
|
}
|
|
return false, message
|
|
}
|
|
}
|
|
}
|
|
return true, ""
|
|
}
|