mirror of
https://github.com/stretchr/testify.git
synced 2025-05-31 11:42:44 +00:00
Merge branch 'master' into doc-update-for-error-fn
This commit is contained in:
commit
01b9a87c30
@ -1949,6 +1949,7 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
|||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan bool, 1)
|
ch := make(chan bool, 1)
|
||||||
|
checkCond := func() { ch <- condition() }
|
||||||
|
|
||||||
timer := time.NewTimer(waitFor)
|
timer := time.NewTimer(waitFor)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
@ -1956,18 +1957,23 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
|||||||
ticker := time.NewTicker(tick)
|
ticker := time.NewTicker(tick)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for tick := ticker.C; ; {
|
var tickC <-chan time.Time
|
||||||
|
|
||||||
|
// Check the condition once first on the initial call.
|
||||||
|
go checkCond()
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
||||||
case <-tick:
|
case <-tickC:
|
||||||
tick = nil
|
tickC = nil
|
||||||
go func() { ch <- condition() }()
|
go checkCond()
|
||||||
case v := <-ch:
|
case v := <-ch:
|
||||||
if v {
|
if v {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
tick = ticker.C
|
tickC = ticker.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2037,35 +2043,42 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
|
|||||||
var lastFinishedTickErrs []error
|
var lastFinishedTickErrs []error
|
||||||
ch := make(chan *CollectT, 1)
|
ch := make(chan *CollectT, 1)
|
||||||
|
|
||||||
|
checkCond := func() {
|
||||||
|
collect := new(CollectT)
|
||||||
|
defer func() {
|
||||||
|
ch <- collect
|
||||||
|
}()
|
||||||
|
condition(collect)
|
||||||
|
}
|
||||||
|
|
||||||
timer := time.NewTimer(waitFor)
|
timer := time.NewTimer(waitFor)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
|
||||||
ticker := time.NewTicker(tick)
|
ticker := time.NewTicker(tick)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for tick := ticker.C; ; {
|
var tickC <-chan time.Time
|
||||||
|
|
||||||
|
// Check the condition once first on the initial call.
|
||||||
|
go checkCond()
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
for _, err := range lastFinishedTickErrs {
|
for _, err := range lastFinishedTickErrs {
|
||||||
t.Errorf("%v", err)
|
t.Errorf("%v", err)
|
||||||
}
|
}
|
||||||
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
||||||
case <-tick:
|
case <-tickC:
|
||||||
tick = nil
|
tickC = nil
|
||||||
go func() {
|
go checkCond()
|
||||||
collect := new(CollectT)
|
|
||||||
defer func() {
|
|
||||||
ch <- collect
|
|
||||||
}()
|
|
||||||
condition(collect)
|
|
||||||
}()
|
|
||||||
case collect := <-ch:
|
case collect := <-ch:
|
||||||
if !collect.failed() {
|
if !collect.failed() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
|
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
|
||||||
lastFinishedTickErrs = collect.errors
|
lastFinishedTickErrs = collect.errors
|
||||||
tick = ticker.C
|
tickC = ticker.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2080,6 +2093,7 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D
|
|||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan bool, 1)
|
ch := make(chan bool, 1)
|
||||||
|
checkCond := func() { ch <- condition() }
|
||||||
|
|
||||||
timer := time.NewTimer(waitFor)
|
timer := time.NewTimer(waitFor)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
@ -2087,18 +2101,23 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D
|
|||||||
ticker := time.NewTicker(tick)
|
ticker := time.NewTicker(tick)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for tick := ticker.C; ; {
|
var tickC <-chan time.Time
|
||||||
|
|
||||||
|
// Check the condition once first on the initial call.
|
||||||
|
go checkCond()
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return true
|
return true
|
||||||
case <-tick:
|
case <-tickC:
|
||||||
tick = nil
|
tickC = nil
|
||||||
go func() { ch <- condition() }()
|
go checkCond()
|
||||||
case v := <-ch:
|
case v := <-ch:
|
||||||
if v {
|
if v {
|
||||||
return Fail(t, "Condition satisfied", msgAndArgs...)
|
return Fail(t, "Condition satisfied", msgAndArgs...)
|
||||||
}
|
}
|
||||||
tick = ticker.C
|
tickC = ticker.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3058,6 +3058,49 @@ func TestEventuallyWithTFailNow(t *testing.T) {
|
|||||||
Len(t, mockT.errors, 1)
|
Len(t, mockT.errors, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that a long running condition doesn't block Eventually.
|
||||||
|
// See issue 805 (and its long tail of following issues)
|
||||||
|
func TestEventuallyTimeout(t *testing.T) {
|
||||||
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
NotPanics(t, func() {
|
||||||
|
done, done2 := make(chan struct{}), make(chan struct{})
|
||||||
|
|
||||||
|
// A condition function that returns after the Eventually timeout
|
||||||
|
condition := func() bool {
|
||||||
|
// Wait until Eventually times out and terminates
|
||||||
|
<-done
|
||||||
|
close(done2)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
False(t, Eventually(mockT, condition, time.Millisecond, time.Microsecond))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
<-done2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventuallySucceedQuickly(t *testing.T) {
|
||||||
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
condition := func() bool { return true }
|
||||||
|
|
||||||
|
// By making the tick longer than the total duration, we expect that this test would fail if
|
||||||
|
// we didn't check the condition before the first tick elapses.
|
||||||
|
True(t, Eventually(mockT, condition, 100*time.Millisecond, time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventuallyWithTSucceedQuickly(t *testing.T) {
|
||||||
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
condition := func(t *CollectT) {}
|
||||||
|
|
||||||
|
// By making the tick longer than the total duration, we expect that this test would fail if
|
||||||
|
// we didn't check the condition before the first tick elapses.
|
||||||
|
True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
func TestNeverFalse(t *testing.T) {
|
func TestNeverFalse(t *testing.T) {
|
||||||
condition := func() bool {
|
condition := func() bool {
|
||||||
return false
|
return false
|
||||||
@ -3085,27 +3128,13 @@ func TestNeverTrue(t *testing.T) {
|
|||||||
False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
|
False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a long running condition doesn't block Eventually.
|
func TestNeverFailQuickly(t *testing.T) {
|
||||||
// See issue 805 (and its long tail of following issues)
|
|
||||||
func TestEventuallyTimeout(t *testing.T) {
|
|
||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
|
|
||||||
NotPanics(t, func() {
|
// By making the tick longer than the total duration, we expect that this test would fail if
|
||||||
done, done2 := make(chan struct{}), make(chan struct{})
|
// we didn't check the condition before the first tick elapses.
|
||||||
|
condition := func() bool { return true }
|
||||||
// A condition function that returns after the Eventually timeout
|
False(t, Never(mockT, condition, 100*time.Millisecond, time.Second))
|
||||||
condition := func() bool {
|
|
||||||
// Wait until Eventually times out and terminates
|
|
||||||
<-done
|
|
||||||
close(done2)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
False(t, Eventually(mockT, condition, time.Millisecond, time.Microsecond))
|
|
||||||
|
|
||||||
close(done)
|
|
||||||
<-done2
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_validateEqualArgs(t *testing.T) {
|
func Test_validateEqualArgs(t *testing.T) {
|
||||||
|
72
mock/mock.go
72
mock/mock.go
@ -948,6 +948,8 @@ func (args Arguments) Is(objects ...interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type outputRenderer func() string
|
||||||
|
|
||||||
// Diff gets a string describing the differences between the arguments
|
// Diff gets a string describing the differences between the arguments
|
||||||
// and the specified objects.
|
// and the specified objects.
|
||||||
//
|
//
|
||||||
@ -955,7 +957,7 @@ func (args Arguments) Is(objects ...interface{}) bool {
|
|||||||
func (args Arguments) Diff(objects []interface{}) (string, int) {
|
func (args Arguments) Diff(objects []interface{}) (string, int) {
|
||||||
// TODO: could return string as error and nil for No difference
|
// TODO: could return string as error and nil for No difference
|
||||||
|
|
||||||
output := "\n"
|
var outputBuilder strings.Builder
|
||||||
var differences int
|
var differences int
|
||||||
|
|
||||||
maxArgCount := len(args)
|
maxArgCount := len(args)
|
||||||
@ -963,24 +965,35 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||||||
maxArgCount = len(objects)
|
maxArgCount = len(objects)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outputRenderers := []outputRenderer{}
|
||||||
|
|
||||||
for i := 0; i < maxArgCount; i++ {
|
for i := 0; i < maxArgCount; i++ {
|
||||||
|
i := i
|
||||||
var actual, expected interface{}
|
var actual, expected interface{}
|
||||||
var actualFmt, expectedFmt string
|
var actualFmt, expectedFmt func() string
|
||||||
|
|
||||||
if len(objects) <= i {
|
if len(objects) <= i {
|
||||||
actual = "(Missing)"
|
actual = "(Missing)"
|
||||||
actualFmt = "(Missing)"
|
actualFmt = func() string {
|
||||||
|
return "(Missing)"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
actual = objects[i]
|
actual = objects[i]
|
||||||
actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual)
|
actualFmt = func() string {
|
||||||
|
return fmt.Sprintf("(%[1]T=%[1]v)", actual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) <= i {
|
if len(args) <= i {
|
||||||
expected = "(Missing)"
|
expected = "(Missing)"
|
||||||
expectedFmt = "(Missing)"
|
expectedFmt = func() string {
|
||||||
|
return "(Missing)"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
expected = args[i]
|
expected = args[i]
|
||||||
expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected)
|
expectedFmt = func() string {
|
||||||
|
return fmt.Sprintf("(%[1]T=%[1]v)", expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matcher, ok := expected.(argumentMatcher); ok {
|
if matcher, ok := expected.(argumentMatcher); ok {
|
||||||
@ -988,16 +1001,22 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||||||
func() {
|
func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
actualFmt = fmt.Sprintf("panic in argument matcher: %v", r)
|
actualFmt = func() string {
|
||||||
|
return fmt.Sprintf("panic in argument matcher: %v", r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
matches = matcher.Matches(actual)
|
matches = matcher.Matches(actual)
|
||||||
}()
|
}()
|
||||||
if matches {
|
if matches {
|
||||||
output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: PASS: %s matched by %s\n", i, actualFmt(), matcher)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: %s not matched by %s\n", i, actualFmt(), matcher)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch expected := expected.(type) {
|
switch expected := expected.(type) {
|
||||||
@ -1006,13 +1025,17 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||||||
if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) {
|
if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) {
|
||||||
// not match
|
// not match
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, expected, reflect.TypeOf(actual).Name(), actualFmt())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case *IsTypeArgument:
|
case *IsTypeArgument:
|
||||||
actualT := reflect.TypeOf(actual)
|
actualT := reflect.TypeOf(actual)
|
||||||
if actualT != expected.t {
|
if actualT != expected.t {
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, expected.t.Name(), actualT.Name(), actualFmt())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case *FunctionalOptionsArgument:
|
case *FunctionalOptionsArgument:
|
||||||
var name string
|
var name string
|
||||||
@ -1023,26 +1046,36 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||||||
const tName = "[]interface{}"
|
const tName = "[]interface{}"
|
||||||
if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 {
|
if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 {
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, tName, reflect.TypeOf(actual).Name(), actualFmt())
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" {
|
if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" {
|
||||||
// match
|
// match
|
||||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: PASS: %s == %s\n", i, tName, tName)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// not match
|
// not match
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: %s != %s\n", i, af, ef)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
|
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
|
||||||
// match
|
// match
|
||||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: PASS: %s == %s\n", i, actualFmt(), expectedFmt())
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// not match
|
// not match
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
|
outputRenderers = append(outputRenderers, func() string {
|
||||||
|
return fmt.Sprintf("\t%d: FAIL: %s != %s\n", i, actualFmt(), expectedFmt())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1053,7 +1086,12 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
|||||||
return "No differences.", differences
|
return "No differences.", differences
|
||||||
}
|
}
|
||||||
|
|
||||||
return output, differences
|
outputBuilder.WriteString("\n")
|
||||||
|
for _, r := range outputRenderers {
|
||||||
|
outputBuilder.WriteString(r())
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputBuilder.String(), differences
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert compares the arguments with the specified objects and fails if
|
// Assert compares the arguments with the specified objects and fails if
|
||||||
|
Loading…
x
Reference in New Issue
Block a user