mirror of https://github.com/stretchr/testify.git
Merge branch 'master' into fix-flaky-TestEventuallyIssue805
commit
0feb1d9baf
|
@ -7,8 +7,8 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
go_version:
|
||||
- "1.19"
|
||||
- "1.20"
|
||||
- "1.21"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Go
|
||||
|
@ -28,6 +28,7 @@ jobs:
|
|||
- "1.18"
|
||||
- "1.19"
|
||||
- "1.20"
|
||||
- "1.21"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Go
|
||||
|
|
|
@ -657,10 +657,12 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string,
|
|||
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
|
||||
// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
|
||||
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -744,10 +746,11 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg
|
|||
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subsetf asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
|
||||
// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
|
||||
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
@ -1306,10 +1306,12 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri
|
|||
return NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubset asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||
// a.NotSubset([1, 3, 4], [1, 2])
|
||||
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
|
||||
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1317,10 +1319,12 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
|
|||
return NotSubset(a.t, list, subset, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
|
||||
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
|
||||
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1480,10 +1484,11 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string,
|
|||
return Samef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Subset asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subset asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||
// a.Subset([1, 2, 3], [1, 2])
|
||||
// a.Subset({"x": 1, "y": 2}, {"x": 1})
|
||||
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1491,10 +1496,11 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
|
|||
return Subset(a.t, list, subset, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subsetf asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
|
||||
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
|
||||
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
@ -150,6 +150,8 @@ func copyExportedFields(expected interface{}) interface{} {
|
|||
// structures.
|
||||
//
|
||||
// This function does no assertion of any kind.
|
||||
//
|
||||
// Deprecated: Use [EqualExportedValues] instead.
|
||||
func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
|
||||
expectedCleaned := copyExportedFields(expected)
|
||||
actualCleaned := copyExportedFields(actual)
|
||||
|
@ -630,17 +632,6 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
|||
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
|
||||
}
|
||||
|
||||
// containsKind checks if a specified kind in the slice of kinds.
|
||||
func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
|
||||
for i := 0; i < len(kinds); i++ {
|
||||
if kind == kinds[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// isNil checks if a specified object is nil or not, without Failing.
|
||||
func isNil(object interface{}) bool {
|
||||
if object == nil {
|
||||
|
@ -648,16 +639,13 @@ func isNil(object interface{}) bool {
|
|||
}
|
||||
|
||||
value := reflect.ValueOf(object)
|
||||
kind := value.Kind()
|
||||
isNilableKind := containsKind(
|
||||
[]reflect.Kind{
|
||||
reflect.Chan, reflect.Func,
|
||||
reflect.Interface, reflect.Map,
|
||||
reflect.Ptr, reflect.Slice, reflect.UnsafePointer},
|
||||
kind)
|
||||
switch value.Kind() {
|
||||
case
|
||||
reflect.Chan, reflect.Func,
|
||||
reflect.Interface, reflect.Map,
|
||||
reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
|
||||
|
||||
if isNilableKind && value.IsNil() {
|
||||
return true
|
||||
return value.IsNil()
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -927,10 +915,11 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
|
|||
|
||||
}
|
||||
|
||||
// Subset asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subset asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||
// assert.Subset(t, [1, 2, 3], [1, 2])
|
||||
// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
|
||||
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -983,10 +972,12 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
|
|||
return true
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubset asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||
// assert.NotSubset(t, [1, 3, 4], [1, 2])
|
||||
// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
|
||||
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1466,19 +1457,26 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
|
|||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if expected == nil || actual == nil ||
|
||||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
||||
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
||||
|
||||
if expected == nil || actual == nil {
|
||||
return Fail(t, "Parameters must be slice", msgAndArgs...)
|
||||
}
|
||||
|
||||
actualSlice := reflect.ValueOf(actual)
|
||||
expectedSlice := reflect.ValueOf(expected)
|
||||
actualSlice := reflect.ValueOf(actual)
|
||||
|
||||
for i := 0; i < actualSlice.Len(); i++ {
|
||||
result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
|
||||
if !result {
|
||||
return result
|
||||
if expectedSlice.Type().Kind() != reflect.Slice {
|
||||
return Fail(t, "Expected value must be slice", msgAndArgs...)
|
||||
}
|
||||
|
||||
expectedLen := expectedSlice.Len()
|
||||
if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < expectedLen; i++ {
|
||||
if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -2922,52 +2921,211 @@ func Test_truncatingFormat(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// parseLabeledOutput does the inverse of labeledOutput - it takes a formatted
|
||||
// output string and turns it back into a slice of labeledContent.
|
||||
func parseLabeledOutput(output string) []labeledContent {
|
||||
labelPattern := regexp.MustCompile(`^\t([^\t]*): *\t(.*)$`)
|
||||
contentPattern := regexp.MustCompile(`^\t *\t(.*)$`)
|
||||
var contents []labeledContent
|
||||
lines := strings.Split(output, "\n")
|
||||
i := -1
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
// skip blank lines
|
||||
continue
|
||||
}
|
||||
matches := labelPattern.FindStringSubmatch(line)
|
||||
if len(matches) == 3 {
|
||||
// a label
|
||||
contents = append(contents, labeledContent{
|
||||
label: matches[1],
|
||||
content: matches[2] + "\n",
|
||||
})
|
||||
i++
|
||||
continue
|
||||
}
|
||||
matches = contentPattern.FindStringSubmatch(line)
|
||||
if len(matches) == 2 {
|
||||
// just content
|
||||
if i >= 0 {
|
||||
contents[i].content += matches[1] + "\n"
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Couldn't parse output
|
||||
return nil
|
||||
}
|
||||
return contents
|
||||
}
|
||||
|
||||
type captureTestingT struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
|
||||
ctt.msg = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) {
|
||||
t.Helper()
|
||||
if res != expectedRes {
|
||||
t.Errorf("Should return %t", expectedRes)
|
||||
return
|
||||
}
|
||||
contents := parseLabeledOutput(ctt.msg)
|
||||
if res == true {
|
||||
if contents != nil {
|
||||
t.Errorf("Should not log an error")
|
||||
}
|
||||
return
|
||||
}
|
||||
if contents == nil {
|
||||
t.Errorf("Should log an error. Log output: %v", ctt.msg)
|
||||
return
|
||||
}
|
||||
for _, content := range contents {
|
||||
if content.label == "Error" {
|
||||
if expectedErrMsg == content.content {
|
||||
return
|
||||
}
|
||||
t.Errorf("Logged Error: %v", content.content)
|
||||
}
|
||||
}
|
||||
t.Errorf("Should log Error: %v", expectedErrMsg)
|
||||
}
|
||||
|
||||
func TestErrorIs(t *testing.T) {
|
||||
mockT := new(testing.T)
|
||||
tests := []struct {
|
||||
err error
|
||||
target error
|
||||
result bool
|
||||
err error
|
||||
target error
|
||||
result bool
|
||||
resultErrMsg string
|
||||
}{
|
||||
{io.EOF, io.EOF, true},
|
||||
{fmt.Errorf("wrap: %w", io.EOF), io.EOF, true},
|
||||
{io.EOF, io.ErrClosedPipe, false},
|
||||
{nil, io.EOF, false},
|
||||
{io.EOF, nil, false},
|
||||
{nil, nil, true},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: io.EOF,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: fmt.Errorf("wrap: %w", io.EOF),
|
||||
target: io.EOF,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: io.ErrClosedPipe,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should be in err chain:\n" +
|
||||
"expected: \"io: read/write on closed pipe\"\n" +
|
||||
"in chain: \"EOF\"\n",
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
target: io.EOF,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should be in err chain:\n" +
|
||||
"expected: \"EOF\"\n" +
|
||||
"in chain: \n",
|
||||
},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: nil,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should be in err chain:\n" +
|
||||
"expected: \"\"\n" +
|
||||
"in chain: \"EOF\"\n",
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
target: nil,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: fmt.Errorf("abc: %w", errors.New("def")),
|
||||
target: io.EOF,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should be in err chain:\n" +
|
||||
"expected: \"EOF\"\n" +
|
||||
"in chain: \"abc: def\"\n" +
|
||||
"\t\"def\"\n",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(fmt.Sprintf("ErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) {
|
||||
mockT := new(captureTestingT)
|
||||
res := ErrorIs(mockT, tt.err, tt.target)
|
||||
if res != tt.result {
|
||||
t.Errorf("ErrorIs(%#v,%#v) should return %t", tt.err, tt.target, tt.result)
|
||||
}
|
||||
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotErrorIs(t *testing.T) {
|
||||
mockT := new(testing.T)
|
||||
tests := []struct {
|
||||
err error
|
||||
target error
|
||||
result bool
|
||||
err error
|
||||
target error
|
||||
result bool
|
||||
resultErrMsg string
|
||||
}{
|
||||
{io.EOF, io.EOF, false},
|
||||
{fmt.Errorf("wrap: %w", io.EOF), io.EOF, false},
|
||||
{io.EOF, io.ErrClosedPipe, true},
|
||||
{nil, io.EOF, true},
|
||||
{io.EOF, nil, true},
|
||||
{nil, nil, false},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: io.EOF,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should not be in err chain:\n" +
|
||||
"found: \"EOF\"\n" +
|
||||
"in chain: \"EOF\"\n",
|
||||
},
|
||||
{
|
||||
err: fmt.Errorf("wrap: %w", io.EOF),
|
||||
target: io.EOF,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should not be in err chain:\n" +
|
||||
"found: \"EOF\"\n" +
|
||||
"in chain: \"wrap: EOF\"\n" +
|
||||
"\t\"EOF\"\n",
|
||||
},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: io.ErrClosedPipe,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
target: io.EOF,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: io.EOF,
|
||||
target: nil,
|
||||
result: true,
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
target: nil,
|
||||
result: false,
|
||||
resultErrMsg: "" +
|
||||
"Target error should not be in err chain:\n" +
|
||||
"found: \"\"\n" +
|
||||
"in chain: \n",
|
||||
},
|
||||
{
|
||||
err: fmt.Errorf("abc: %w", errors.New("def")),
|
||||
target: io.EOF,
|
||||
result: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(fmt.Sprintf("NotErrorIs(%#v,%#v)", tt.err, tt.target), func(t *testing.T) {
|
||||
mockT := new(captureTestingT)
|
||||
res := NotErrorIs(mockT, tt.err, tt.target)
|
||||
if res != tt.result {
|
||||
t.Errorf("NotErrorIs(%#v,%#v) should return %t", tt.err, tt.target, tt.result)
|
||||
}
|
||||
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2993,10 +3151,3 @@ func TestErrorAs(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNil(t *testing.T) {
|
||||
var n unsafe.Pointer = nil
|
||||
if !isNil(n) {
|
||||
t.Fatal("fail")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// This package exists just to isolate tests that reference the [unsafe] package.
|
||||
//
|
||||
// The tests in this package are totally safe.
|
||||
package unsafetests
|
|
@ -0,0 +1,34 @@
|
|||
package unsafetests_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type ignoreTestingT struct{}
|
||||
|
||||
var _ assert.TestingT = ignoreTestingT{}
|
||||
|
||||
func (ignoreTestingT) Helper() {}
|
||||
|
||||
func (ignoreTestingT) Errorf(format string, args ...interface{}) {
|
||||
// Run the formatting, but ignore the result
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
_ = msg
|
||||
}
|
||||
|
||||
func TestUnsafePointers(t *testing.T) {
|
||||
var ignore ignoreTestingT
|
||||
|
||||
assert.True(t, assert.Nil(t, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil"))
|
||||
assert.False(t, assert.NotNil(ignore, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil"))
|
||||
|
||||
assert.True(t, assert.Nil(t, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil"))
|
||||
assert.False(t, assert.NotNil(ignore, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil"))
|
||||
|
||||
assert.False(t, assert.Nil(ignore, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil"))
|
||||
assert.True(t, assert.NotNil(t, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil"))
|
||||
}
|
12
doc.go
12
doc.go
|
@ -5,19 +5,7 @@
|
|||
//
|
||||
// The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system.
|
||||
//
|
||||
// The http package contains tools to make it easier to test http activity using the Go testing system.
|
||||
//
|
||||
// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected.
|
||||
//
|
||||
// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces.
|
||||
package testify
|
||||
|
||||
// blank imports help docs.
|
||||
import (
|
||||
// assert package
|
||||
_ "github.com/stretchr/testify/assert"
|
||||
// http package
|
||||
_ "github.com/stretchr/testify/http"
|
||||
// mock package
|
||||
_ "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
|
6
go.mod
6
go.mod
|
@ -7,6 +7,10 @@ go 1.17
|
|||
require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/stretchr/objx v0.5.0
|
||||
github.com/stretchr/objx v0.5.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
// Break dependency cycle with objx.
|
||||
// See https://github.com/stretchr/objx/pull/140
|
||||
exclude github.com/stretchr/testify v1.8.2
|
||||
|
|
10
go.sum
10
go.sum
|
@ -1,16 +1,10 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
|
||||
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// Package http DEPRECATED USE net/http/httptest
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
package http
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
// TestResponseWriter DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
type TestResponseWriter struct {
|
||||
|
||||
// StatusCode is the last int written by the call to WriteHeader(int)
|
||||
|
@ -17,7 +17,7 @@ type TestResponseWriter struct {
|
|||
header http.Header
|
||||
}
|
||||
|
||||
// Header DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
func (rw *TestResponseWriter) Header() http.Header {
|
||||
|
||||
if rw.header == nil {
|
||||
|
@ -27,7 +27,7 @@ func (rw *TestResponseWriter) Header() http.Header {
|
|||
return rw.header
|
||||
}
|
||||
|
||||
// Write DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
func (rw *TestResponseWriter) Write(bytes []byte) (int, error) {
|
||||
|
||||
// assume 200 success if no header has been set
|
||||
|
@ -43,7 +43,7 @@ func (rw *TestResponseWriter) Write(bytes []byte) (int, error) {
|
|||
|
||||
}
|
||||
|
||||
// WriteHeader DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
func (rw *TestResponseWriter) WriteHeader(i int) {
|
||||
rw.StatusCode = i
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// TestRoundTripper DEPRECATED USE net/http/httptest
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
type TestRoundTripper struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// RoundTrip DEPRECATED USE net/http/httptest
|
||||
// Deprecated: Use [net/http/httptest] instead.
|
||||
func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
args := t.Called(req)
|
||||
return args.Get(0).(*http.Response), args.Error(1)
|
||||
|
|
84
mock/mock.go
84
mock/mock.go
|
@ -786,7 +786,7 @@ func AnythingOfType(t string) AnythingOfTypeArgument {
|
|||
// for use when type checking. This is an alternative to AnythingOfType.
|
||||
// Used in Diff and Assert.
|
||||
type IsTypeArgument struct {
|
||||
t interface{}
|
||||
t reflect.Type
|
||||
}
|
||||
|
||||
// IsType returns an IsTypeArgument object containing the type to check for.
|
||||
|
@ -796,7 +796,7 @@ type IsTypeArgument struct {
|
|||
// For example:
|
||||
// Assert(t, IsType(""), IsType(0))
|
||||
func IsType(t interface{}) *IsTypeArgument {
|
||||
return &IsTypeArgument{t: t}
|
||||
return &IsTypeArgument{t: reflect.TypeOf(t)}
|
||||
}
|
||||
|
||||
// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument
|
||||
|
@ -960,53 +960,55 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
|
||||
}
|
||||
} else if reflect.TypeOf(expected) == reflect.TypeOf((*anythingOfTypeArgument)(nil)).Elem() {
|
||||
// type checking
|
||||
if reflect.TypeOf(actual).Name() != string(expected.(anythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(anythingOfTypeArgument)) {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
|
||||
}
|
||||
} else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) {
|
||||
t := expected.(*IsTypeArgument).t
|
||||
if reflect.TypeOf(t) != reflect.TypeOf(actual) {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt)
|
||||
}
|
||||
} else if reflect.TypeOf(expected) == reflect.TypeOf((*FunctionalOptionsArgument)(nil)) {
|
||||
t := expected.(*FunctionalOptionsArgument).value
|
||||
} else {
|
||||
switch expected := expected.(type) {
|
||||
case anythingOfTypeArgument:
|
||||
// type checking
|
||||
if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
|
||||
}
|
||||
case *IsTypeArgument:
|
||||
actualT := reflect.TypeOf(actual)
|
||||
if actualT != expected.t {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt)
|
||||
}
|
||||
case *FunctionalOptionsArgument:
|
||||
t := expected.value
|
||||
|
||||
var name string
|
||||
tValue := reflect.ValueOf(t)
|
||||
if tValue.Len() > 0 {
|
||||
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
|
||||
}
|
||||
var name string
|
||||
tValue := reflect.ValueOf(t)
|
||||
if tValue.Len() > 0 {
|
||||
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
|
||||
}
|
||||
|
||||
tName := reflect.TypeOf(t).Name()
|
||||
if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
|
||||
} else {
|
||||
if ef, af := assertOpts(t, actual); ef == "" && af == "" {
|
||||
tName := reflect.TypeOf(t).Name()
|
||||
if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 {
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
|
||||
} else {
|
||||
if ef, af := assertOpts(t, actual); ef == "" && af == "" {
|
||||
// match
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
|
||||
} else {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
|
||||
// match
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
|
||||
} else {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// normal checking
|
||||
|
||||
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
|
||||
// match
|
||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
|
||||
} else {
|
||||
// not match
|
||||
differences++
|
||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1616,17 +1616,14 @@ func Test_Mock_IsMethodCallable(t *testing.T) {
|
|||
|
||||
func TestIsArgsEqual(t *testing.T) {
|
||||
var expected = Arguments{5, 3, 4, 6, 7, 2}
|
||||
var args = make([]interface{}, 5)
|
||||
for i := 1; i < len(expected); i++ {
|
||||
args[i-1] = expected[i]
|
||||
}
|
||||
|
||||
// Copy elements 1 to 5
|
||||
args := append(([]interface{})(nil), expected[1:]...)
|
||||
args[2] = expected[1]
|
||||
assert.False(t, isArgsEqual(expected, args))
|
||||
|
||||
var arr = make([]interface{}, 6)
|
||||
for i := 0; i < len(expected); i++ {
|
||||
arr[i] = expected[i]
|
||||
}
|
||||
// Clone
|
||||
arr := append(([]interface{})(nil), expected...)
|
||||
assert.True(t, isArgsEqual(expected, arr))
|
||||
}
|
||||
|
||||
|
|
|
@ -1655,10 +1655,12 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string,
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubset asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||
// assert.NotSubset(t, [1, 3, 4], [1, 2])
|
||||
// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
|
||||
func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1669,10 +1671,12 @@ func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...i
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
|
||||
// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
|
||||
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1877,10 +1881,11 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// Subset asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subset asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||
// assert.Subset(t, [1, 2, 3], [1, 2])
|
||||
// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
|
||||
func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1891,10 +1896,11 @@ func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...inte
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subsetf asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
|
||||
// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
|
||||
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
@ -1307,10 +1307,12 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri
|
|||
NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubset asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||
// a.NotSubset([1, 3, 4], [1, 2])
|
||||
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
|
||||
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1318,10 +1320,12 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
|
|||
NotSubset(a.t, list, subset, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
|
||||
// contain all elements given in the specified subset list(array, slice...) or
|
||||
// map.
|
||||
//
|
||||
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
|
||||
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
|
||||
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1481,10 +1485,11 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string,
|
|||
Samef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Subset asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subset asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||
// a.Subset([1, 2, 3], [1, 2])
|
||||
// a.Subset({"x": 1, "y": 2}, {"x": 1})
|
||||
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
@ -1492,10 +1497,11 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
|
|||
Subset(a.t, list, subset, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
// Subsetf asserts that the specified list(array, slice...) or map contains all
|
||||
// elements given in the specified subset list(array, slice...) or map.
|
||||
//
|
||||
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
|
||||
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
|
||||
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
@ -96,19 +96,20 @@ func failOnPanic(t *testing.T, r interface{}) {
|
|||
func (suite *Suite) Run(name string, subtest func()) bool {
|
||||
oldT := suite.T()
|
||||
|
||||
if setupSubTest, ok := suite.s.(SetupSubTest); ok {
|
||||
setupSubTest.SetupSubTest()
|
||||
}
|
||||
|
||||
defer func() {
|
||||
suite.SetT(oldT)
|
||||
if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
|
||||
tearDownSubTest.TearDownSubTest()
|
||||
}
|
||||
}()
|
||||
|
||||
return oldT.Run(name, func(t *testing.T) {
|
||||
suite.SetT(t)
|
||||
defer suite.SetT(oldT)
|
||||
|
||||
defer recoverAndFailOnPanic(t)
|
||||
|
||||
if setupSubTest, ok := suite.s.(SetupSubTest); ok {
|
||||
setupSubTest.SetupSubTest()
|
||||
}
|
||||
|
||||
if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
|
||||
defer tearDownSubTest.TearDownSubTest()
|
||||
}
|
||||
|
||||
subtest()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -27,14 +27,14 @@ func TestSuiteRequireTwice(t *testing.T) {
|
|||
ok := testing.RunTests(
|
||||
allTestsFilter,
|
||||
[]testing.InternalTest{{
|
||||
Name: "TestSuiteRequireTwice",
|
||||
Name: t.Name() + "/SuiteRequireTwice",
|
||||
F: func(t *testing.T) {
|
||||
suite := new(SuiteRequireTwice)
|
||||
Run(t, suite)
|
||||
},
|
||||
}},
|
||||
)
|
||||
assert.Equal(t, false, ok)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func (s *SuiteRequireTwice) TestRequireOne() {
|
||||
|
@ -104,31 +104,31 @@ func TestSuiteRecoverPanic(t *testing.T) {
|
|||
ok := true
|
||||
panickingTests := []testing.InternalTest{
|
||||
{
|
||||
Name: "TestPanicInSetupSuite",
|
||||
Name: t.Name() + "/InSetupSuite",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInSetupTest",
|
||||
Name: t.Name() + "/InSetupTest",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInBeforeTest",
|
||||
Name: t.Name() + "InBeforeTest",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInTest",
|
||||
Name: t.Name() + "/InTest",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInAfterTest",
|
||||
Name: t.Name() + "/InAfterTest",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInTearDownTest",
|
||||
Name: t.Name() + "/InTearDownTest",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) },
|
||||
},
|
||||
{
|
||||
Name: "TestPanicInTearDownSuite",
|
||||
Name: t.Name() + "/InTearDownSuite",
|
||||
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) },
|
||||
},
|
||||
}
|
||||
|
@ -162,6 +162,9 @@ type SuiteTester struct {
|
|||
SetupSubTestRunCount int
|
||||
TearDownSubTestRunCount int
|
||||
|
||||
SetupSubTestNames []string
|
||||
TearDownSubTestNames []string
|
||||
|
||||
SuiteNameBefore []string
|
||||
TestNameBefore []string
|
||||
|
||||
|
@ -258,10 +261,12 @@ func (suite *SuiteTester) TestSubtest() {
|
|||
}
|
||||
|
||||
func (suite *SuiteTester) TearDownSubTest() {
|
||||
suite.TearDownSubTestNames = append(suite.TearDownSubTestNames, suite.T().Name())
|
||||
suite.TearDownSubTestRunCount++
|
||||
}
|
||||
|
||||
func (suite *SuiteTester) SetupSubTest() {
|
||||
suite.SetupSubTestNames = append(suite.SetupSubTestNames, suite.T().Name())
|
||||
suite.SetupSubTestRunCount++
|
||||
}
|
||||
|
||||
|
@ -301,13 +306,13 @@ func TestRunSuite(t *testing.T) {
|
|||
|
||||
// The suite was only run once, so the SetupSuite and TearDownSuite
|
||||
// methods should have each been run only once.
|
||||
assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
|
||||
assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
|
||||
assert.Equal(t, 1, suiteTester.SetupSuiteRunCount)
|
||||
assert.Equal(t, 1, suiteTester.TearDownSuiteRunCount)
|
||||
|
||||
assert.Equal(t, len(suiteTester.SuiteNameAfter), 4)
|
||||
assert.Equal(t, len(suiteTester.SuiteNameBefore), 4)
|
||||
assert.Equal(t, len(suiteTester.TestNameAfter), 4)
|
||||
assert.Equal(t, len(suiteTester.TestNameBefore), 4)
|
||||
assert.Len(t, suiteTester.SuiteNameAfter, 4)
|
||||
assert.Len(t, suiteTester.SuiteNameBefore, 4)
|
||||
assert.Len(t, suiteTester.TestNameAfter, 4)
|
||||
assert.Len(t, suiteTester.TestNameBefore, 4)
|
||||
|
||||
assert.Contains(t, suiteTester.TestNameAfter, "TestOne")
|
||||
assert.Contains(t, suiteTester.TestNameAfter, "TestTwo")
|
||||
|
@ -319,6 +324,12 @@ func TestRunSuite(t *testing.T) {
|
|||
assert.Contains(t, suiteTester.TestNameBefore, "TestSkip")
|
||||
assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest")
|
||||
|
||||
assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/first")
|
||||
assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/second")
|
||||
|
||||
assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/first")
|
||||
assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/second")
|
||||
|
||||
for _, suiteName := range suiteTester.SuiteNameAfter {
|
||||
assert.Equal(t, "SuiteTester", suiteName)
|
||||
}
|
||||
|
@ -338,20 +349,20 @@ func TestRunSuite(t *testing.T) {
|
|||
// There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so
|
||||
// the SetupTest and TearDownTest methods (which should be run once for
|
||||
// each test) should have been run four times.
|
||||
assert.Equal(t, suiteTester.SetupTestRunCount, 4)
|
||||
assert.Equal(t, suiteTester.TearDownTestRunCount, 4)
|
||||
assert.Equal(t, 4, suiteTester.SetupTestRunCount)
|
||||
assert.Equal(t, 4, suiteTester.TearDownTestRunCount)
|
||||
|
||||
// Each test should have been run once.
|
||||
assert.Equal(t, suiteTester.TestOneRunCount, 1)
|
||||
assert.Equal(t, suiteTester.TestTwoRunCount, 1)
|
||||
assert.Equal(t, suiteTester.TestSubtestRunCount, 1)
|
||||
assert.Equal(t, 1, suiteTester.TestOneRunCount)
|
||||
assert.Equal(t, 1, suiteTester.TestTwoRunCount)
|
||||
assert.Equal(t, 1, suiteTester.TestSubtestRunCount)
|
||||
|
||||
assert.Equal(t, suiteTester.TearDownSubTestRunCount, 2)
|
||||
assert.Equal(t, suiteTester.SetupSubTestRunCount, 2)
|
||||
assert.Equal(t, 2, suiteTester.TearDownSubTestRunCount)
|
||||
assert.Equal(t, 2, suiteTester.SetupSubTestRunCount)
|
||||
|
||||
// Methods that don't match the test method identifier shouldn't
|
||||
// have been run at all.
|
||||
assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)
|
||||
assert.Equal(t, 0, suiteTester.NonTestMethodRunCount)
|
||||
|
||||
suiteSkipTester := new(SuiteSkipTester)
|
||||
Run(t, suiteSkipTester)
|
||||
|
@ -359,8 +370,8 @@ func TestRunSuite(t *testing.T) {
|
|||
// The suite was only run once, so the SetupSuite and TearDownSuite
|
||||
// methods should have each been run only once, even though SetupSuite
|
||||
// called Skip()
|
||||
assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1)
|
||||
assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1)
|
||||
assert.Equal(t, 1, suiteSkipTester.SetupSuiteRunCount)
|
||||
assert.Equal(t, 1, suiteSkipTester.TearDownSuiteRunCount)
|
||||
|
||||
}
|
||||
|
||||
|
@ -440,7 +451,7 @@ func TestSuiteLogging(t *testing.T) {
|
|||
suiteLoggingTester := new(SuiteLoggingTester)
|
||||
capture := StdoutCapture{}
|
||||
internalTest := testing.InternalTest{
|
||||
Name: "SomeTest",
|
||||
Name: t.Name() + "/SuiteLoggingTester",
|
||||
F: func(subT *testing.T) {
|
||||
Run(subT, suiteLoggingTester)
|
||||
},
|
||||
|
@ -481,7 +492,7 @@ func (s *CallOrderSuite) SetupSuite() {
|
|||
|
||||
func (s *CallOrderSuite) TearDownSuite() {
|
||||
s.call("TearDownSuite")
|
||||
assert.Equal(s.T(), "SetupSuite;SetupTest;Test A;TearDownTest;SetupTest;Test B;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
|
||||
assert.Equal(s.T(), "SetupSuite;SetupTest;Test A;SetupSubTest;SubTest A1;TearDownSubTest;SetupSubTest;SubTest A2;TearDownSubTest;TearDownTest;SetupTest;Test B;SetupSubTest;SubTest B1;TearDownSubTest;SetupSubTest;SubTest B2;TearDownSubTest;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
|
||||
}
|
||||
func (s *CallOrderSuite) SetupTest() {
|
||||
s.call("SetupTest")
|
||||
|
@ -491,12 +502,32 @@ func (s *CallOrderSuite) TearDownTest() {
|
|||
s.call("TearDownTest")
|
||||
}
|
||||
|
||||
func (s *CallOrderSuite) SetupSubTest() {
|
||||
s.call("SetupSubTest")
|
||||
}
|
||||
|
||||
func (s *CallOrderSuite) TearDownSubTest() {
|
||||
s.call("TearDownSubTest")
|
||||
}
|
||||
|
||||
func (s *CallOrderSuite) Test_A() {
|
||||
s.call("Test A")
|
||||
s.Run("SubTest A1", func() {
|
||||
s.call("SubTest A1")
|
||||
})
|
||||
s.Run("SubTest A2", func() {
|
||||
s.call("SubTest A2")
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CallOrderSuite) Test_B() {
|
||||
s.call("Test B")
|
||||
s.Run("SubTest B1", func() {
|
||||
s.call("SubTest B1")
|
||||
})
|
||||
s.Run("SubTest B2", func() {
|
||||
s.call("SubTest B2")
|
||||
})
|
||||
}
|
||||
|
||||
type suiteWithStats struct {
|
||||
|
@ -521,14 +552,15 @@ func (s *suiteWithStats) TestPanic() {
|
|||
func TestSuiteWithStats(t *testing.T) {
|
||||
suiteWithStats := new(suiteWithStats)
|
||||
|
||||
testing.RunTests(allTestsFilter, []testing.InternalTest{
|
||||
suiteSuccess := testing.RunTests(allTestsFilter, []testing.InternalTest{
|
||||
{
|
||||
Name: "WithStats",
|
||||
Name: t.Name() + "/suiteWithStats",
|
||||
F: func(t *testing.T) {
|
||||
Run(t, suiteWithStats)
|
||||
},
|
||||
},
|
||||
})
|
||||
require.False(t, suiteSuccess, "suiteWithStats should report test failure because of panic in TestPanic")
|
||||
|
||||
assert.True(t, suiteWithStats.wasCalled)
|
||||
assert.NotZero(t, suiteWithStats.stats.Start)
|
||||
|
@ -565,13 +597,13 @@ func TestFailfastSuite(t *testing.T) {
|
|||
ok := testing.RunTests(
|
||||
allTestsFilter,
|
||||
[]testing.InternalTest{{
|
||||
Name: "TestFailfastSuite",
|
||||
Name: t.Name() + "/FailfastSuite",
|
||||
F: func(t *testing.T) {
|
||||
Run(t, s)
|
||||
},
|
||||
}},
|
||||
)
|
||||
assert.Equal(t, false, ok)
|
||||
assert.False(t, ok)
|
||||
if failFast {
|
||||
// Test A Fails and because we are running with failfast Test B never runs and we proceed straight to TearDownSuite
|
||||
assert.Equal(t, "SetupSuite;SetupTest;Test A Fails;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
|
||||
|
@ -617,3 +649,46 @@ func (s *FailfastSuite) Test_B_Passes() {
|
|||
s.call("Test B Passes")
|
||||
s.Require().True(true)
|
||||
}
|
||||
|
||||
type subtestPanicSuite struct {
|
||||
Suite
|
||||
inTearDownSuite bool
|
||||
inTearDownTest bool
|
||||
inTearDownSubTest bool
|
||||
}
|
||||
|
||||
func (s *subtestPanicSuite) TearDownSuite() {
|
||||
s.inTearDownSuite = true
|
||||
}
|
||||
|
||||
func (s *subtestPanicSuite) TearDownTest() {
|
||||
s.inTearDownTest = true
|
||||
}
|
||||
|
||||
func (s *subtestPanicSuite) TearDownSubTest() {
|
||||
s.inTearDownSubTest = true
|
||||
}
|
||||
|
||||
func (s *subtestPanicSuite) TestSubtestPanic() {
|
||||
ok := s.Run("subtest", func() {
|
||||
panic("panic")
|
||||
})
|
||||
s.False(ok, "subtest failure is expected")
|
||||
}
|
||||
|
||||
func TestSubtestPanic(t *testing.T) {
|
||||
suite := new(subtestPanicSuite)
|
||||
ok := testing.RunTests(
|
||||
allTestsFilter,
|
||||
[]testing.InternalTest{{
|
||||
Name: t.Name() + "/subtestPanicSuite",
|
||||
F: func(t *testing.T) {
|
||||
Run(t, suite)
|
||||
},
|
||||
}},
|
||||
)
|
||||
assert.False(t, ok, "TestSubtestPanic/subtest should make the testsuite fail")
|
||||
assert.True(t, suite.inTearDownSubTest)
|
||||
assert.True(t, suite.inTearDownTest)
|
||||
assert.True(t, suite.inTearDownSuite)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue