Skip to content

Commit 93b53f2

Browse files
committed
feat: add Next() method to mock Clock
1 parent 878bf34 commit 93b53f2

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

clock/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ w.MustWait(ctx)
188188
// d contains the duration we advanced
189189
```
190190

191+
`d, ok := Next()` returns the duration until the next event, if any (`ok` is `true`). You can use
192+
this to advance a specific time, regardless of the tickers and timer events:
193+
194+
```go
195+
desired := time.Minute // time to advance
196+
for desired > 0 {
197+
n, ok := mClock.Next()
198+
if !ok || n > desired {
199+
mClock.Advance(desired).MustWait(ctx)
200+
break
201+
}
202+
mClock.Advance(n).MustWait(ctx)
203+
desired -= n
204+
}
205+
```
206+
191207
### Traps
192208

193209
A trap allows you to match specific calls into the library while mocking, block their return,

clock/mock.go

+12
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,18 @@ func (m *Mock) AdvanceNext() (time.Duration, AdvanceWaiter) {
357357
return d, w
358358
}
359359

360+
// Next returns the duration until the next ticker or timer event and the value
361+
// true, or, if there are no running tickers or timers, it returns zero and
362+
// false.
363+
func (m *Mock) Next() (d time.Duration, ok bool) {
364+
m.mu.Lock()
365+
defer m.mu.Unlock()
366+
if m.nextTime.IsZero() {
367+
return 0, false
368+
}
369+
return m.nextTime.Sub(m.cur), true
370+
}
371+
360372
// Trapper allows the creation of Traps
361373
type Trapper struct {
362374
// mock is the underlying Mock. This is a thin wrapper around Mock so that

clock/mock_test.go

+48-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func TestAfterFunc_NegativeDuration(t *testing.T) {
8484
func TestNewTicker(t *testing.T) {
8585
t.Parallel()
8686
// nolint:gocritic // trying to avoid Coder-specific stuff with an eye toward spinning this out
87-
ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
87+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
8888
defer cancel()
8989

9090
mClock := clock.NewMock(t)
@@ -167,3 +167,50 @@ func TestNewTicker(t *testing.T) {
167167
}
168168
}
169169
}
170+
171+
func TestNext(t *testing.T) {
172+
t.Parallel()
173+
// nolint:gocritic // trying to avoid Coder-specific stuff with an eye toward spinning this out
174+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
175+
defer cancel()
176+
177+
mClock := clock.NewMock(t)
178+
d, ok := mClock.Next()
179+
if d != 0 {
180+
t.Fatal("expected Next() to return 0")
181+
}
182+
if ok {
183+
t.Fatal("expected Next() to return false")
184+
}
185+
186+
tmr := mClock.NewTimer(time.Second)
187+
d, ok = mClock.Next()
188+
if d != time.Second {
189+
t.Fatal("expected Next() to return 1s")
190+
}
191+
if !ok {
192+
t.Fatal("expected Next() to return true")
193+
}
194+
195+
mClock.Advance(999 * time.Millisecond).MustWait(ctx)
196+
d, ok = mClock.Next()
197+
if d != time.Millisecond {
198+
t.Fatal("expected Next() to return 1ms")
199+
}
200+
if !ok {
201+
t.Fatal("expected Next() to return true")
202+
}
203+
204+
stopped := tmr.Stop()
205+
if !stopped {
206+
t.Fatal("expected Stop() to return true")
207+
}
208+
209+
d, ok = mClock.Next()
210+
if d != 0 {
211+
t.Fatal("expected Next() to return 0")
212+
}
213+
if ok {
214+
t.Fatal("expected Next() to return false")
215+
}
216+
}

0 commit comments

Comments
 (0)