package counter import ( "sync" "testing" ) // Counter is a small thread-safe integer counter. type Counter struct { mu sync.Mutex value int64 } // New returns a counter initialized to value. func New(value int64) *Counter { return &Counter{value: value} } // Add increments 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 increments 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 value and returns the previous value. func (c *Counter) Reset(value int64) int64 { c.mu.Lock() defer c.mu.Unlock() old := c.value c.value = value return old } func TestCounterBasic(t *testing.T) { c := New(2) if got := c.Inc(); got != 3 { t.Fatalf("Inc() = %d, want 3", got) } if got := c.Add(4); got != 7 { t.Fatalf("Add(4) = %d, want 7", got) } if old := c.Reset(10); old != 7 { t.Fatalf("Reset(10) old value = %d, want 7", old) } if got := c.Value(); got != 10 { t.Fatalf("Value() = %d, want 10", got) } } func TestCounterConcurrent(t *testing.T) { const goroutines = 32 const increments = 1000 c := New(0) 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) } }