package counter import ( "sync" "testing" ) // Counter is a thread-safe integer counter. type Counter struct { mu sync.RWMutex value int64 } // Add changes the counter by delta and returns its new value. func (c *Counter) Add(delta int64) int64 { c.mu.Lock() defer c.mu.Unlock() c.value += delta return c.value } // Increment increases the counter by one and returns its new value. func (c *Counter) Increment() int64 { return c.Add(1) } // Value returns the current counter value. func (c *Counter) Value() int64 { c.mu.RLock() defer c.mu.RUnlock() return c.value } // Reset sets the counter to zero. func (c *Counter) Reset() { c.mu.Lock() defer c.mu.Unlock() c.value = 0 } func TestCounter(t *testing.T) { var c Counter c.Increment() c.Add(4) if got, want := c.Value(), int64(5); got != want { t.Fatalf("Value() = %d, want %d", got, want) } c.Reset() if got := c.Value(); got != 0 { t.Fatalf("Value() after Reset() = %d, want 0", got) } } func TestCounterConcurrent(t *testing.T) { var c Counter var wg sync.WaitGroup const goroutines = 20 const increments = 1_000 wg.Add(goroutines) for range goroutines { go func() { defer wg.Done() for range increments { c.Increment() } }() } wg.Wait() if got, want := c.Value(), int64(goroutines*increments); got != want { t.Fatalf("Value() = %d, want %d", got, want) } }