Skip to content
Open
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
21 changes: 21 additions & 0 deletions assert/assertion_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package assert
import (
http "net/http"
url "net/url"
reflect "reflect"
time "time"
)

Expand Down Expand Up @@ -475,6 +476,16 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}

// Kindf asserts that the given object's kind matches the expected kind.
//
// assert.Kindf(t, reflect.String, "Hello World", "error message %s", "formatted")
func Kindf(t TestingT, expectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Kind(t, expectedKind, object, append([]interface{}{msg}, args...)...)
}

// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
Expand Down Expand Up @@ -667,6 +678,16 @@ func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{},
return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
}

// NotKindf asserts that the given object's kind does not match the unexpected kind.
//
// assert.NotKindf(t, reflect.Int, "Hello World", "error message %s", "formatted")
func NotKindf(t TestingT, unexpectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotKind(t, unexpectedKind, object, append([]interface{}{msg}, args...)...)
}

// NotNilf asserts that the specified object is not nil.
//
// assert.NotNilf(t, err, "error message %s", "formatted")
Expand Down
41 changes: 41 additions & 0 deletions assert/assertion_forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package assert
import (
http "net/http"
url "net/url"
reflect "reflect"
time "time"
)

Expand Down Expand Up @@ -942,6 +943,26 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
return JSONEqf(a.t, expected, actual, msg, args...)
}

// Kind asserts that the given object's kind matches the expected kind.
//
// a.Kind(reflect.String, "Hello World")
func (a *Assertions) Kind(expectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Kind(a.t, expectedKind, object, msgAndArgs...)
}

// Kindf asserts that the given object's kind matches the expected kind.
//
// a.Kindf(reflect.String, "Hello World", "error message %s", "formatted")
func (a *Assertions) Kindf(expectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Kindf(a.t, expectedKind, object, msg, args...)
}

// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
Expand Down Expand Up @@ -1326,6 +1347,26 @@ func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interfac
return NotImplementsf(a.t, interfaceObject, object, msg, args...)
}

// NotKind asserts that the given object's kind does not match the unexpected kind.
//
// a.NotKind(reflect.Int, "Hello World")
func (a *Assertions) NotKind(unexpectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotKind(a.t, unexpectedKind, object, msgAndArgs...)
}

// NotKindf asserts that the given object's kind does not match the unexpected kind.
//
// a.NotKindf(reflect.Int, "Hello World", "error message %s", "formatted")
func (a *Assertions) NotKindf(unexpectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotKindf(a.t, unexpectedKind, object, msg, args...)
}

// NotNil asserts that the specified object is not nil.
//
// a.NotNil(err)
Expand Down
48 changes: 48 additions & 0 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,54 @@ func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...interface{
return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...)
}

// Kind asserts that the given object's kind matches the expected kind.
//
// assert.Kind(t, reflect.String, "Hello World")
func Kind(t TestingT, expectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case where expectedKind == reflect.Invalid must be rejected (and added to test cases).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this.
I've updated to handle this

if expectedKind == reflect.Invalid {
return Fail(t, "reflect.Invalid must not be used as expected kind", msgAndArgs...)
}

if object == nil {
return Fail(t, "Object must not be nil", msgAndArgs...)
}

objectKind := reflect.TypeOf(object).Kind()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object must be checked for nil and rejected before calling reflect.TypeOf (another missing test case).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this.
I've updated to handle this

if objectKind == expectedKind {
return true
}

return Fail(t, fmt.Sprintf("Object expected to be of kind %v, but was %v", expectedKind, objectKind), msgAndArgs...)
}

// NotKind asserts that the given object's kind does not match the unexpected kind.
//
// assert.NotKind(t, reflect.Int, "Hello World")
func NotKind(t TestingT, unexpectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issues as in Kind:

  • check for reflect.Invalid expectedKind
  • check for nil object

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thank you.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dolmen
Could you re-review, please?

if unexpectedKind == reflect.Invalid {
return Fail(t, "reflect.Invalid must not be used as unexpected kind", msgAndArgs...)
}

if object == nil {
return Fail(t, "Object must not be nil", msgAndArgs...)
}

objectKind := reflect.TypeOf(object).Kind()
if objectKind != unexpectedKind {
return true
}

return Fail(t, fmt.Sprintf("Object expected NOT to be of kind %v, but was %v", unexpectedKind, objectKind), msgAndArgs...)
}

// Equal asserts that two objects are equal.
//
// assert.Equal(t, 123, 123)
Expand Down
75 changes: 75 additions & 0 deletions assert/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,81 @@ func TestNotIsType(t *testing.T) {
}
}

