Skip to content

Commit f3b35fa

Browse files
committed
add EventuallyWithT assertion
1 parent 181cea6 commit f3b35fa

File tree

6 files changed

+362
-0
lines changed

6 files changed

+362
-0
lines changed

assert/assertion_format.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,40 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
155155
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
156156
}
157157

158+
// EventuallyWithTf asserts that given condition will be met in waitFor time,
159+
// periodically checking target function each tick. In contrast to Eventually,
160+
// it supplies a CollectT to the condition function, so that the condition
161+
// function can use the CollectT to call other assertions.
162+
// The supplied CollectT collects all errors from one tick (if there are any).
163+
// If the condition is not met before waitFor, the collected errors of
164+
// the last tick are copied to t.
165+
//
166+
// falseThenTrue := func(falses int) func() bool {
167+
// count := 0
168+
// return func() bool {
169+
// if count < falses {
170+
// count++
171+
// return false
172+
// }
173+
// return true
174+
// }
175+
// }
176+
// f := falseThenTrue(5)
177+
// assert.EventuallyWithTf(t, func(mockT *assert.CollectT) (success bool, "error message %s", "formatted") {
178+
// defer func() {
179+
// r := recover()
180+
// success = (r == nil)
181+
// }()
182+
// assert.True(mockT, f())
183+
// return
184+
// }, 50*time.Millisecond, 10*time.Millisecond)
185+
func EventuallyWithTf(t TestingT, condition func(collect *CollectT) bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
186+
if h, ok := t.(tHelper); ok {
187+
h.Helper()
188+
}
189+
return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
190+
}
191+
158192
// Exactlyf asserts that two objects are equal in value and type.
159193
//
160194
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")

assert/assertion_forward.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,74 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
288288
return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
289289
}
290290

291+
// EventuallyWithT asserts that given condition will be met in waitFor time,
292+
// periodically checking target function each tick. In contrast to Eventually,
293+
// it supplies a CollectT to the condition function, so that the condition
294+
// function can use the CollectT to call other assertions.
295+
// The supplied CollectT collects all errors from one tick (if there are any).
296+
// If the condition is not met before waitFor, the collected errors of
297+
// the last tick are copied to t.
298+
//
299+
// falseThenTrue := func(falses int) func() bool {
300+
// count := 0
301+
// return func() bool {
302+
// if count < falses {
303+
// count++
304+
// return false
305+
// }
306+
// return true
307+
// }
308+
// }
309+
// f := falseThenTrue(5)
310+
// a.EventuallyWithT(func(mockT *assert.CollectT) (success bool) {
311+
// defer func() {
312+
// r := recover()
313+
// success = (r == nil)
314+
// }()
315+
// assert.True(mockT, f())
316+
// return
317+
// }, 50*time.Millisecond, 10*time.Millisecond)
318+
func (a *Assertions) EventuallyWithT(condition func(collect *CollectT) bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
319+
if h, ok := a.t.(tHelper); ok {
320+
h.Helper()
321+
}
322+
return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
323+
}
324+
325+
// EventuallyWithTf asserts that given condition will be met in waitFor time,
326+
// periodically checking target function each tick. In contrast to Eventually,
327+
// it supplies a CollectT to the condition function, so that the condition
328+
// function can use the CollectT to call other assertions.
329+
// The supplied CollectT collects all errors from one tick (if there are any).
330+
// If the condition is not met before waitFor, the collected errors of
331+
// the last tick are copied to t.
332+
//
333+
// falseThenTrue := func(falses int) func() bool {
334+
// count := 0
335+
// return func() bool {
336+
// if count < falses {
337+
// count++
338+
// return false
339+
// }
340+
// return true
341+
// }
342+
// }
343+
// f := falseThenTrue(5)
344+
// a.EventuallyWithTf(func(mockT *assert.CollectT) (success bool, "error message %s", "formatted") {
345+
// defer func() {
346+
// r := recover()
347+
// success = (r == nil)
348+
// }()
349+
// assert.True(mockT, f())
350+
// return
351+
// }, 50*time.Millisecond, 10*time.Millisecond)
352+
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT) bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
353+
if h, ok := a.t.(tHelper); ok {
354+
h.Helper()
355+
}
356+
return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
357+
}
358+
291359
// Eventuallyf asserts that given condition will be met in waitFor time,
292360
// periodically checking target function each tick.
293361
//

assert/assertions.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,92 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
17561756
}
17571757
}
17581758

