github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/common/debounce/debounce_test.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package debounce
    20  
    21  import (
    22  	"fmt"
    23  	"sync"
    24  	"sync/atomic"
    25  	"testing"
    26  	"time"
    27  )
    28  
    29  func TestDebounce(t *testing.T) {
    30  	var (
    31  		counter1 uint64
    32  		counter2 uint64
    33  	)
    34  
    35  	f1 := func() {
    36  		atomic.AddUint64(&counter1, 1)
    37  	}
    38  
    39  	f2 := func() {
    40  		atomic.AddUint64(&counter2, 1)
    41  	}
    42  
    43  	f3 := func() {
    44  		atomic.AddUint64(&counter2, 2)
    45  	}
    46  
    47  	debounced := New(100 * time.Millisecond)
    48  
    49  	for i := 0; i < 3; i++ {
    50  		for j := 0; j < 10; j++ {
    51  			debounced(f1)
    52  		}
    53  
    54  		time.Sleep(200 * time.Millisecond)
    55  	}
    56  
    57  	for i := 0; i < 4; i++ {
    58  		for j := 0; j < 10; j++ {
    59  			debounced(f2)
    60  		}
    61  		for j := 0; j < 10; j++ {
    62  			debounced(f3)
    63  		}
    64  
    65  		time.Sleep(200 * time.Millisecond)
    66  	}
    67  
    68  	c1 := int(atomic.LoadUint64(&counter1))
    69  	c2 := int(atomic.LoadUint64(&counter2))
    70  	if c1 != 3 {
    71  		t.Error("Expected count 3, was", c1)
    72  	}
    73  	if c2 != 8 {
    74  		t.Error("Expected count 8, was", c2)
    75  	}
    76  
    77  	fmt.Println("counter1", c1)
    78  	fmt.Println("counter2", c2)
    79  }
    80  
    81  func TestDebounceConcurrentAdd(t *testing.T) {
    82  	var wg sync.WaitGroup
    83  
    84  	var flag uint64
    85  
    86  	debounced := New(100 * time.Millisecond)
    87  
    88  	for i := 0; i < 10; i++ {
    89  		wg.Add(1)
    90  		go func() {
    91  			defer wg.Done()
    92  			debounced(func() {
    93  				atomic.CompareAndSwapUint64(&flag, 0, 1)
    94  			})
    95  		}()
    96  	}
    97  	wg.Wait()
    98  
    99  	time.Sleep(500 * time.Millisecond)
   100  	c := int(atomic.LoadUint64(&flag))
   101  	if c != 1 {
   102  		t.Error("Flag not set")
   103  	}
   104  }
   105  
   106  // Issue #1
   107  func TestDebounceDelayed(t *testing.T) {
   108  
   109  	var (
   110  		counter1 uint64
   111  	)
   112  
   113  	f1 := func() {
   114  		atomic.AddUint64(&counter1, 1)
   115  	}
   116  
   117  	debounced := New(100 * time.Millisecond)
   118  
   119  	time.Sleep(110 * time.Millisecond)
   120  
   121  	debounced(f1)
   122  
   123  	time.Sleep(200 * time.Millisecond)
   124  
   125  	c1 := int(atomic.LoadUint64(&counter1))
   126  	if c1 != 1 {
   127  		t.Error("Expected count 1, was", c1)
   128  	}
   129  
   130  }
   131  
   132  func BenchmarkDebounce(b *testing.B) {
   133  	var counter uint64
   134  
   135  	f := func() {
   136  		atomic.AddUint64(&counter, 1)
   137  	}
   138  
   139  	debounced := New(100 * time.Millisecond)
   140  
   141  	b.ResetTimer()
   142  	for i := 0; i < b.N; i++ {
   143  		debounced(f)
   144  	}
   145  
   146  	c := int(atomic.LoadUint64(&counter))
   147  	if c != 0 {
   148  		b.Fatal("Expected count 0, was", c)
   149  	}
   150  }
   151  
   152  func ExampleNew() {
   153  	var counter uint64
   154  
   155  	f := func() {
   156  		atomic.AddUint64(&counter, 1)
   157  	}
   158  
   159  	debounced := New(100 * time.Millisecond)
   160  
   161  	for i := 0; i < 3; i++ {
   162  		for j := 0; j < 10; j++ {
   163  			debounced(f)
   164  		}
   165  
   166  		time.Sleep(200 * time.Millisecond)
   167  	}
   168  
   169  	c := int(atomic.LoadUint64(&counter))
   170  
   171  	fmt.Println("Counter is", c)
   172  	// Output: Counter is 3
   173  }
   174  
   175  func ExampleNew2() {
   176  	var counter1 uint64
   177  	var counter2 uint64
   178  
   179  	f := func() {
   180  		atomic.AddUint64(&counter1, 1)
   181  	}
   182  
   183  	f2 := func() {
   184  		atomic.AddUint64(&counter2, 1)
   185  	}
   186  
   187  	debounced := New(100 * time.Millisecond)
   188  
   189  	debounced(f) // will be reset and dropped!!!
   190  	for i := 0; i < 10; i++ {
   191  		debounced(f2)
   192  	}
   193  
   194  	time.Sleep(time.Millisecond * 500)
   195  
   196  	c1 := int(atomic.LoadUint64(&counter1))
   197  	c2 := int(atomic.LoadUint64(&counter2))
   198  
   199  	fmt.Println("Counter1 is", c1)
   200  	fmt.Println("Counter2 is", c2)
   201  	// Output: Counter1 is 0
   202  	// Counter2 is 1
   203  }