func TestKind(t *testing.T) {
mockT := new(testing.T)

cases := []struct {
expected reflect.Kind
object interface{}
result bool
remark string
}{
// True cases
{reflect.String, "Hello World", true, "is string"},
{reflect.Int, 123, true, "is int"},
{reflect.Array, [6]int{2, 3, 5, 7, 11, 13}, true, "is array"},
{reflect.Func, Kind, true, "is func"},
{reflect.Float64, 0.0345, true, "is float64"},
{reflect.Map, make(map[string]int), true, "is map"},
{reflect.Bool, true, true, "is bool"},
{reflect.Ptr, new(int), true, "is pointer"},

// False cases
{reflect.String, 13, false, "not string"},
{reflect.Int, [6]int{2, 3, 5, 7, 11, 13}, false, "not int"},
{reflect.Float64, 12, false, "not float64"},
{reflect.Bool, make(map[string]int), false, "not bool"},

// Invalid inputs
{reflect.Invalid, "string", false, "reflect.Invalid must not be used as expected kind"},
{reflect.Ptr, nil, false, "Object must not be nil"},
}

for _, c := range cases {
t.Run(fmt.Sprintf("Kind(%#v, %#v)", c.expected, c.object), func(t *testing.T) {
res := Kind(mockT, c.expected, c.object)

if res != c.result {
t.Errorf("Kind(%#v, %#v) should return %#v: %s", c.expected, c.object, c.result, c.remark)
}
})
}
}

func TestNotKind(t *testing.T) {
mockT := new(testing.T)

cases := []struct {
unexpected reflect.Kind
object interface{}
result bool
remark string
}{
// True cases
{reflect.String, 123, true, "not string"},
{reflect.Int, "hi", true, "not int"},
{reflect.Map, []int{1, 2}, true, "not map"},
{reflect.Ptr, 99, true, "not pointer"},

// False cases
{reflect.Func, func() {}, false, "is func"},
{reflect.Bool, false, false, "is bool"},

// Invalid inputs
{reflect.Invalid, "string", false, "reflect.Invalid must not be used as unexpected kind"},
{reflect.Ptr, nil, false, "Object must not be nil"},
}

for _, c := range cases {
t.Run(fmt.Sprintf("NotKind(%#v, %#v)", c.unexpected, c.object), func(t *testing.T) {
res := NotKind(mockT, c.unexpected, c.object)
if res != c.result {
t.Errorf("NotKind(%#v, %#v) should return %#v: %s", c.unexpected, c.object, c.result, c.remark)
}
})
}
}

func TestEqual(t *testing.T) {
t.Parallel()

Expand Down
53 changes: 53 additions & 0 deletions require/require.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
assert "github.com/stretchr/testify/assert"
http "net/http"
url "net/url"
reflect "reflect"
time "time"
)

Expand Down Expand Up @@ -1189,6 +1190,32 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
t.FailNow()
}

// Kind asserts that the given object's kind matches the expected kind.
//
// require.Kind(t, reflect.String, "Hello World")
func Kind(t TestingT, expectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Kind(t, expectedKind, object, msgAndArgs...) {
return
}
t.FailNow()
}

// Kindf asserts that the given object's kind matches the expected kind.
//
// require.Kindf(t, reflect.String, "Hello World", "error message %s", "formatted")
func Kindf(t TestingT, expectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Kindf(t, expectedKind, object, msg, args...) {
return
}
t.FailNow()
}

// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
Expand Down Expand Up @@ -1675,6 +1702,32 @@ func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{},
t.FailNow()
}

// NotKind asserts that the given object's kind does not match the unexpected kind.
//
// require.NotKind(t, reflect.Int, "Hello World")
func NotKind(t TestingT, unexpectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotKind(t, unexpectedKind, object, msgAndArgs...) {
return
}
t.FailNow()
}

// NotKindf asserts that the given object's kind does not match the unexpected kind.
//
// require.NotKindf(t, reflect.Int, "Hello World", "error message %s", "formatted")
func NotKindf(t TestingT, unexpectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotKindf(t, unexpectedKind, object, msg, args...) {
return
}
t.FailNow()
}

// NotNil asserts that the specified object is not nil.
//
// require.NotNil(t, err)
Expand Down
41 changes: 41 additions & 0 deletions require/require_forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
assert "github.com/stretchr/testify/assert"
http "net/http"
url "net/url"
reflect "reflect"
time "time"
)

Expand Down Expand Up @@ -943,6 +944,26 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
JSONEqf(a.t, expected, actual, msg, args...)
}

// Kind asserts that the given object's kind matches the expected kind.
//
// a.Kind(reflect.String, "Hello World")
func (a *Assertions) Kind(expectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Kind(a.t, expectedKind, object, msgAndArgs...)
}

// Kindf asserts that the given object's kind matches the expected kind.
//
// a.Kindf(reflect.String, "Hello World", "error message %s", "formatted")
func (a *Assertions) Kindf(expectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Kindf(a.t, expectedKind, object, msg, args...)
}

// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
Expand Down Expand Up @@ -1327,6 +1348,26 @@ func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interfac
NotImplementsf(a.t, interfaceObject, object, msg, args...)
}

// NotKind asserts that the given object's kind does not match the unexpected kind.
//
// a.NotKind(reflect.Int, "Hello World")
func (a *Assertions) NotKind(unexpectedKind reflect.Kind, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotKind(a.t, unexpectedKind, object, msgAndArgs...)
}

// NotKindf asserts that the given object's kind does not match the unexpected kind.
//
// a.NotKindf(reflect.Int, "Hello World", "error message %s", "formatted")
func (a *Assertions) NotKindf(unexpectedKind reflect.Kind, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotKindf(a.t, unexpectedKind, object, msg, args...)
}

// NotNil asserts that the specified object is not nil.
//
// a.NotNil(err)
Expand Down