Skip to content

Commit

Permalink
Merge pull request vnteamopen#24 from vnteamopen/fix-done-channel
Browse files Browse the repository at this point in the history
Fix done channel
  • Loading branch information
ledongthuc authored May 23, 2022
2 parents ab8103a + 8157702 commit f1527dd
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
11 changes: 7 additions & 4 deletions debouncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Debouncer struct {

// New creates a new instance of debouncer. Each instance of debouncer works independent, concurrency with different wait duration.
func New(duration time.Duration) *Debouncer {
return &Debouncer{timeDuration: duration, triggeredFunc: func() {}, done: make(chan struct{})}
return &Debouncer{timeDuration: duration, triggeredFunc: func() {}}
}

// WithTriggered attached a triggered function to debouncer instance and return the same instance of debouncer to use.
Expand All @@ -32,7 +32,8 @@ func (d *Debouncer) SendSignal() {
d.Cancel()
d.timer = time.AfterFunc(d.timeDuration, func() {
d.triggeredFunc()
d.done <- struct{}{}
close(d.done)
d.done = make(chan struct{})
})
}

Expand All @@ -47,20 +48,22 @@ func (d *Debouncer) Cancel() {
if d.timer != nil {
d.timer.Stop()
}
d.done = make(chan struct{})
}

// UpdateTriggeredFunc replaces triggered function.
func (d *Debouncer) UpdateTriggeredFunc(newTriggeredFunc func()) {
d.triggeredFunc = newTriggeredFunc
}

// UpdateTimeDuratioe replaces the waiting time duration. You need to call a SendSignal() again to trigger a new timer with a new waiting time duration.
// UpdateTimeDuration replaces the waiting time duration. You need to call a SendSignal() again to trigger a new timer with a new waiting time duration.
func (d *Debouncer) UpdateTimeDuration(newTimeDuration time.Duration) {
d.timeDuration = newTimeDuration
}

// Done returns a receive-only channel to notify the caller when the triggered func has been executed.
func (d *Debouncer) Done() <-chan struct{} {
if d.done == nil {
d.done = make(chan struct{})
}
return d.done
}
46 changes: 42 additions & 4 deletions debouncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,17 +216,55 @@ func TestDone(t *testing.T) {
debouncer := godebouncer.New(200 * time.Millisecond).WithTriggered(incrementCount)
expectedCounter := int(2)

fmt.Println("Action 1")
debouncer.SendSignal()
time.Sleep(400 * time.Millisecond)
<-debouncer.Done()

debouncer.SendSignal()
<-debouncer.Done()

if *countPtr != expectedCounter {
t.Errorf("Expected count %d, was %d", expectedCounter, *countPtr)
}
}

func TestDoneInGoroutine(t *testing.T) {
countPtr, incrementCount := createIncrementCount(0)
debouncer := godebouncer.New(200 * time.Millisecond).WithTriggered(incrementCount)
expectedCounter := int(3)

fmt.Println("Action 2")
debouncer.SendSignal()
go func() {
<-debouncer.Done() // awaits for the second send signal to complete
*countPtr += 2
}()

debouncer.SendSignal() // after 1 milliseconds, unblock done channel in 2 goroutines
<-debouncer.Done()

fmt.Println(len(debouncer.Done()))
time.Sleep(200 * time.Millisecond)

if *countPtr != expectedCounter {
t.Errorf("Expected count %d, was %d", expectedCounter, *countPtr)
}
}

func TestDoneHangBeforeSendSignal(t *testing.T) {
debouncer := godebouncer.New(200 * time.Millisecond).WithTriggered(func() {})
select {
case <-debouncer.Done():
t.Error("Done() must hang when being called before SendSignal()")
case <-time.After(time.Second):
}
}

func TestDoneHangIfBeingCalledTwice(t *testing.T) {
debouncer := godebouncer.New(200 * time.Millisecond).WithTriggered(func() {})
debouncer.SendSignal()
<-debouncer.Done()

select {
case <-debouncer.Done():
t.Error("Done() must hang if being called twice")
case <-time.After(time.Second):
}
}

0 comments on commit f1527dd

Please sign in to comment.