mirror of https://github.com/stretchr/testify.git
assert: fix error message formatting for NotContains (#1362)
* assert: rename and refactor TestContainsFailMessage I've renamed it to TestContainsNotContains and added a test case structure so that I can use this test to validate the failure messages from both Contains and NotContains, There are no functional changes here, strictly refactoring. A new test case will be added in a subsequent change. * assert: fix error message formatting for NotContains It was using "%s" to format the s and contains arguments, but these could be any type that supports iteration such as a map. In this case of NotContains failing against a map, it would print something like: "map[one:%!s(int=1)]" should not contain "one" Fix this using "%#v" as was already done for Contains and added test cases covering both the "len()" / iterable failure messages as well as the Contains/NotContains failure case. The new message for this example map would be something like: map[string]int{"one":1} should not contain "one"pull/1336/merge
parent
c5fc9d6b6b
commit
437071b948
|
@ -877,10 +877,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
|
||||||
|
|
||||||
ok, found := containsElement(s, contains)
|
ok, found := containsElement(s, contains)
|
||||||
if !ok {
|
if !ok {
|
||||||
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
|
||||||
}
|
}
|
||||||
if found {
|
if found {
|
||||||
return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -688,15 +689,59 @@ func TestContainsNotContains(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainsFailMessage(t *testing.T) {
|
func TestContainsNotContainsFailMessage(t *testing.T) {
|
||||||
|
|
||||||
mockT := new(mockTestingT)
|
mockT := new(mockTestingT)
|
||||||
|
|
||||||
Contains(mockT, "Hello World", errors.New("Hello"))
|
type nonContainer struct {
|
||||||
expectedFail := "\"Hello World\" does not contain &errors.errorString{s:\"Hello\"}"
|
Value string
|
||||||
actualFail := mockT.errorString()
|
}
|
||||||
if !strings.Contains(actualFail, expectedFail) {
|
|
||||||
t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail)
|
cases := []struct {
|
||||||
|
assertion func(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool
|
||||||
|
container interface{}
|
||||||
|
instance interface{}
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
assertion: Contains,
|
||||||
|
container: "Hello World",
|
||||||
|
instance: errors.New("Hello"),
|
||||||
|
expected: "\"Hello World\" does not contain &errors.errorString{s:\"Hello\"}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assertion: Contains,
|
||||||
|
container: map[string]int{"one": 1},
|
||||||
|
instance: "two",
|
||||||
|
expected: "map[string]int{\"one\":1} does not contain \"two\"\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assertion: NotContains,
|
||||||
|
container: map[string]int{"one": 1},
|
||||||
|
instance: "one",
|
||||||
|
expected: "map[string]int{\"one\":1} should not contain \"one\"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assertion: Contains,
|
||||||
|
container: nonContainer{Value: "Hello"},
|
||||||
|
instance: "Hello",
|
||||||
|
expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assertion: NotContains,
|
||||||
|
container: nonContainer{Value: "Hello"},
|
||||||
|
instance: "Hello",
|
||||||
|
expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
name := filepath.Base(runtime.FuncForPC(reflect.ValueOf(c.assertion).Pointer()).Name())
|
||||||
|
t.Run(fmt.Sprintf("%v(%T, %T)", name, c.container, c.instance), func(t *testing.T) {
|
||||||
|
c.assertion(mockT, c.container, c.instance)
|
||||||
|
actualFail := mockT.errorString()
|
||||||
|
if !strings.Contains(actualFail, c.expected) {
|
||||||
|
t.Errorf("Contains failure should include %q but was %q", c.expected, actualFail)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue