Repository navigation
Expand file tree
/
Copy pathtimers_test.go
More file actions
113 lines (99 loc) · 2.92 KB
/
Copy pathtimers_test.go
File metadata and controls
113 lines (99 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package timers_test
import (
"sync/atomic"
"testing"
"time"
"github.com/burrows99/async/timers"
)
func TestSetTimeoutFires(t *testing.T) {
t.Parallel()
var fired atomic.Bool
timers.SetTimeout(func() { fired.Store(true) }, 10*time.Millisecond)
if fired.Load() {
t.Fatal("fired immediately, want after the delay")
}
time.Sleep(40 * time.Millisecond)
if !fired.Load() {
t.Fatal("SetTimeout never fired")
}
}
func TestClearTimeoutCancels(t *testing.T) {
t.Parallel()
var fired atomic.Bool
h := timers.SetTimeout(func() { fired.Store(true) }, 30*time.Millisecond)
timers.ClearTimeout(h)
time.Sleep(60 * time.Millisecond)
if fired.Load() {
t.Fatal("ClearTimeout did not cancel the pending timeout")
}
}
func TestClearTimeoutNilIsNoop(t *testing.T) {
t.Parallel()
timers.ClearTimeout(nil) // must not panic
}
func TestSetIntervalRepeatsUntilCleared(t *testing.T) {
t.Parallel()
var ticks atomic.Int64
iv := timers.SetInterval(func() { ticks.Add(1) }, 10*time.Millisecond)
time.Sleep(55 * time.Millisecond)
timers.ClearInterval(iv)
got := ticks.Load()
if got < 3 {
t.Fatalf("interval ticked %d times in ~55ms at 10ms, want >= 3", got)
}
// After clearing, ticking must stop.
time.Sleep(40 * time.Millisecond)
if after := ticks.Load(); after != got {
t.Fatalf("interval kept ticking after ClearInterval: %d -> %d", got, after)
}
}
func TestClearIntervalIdempotent(t *testing.T) {
t.Parallel()
iv := timers.SetInterval(func() {}, 10*time.Millisecond)
timers.ClearInterval(iv)
timers.ClearInterval(iv) // must not panic (double close guarded by sync.Once)
timers.ClearInterval(nil)
}
func TestDebounceRunsOnceForABurst(t *testing.T) {
t.Parallel()
var calls atomic.Int64
debounced, _ := timers.Debounce(func() { calls.Add(1) }, 20*time.Millisecond)
for range 5 {
debounced()
time.Sleep(2 * time.Millisecond) // rapid, all within the window
}
time.Sleep(50 * time.Millisecond)
if got := calls.Load(); got != 1 {
t.Fatalf("debounced ran %d times for a burst, want 1", got)
}
}
func TestDebounceCancel(t *testing.T) {
t.Parallel()
var calls atomic.Int64
debounced, cancel := timers.Debounce(func() { calls.Add(1) }, 20*time.Millisecond)
debounced()
cancel()
time.Sleep(40 * time.Millisecond)
if got := calls.Load(); got != 0 {
t.Fatalf("debounced ran %d times after cancel, want 0", got)
}
}
func TestThrottleLeadingEdge(t *testing.T) {
t.Parallel()
var calls atomic.Int64
throttled, _ := timers.Throttle(func() { calls.Add(1) }, 50*time.Millisecond)
// A burst inside one window should run exactly once (the leading call).
for range 5 {
throttled()
time.Sleep(2 * time.Millisecond)
}
if got := calls.Load(); got != 1 {
t.Fatalf("throttled ran %d times in one window, want 1", got)
}
// After the window elapses, the next call runs again.
time.Sleep(60 * time.Millisecond)
throttled()
if got := calls.Load(); got != 2 {
t.Fatalf("throttled ran %d times total, want 2 after the window", got)
}
}