1759+
// CollectT implements the TestingT interface and collects all errors.
1760+
type CollectT struct {
1761+
errors []error
1762+
}
1763+
1764+
// Errorf collects the error.
1765+
func (c *CollectT) Errorf(format string, args ...interface{}) {
1766+
c.errors = append(c.errors, fmt.Errorf(format, args...))
1767+
}
1768+
1769+
// FailNow panics.
1770+
func (c *CollectT) FailNow() {
1771+
panic("Assertion failed")
1772+
}
1773+
1774+
// Reset clears the collected errors.
1775+
func (c *CollectT) Reset() {
1776+
c.errors = nil
1777+
}
1778+
1779+
// Copy copies the collected errors to the supplied t.
1780+
func (c *CollectT) Copy(t TestingT) {
1781+
for _, err := range c.errors {
1782+
t.Errorf("%v", err)
1783+
}
1784+
}
1785+
1786+
// EventuallyWithT asserts that given condition will be met in waitFor time,
1787+
// periodically checking target function each tick. In contrast to Eventually,
1788+
// it supplies a CollectT to the condition function, so that the condition
1789+
// function can use the CollectT to call other assertions.
1790+
// The supplied CollectT collects all errors from one tick (if there are any).
1791+
// If the condition is not met before waitFor, the collected errors of
1792+
// the last tick are copied to t.
1793+
//
1794+
// falseThenTrue := func(falses int) func() bool {
1795+
// count := 0
1796+
// return func() bool {
1797+
// if count < falses {
1798+
// count++
1799+
// return false
1800+
// }
1801+
// return true
1802+
// }
1803+
// }
1804+
// f := falseThenTrue(5)
1805+
// assert.EventuallyWithT(t, func(mockT *assert.CollectT) (success bool) {
1806+
// defer func() {
1807+
// r := recover()
1808+
// success = (r == nil)
1809+
// }()
1810+
// assert.True(mockT, f())
1811+
// return
1812+
// }, 50*time.Millisecond, 10*time.Millisecond)
1813+
func EventuallyWithT(t TestingT, condition func(collect *CollectT) bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
1814+
if h, ok := t.(tHelper); ok {
1815+
h.Helper()
1816+
}
1817+
1818+
collect := new(CollectT)
1819+
ch := make(chan bool, 1)
1820+
1821+
timer := time.NewTimer(waitFor)
1822+
defer timer.Stop()
1823+
1824+
ticker := time.NewTicker(tick)
1825+
defer ticker.Stop()
1826+
1827+
for tick := ticker.C; ; {
1828+
select {
1829+
case <-timer.C:
1830+
collect.Copy(t)
1831+
return Fail(t, "Condition never satisfied", msgAndArgs...)
1832+
case <-tick:
1833+
tick = nil
1834+
collect.Reset()
1835+
go func() { ch <- condition(collect) }()
1836+
case v := <-ch:
1837+
if v {
1838+
return true
1839+
}
1840+
tick = ticker.C
1841+
}
1842+
}
1843+
}
1844+
17591845
// Never asserts that the given condition doesn't satisfy in waitFor time,
17601846
// periodically checking the target function each tick.
17611847
//

assert/assertions_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,6 +2428,38 @@ func TestEventuallyTrue(t *testing.T) {
24282428
True(t, Eventually(t, condition, 100*time.Millisecond, 20*time.Millisecond))
24292429
}
24302430

2431+
func TestEventuallyWithTFalse(t *testing.T) {
2432+
mockT := new(CollectT)
2433+
2434+
condition := func(collect *CollectT) bool {
2435+
return True(collect, false)
2436+
}
2437+
2438+
False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
2439+
Len(t, mockT.errors, 2)
2440+
}
2441+
2442+
func TestEventuallyWithTTrue(t *testing.T) {
2443+
mockT := new(CollectT)
2444+
2445+
state := 0
2446+
condition := func(collect *CollectT) bool {
2447+
defer func() {
2448+
state += 1
2449+
}()
2450+
2451+
if state == 2 {
2452+
True(collect, true)
2453+
return true
2454+
}
2455+
2456+
return True(collect, false)
2457+
}
2458+
2459+
True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
2460+
Len(t, mockT.errors, 0)
2461+
}
2462+
24312463
func TestNeverFalse(t *testing.T) {
24322464
condition := func() bool {
24332465
return false

require/require.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,80 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
364364
t.FailNow()
365365
}
366366

367+
// EventuallyWithT asserts that given condition will be met in waitFor time,
368+
// periodically checking target function each tick. In contrast to Eventually,
369+
// it supplies a CollectT to the condition function, so that the condition
370+
// function can use the CollectT to call other assertions.
371+
// The supplied CollectT collects all errors from one tick (if there are any).
372+
// If the condition is not met before waitFor, the collected errors of
373+
// the last tick are copied to t.
374+
//
375+
// falseThenTrue := func(falses int) func() bool {
376+
// count := 0
377+
// return func() bool {
378+
// if count < falses {
379+
// count++
380+
// return false
381+
// }
382+
// return true
383+
// }
384+
// }
385+
// f := falseThenTrue(5)
386+
// assert.EventuallyWithT(t, func(mockT *assert.CollectT) (success bool) {
387+
// defer func() {
388+
// r := recover()
389+
// success = (r == nil)
390+
// }()
391+
// assert.True(mockT, f())
392+
// return
393+
// }, 50*time.Millisecond, 10*time.Millisecond)
394+
func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT) bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
395+
if h, ok := t.(tHelper); ok {
396+
h.Helper()
397+
}
398+
if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) {
399+
return
400+
}
401+
t.FailNow()
402+
}
403+
404+
// EventuallyWithTf asserts that given condition will be met in waitFor time,
405+
// periodically checking target function each tick. In contrast to Eventually,
406+
// it supplies a CollectT to the condition function, so that the condition
407+
// function can use the CollectT to call other assertions.
408+
// The supplied CollectT collects all errors from one tick (if there are any).
409+
// If the condition is not met before waitFor, the collected errors of
410+
// the last tick are copied to t.
411+
//
412+
// falseThenTrue := func(falses int) func() bool {
413+
// count := 0
414+
// return func() bool {
415+
// if count < falses {
416+
// count++
417+
// return false
418+
// }
419+
// return true
420+
// }
421+
// }
422+
// f := falseThenTrue(5)
423+
// assert.EventuallyWithTf(t, func(mockT *assert.CollectT) (success bool, "error message %s", "formatted") {
424+
// defer func() {
425+
// r := recover()
426+
// success = (r == nil)
427+
// }()
428+
// assert.True(mockT, f())
429+
// return
430+
// }, 50*time.Millisecond, 10*time.Millisecond)
431+
func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT) bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
432+
if h, ok := t.(tHelper); ok {
433+
h.Helper()
434+
}
435+
if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) {
436+
return
437+
}
438+
t.FailNow()
439+
}
440+
367441
// Eventuallyf asserts that given condition will be met in waitFor time,
368442
// periodically checking target function each tick.
369443
//

0 commit comments

Comments
 (0)