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