Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion internal/assertions/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,12 @@ func containsElement(list any, element any) (ok, found bool) {

// isList checks that the provided value is array or slice.
func isList(t T, list any, msgAndArgs ...any) (ok bool) {
kind := reflect.TypeOf(list).Kind()
listType := reflect.TypeOf(list)
if listType == nil {
return Fail(t, fmt.Sprintf("%q has an unsupported type <nil>, expecting array or slice", list),
msgAndArgs...)
}
kind := listType.Kind()
if kind != reflect.Array && kind != reflect.Slice {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind),
msgAndArgs...)
Expand Down
12 changes: 10 additions & 2 deletions internal/assertions/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,11 @@ func Positive(t T, e any, msgAndArgs ...any) bool {
if h, ok := t.(H); ok {
h.Helper()
}
zero := reflect.Zero(reflect.TypeOf(e))
eType := reflect.TypeOf(e)
if eType == nil {
return Fail(t, fmt.Sprintf("\"%v\" is not positive", e), msgAndArgs...)
}
zero := reflect.Zero(eType)
failMessage := fmt.Sprintf("\"%v\" is not positive", e)
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...)
}
Expand Down Expand Up @@ -322,7 +326,11 @@ func Negative(t T, e any, msgAndArgs ...any) bool {
if h, ok := t.(H); ok {
h.Helper()
}
zero := reflect.Zero(reflect.TypeOf(e))
eType := reflect.TypeOf(e)
if eType == nil {
return Fail(t, fmt.Sprintf("\"%v\" is not negative", e), msgAndArgs...)
}
zero := reflect.Zero(eType)
failMessage := fmt.Sprintf("\"%v\" is not negative", e)
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...)
}
Expand Down
7 changes: 6 additions & 1 deletion internal/assertions/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package assertions

import (
"errors"
"fmt"
"reflect"
"slices"
Expand Down Expand Up @@ -320,7 +321,11 @@ func IsNonDecreasingT[OrderedSlice ~[]E, E Ordered](t T, collection OrderedSlice
// It returns an error if the object can't be ordered.
// When not strictly ordered, it returns the first 2 offending values found.
func isStrictlyOrdered(object any, reverseOrder bool) ([]any, bool, error) {
objKind := reflect.TypeOf(object).Kind()
objType := reflect.TypeOf(object)
if objType == nil {
return nil, false, errors.New("object <nil> is not an ordered collection")
}
objKind := objType.Kind()
if objKind != reflect.Slice && objKind != reflect.Array {
return nil, false, fmt.Errorf("object %T is not an ordered collection", object)
}
Expand Down
12 changes: 10 additions & 2 deletions internal/assertions/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ func Implements(t T, interfaceObject any, object any, msgAndArgs ...any) bool {
if h, ok := t.(H); ok {
h.Helper()
}
interfaceType := reflect.TypeOf(interfaceObject).Elem()
ifType := reflect.TypeOf(interfaceObject)
if ifType == nil {
return Fail(t, "interfaceObject must be a pointer to an interface type", msgAndArgs...)
}
interfaceType := ifType.Elem()

if object == nil {
return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
Expand All @@ -51,7 +55,11 @@ func NotImplements(t T, interfaceObject any, object any, msgAndArgs ...any) bool
if h, ok := t.(H); ok {
h.Helper()
}
interfaceType := reflect.TypeOf(interfaceObject).Elem()
ifType := reflect.TypeOf(interfaceObject)
if ifType == nil {
return Fail(t, "interfaceObject must be a pointer to an interface type", msgAndArgs...)
}
interfaceType := ifType.Elem()

if object == nil {
return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...)
Expand Down
56 changes: 56 additions & 0 deletions internal/testintegration/assertions/assertions_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0

package assertions

import (
"testing"

"pgregory.net/rapid"

"github.com/go-openapi/testify/v2/internal/assertions"
)

// FuzzAssertionsNilSafety is the fuzzed equivalent of TestNilSafetyUnary
// and TestNilSafetyBinary.
//
// Given a high number of values of different types generated randomly,
// the fuzz engine will alter these values and run assertion functions.
//
// # Property
//
// No assertion function should ever panic, regardless of the inputs.
func FuzzAssertionsNilSafety(f *testing.F) {
prop := func(rt *rapid.T) {
value := genAny().Draw(rt, "value")
other := genAny().Draw(rt, "other")
mock := silentT{}

noPanic(rt, "Nil", func() { _ = assertions.Nil(mock, value) })
noPanic(rt, "NotNil", func() { _ = assertions.NotNil(mock, value) })
noPanic(rt, "Empty", func() { _ = assertions.Empty(mock, value) })
noPanic(rt, "NotEmpty", func() { _ = assertions.NotEmpty(mock, value) })
noPanic(rt, "Zero", func() { _ = assertions.Zero(mock, value) })
noPanic(rt, "NotZero", func() { _ = assertions.NotZero(mock, value) })
noPanic(rt, "Len", func() { _ = assertions.Len(mock, value, 0) })
noPanic(rt, "Equal", func() { _ = assertions.Equal(mock, value, other) })
noPanic(rt, "NotEqual", func() { _ = assertions.NotEqual(mock, value, other) })
noPanic(rt, "EqualValues", func() { _ = assertions.EqualValues(mock, value, other) })
noPanic(rt, "Contains", func() { _ = assertions.Contains(mock, value, other) })
noPanic(rt, "NotContains", func() { _ = assertions.NotContains(mock, value, other) })
noPanic(rt, "IsType", func() { _ = assertions.IsType(mock, value, other) })
noPanic(rt, "IsNotType", func() { _ = assertions.IsNotType(mock, value, other) })
}

f.Fuzz(rapid.MakeFuzz(prop))
}

// noPanic wraps a function call and reports a test error if it panics.
func noPanic(t *rapid.T, name string, fn func()) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("%s panicked: %v", name, r)
}
}()
fn()
}
Loading
Loading