package my_sync

// READ https://go.dev/wiki/MutexOrChannel. The gist is that go prefers to share data by
// communicating, not by sharing. This mean stylistically you will see a lot more chan than Mutex

// Channels are good for
// passing ownership of data,
// distributing units of work,
// communicating async results

// Mutexes are good for caches, state.

import (
	"sync"
	"testing"
)

// go vet
// # my_sync
// # [my_sync]
// ./my_sync_test.go:8:36: assertCount passes lock by value: my_sync.Counter contains sync.Mutex
// ./my_sync_test.go:22:18: call of assertCount copies lock value: my_sync.Counter contains sync.Mutex
// ./my_sync_test.go:42:18: call of assertCount copies lock value: my_sync.Counter contains sync.Mutex
// We don't want to copy a mutex. So this should be changed to take a pointer to a counter

func assertCount(t testing.TB, got *Counter, want int) {
	t.Helper()
	if got.Value() != want {
		t.Errorf("got %d, want %d", got.Value(), want)
	}
}

func TestCounter(t *testing.T) {
	t.Run("Incrementing the counter 3 times leaves it at 3", func(t *testing.T) {
		// We could also implemented a `func NewCounter() *Counter {}` if we wanted to.
		counter := Counter{}
		counter.Inc()
		counter.Inc()
		counter.Inc()

		assertCount(t, &counter, 3)

	})

	t.Run("it runs safely concurrently", func(t *testing.T) {
		wantedCount := 1000
		counter := Counter{}

		var wg sync.WaitGroup
		wg.Add(wantedCount)

		for i := 0; i < wantedCount; i++ {
			go func() {
				counter.Inc()
				wg.Done()
			}()
		}
		// blocking call to wait for all goroutines
		wg.Wait()

		assertCount(t, &counter, wantedCount)
	})
}
