package once

import (
	"errors"
	"sync"
	"testing"
)

func TestOncev2_Do(t *testing.T) {
	var count int

	var once Oncev2
	for i := 0; i < 5; i++ {
		err := once.Do(func() error {
			count++
			return nil
		})
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
		}
	}

	if count != 1 {
		t.Errorf("Function called %d times, expected 1", count)
	}
}

func TestOncev2_DoWithError(t *testing.T) {
	var count int

	var once Oncev2
	for i := 0; i < 5; i++ {
		err := once.Do(func() error {
			count++
			return errors.New("an error occurred")
		})
		if err == nil {
			t.Error("Expected error, got nil")
		}
	}

	if count != 5 {
		t.Errorf("Function called %d times, expected 5", count)
	}
}

func TestOncev2_DoConcurrent(t *testing.T) {
	var count int

	var once Oncev2
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			err := once.Do(func() error {
				count++
				return nil
			})
			if err != nil {
				t.Errorf("Unexpected error: %v", err)
			}
		}()
	}
	wg.Wait()

	if count != 1 {
		t.Errorf("Function called %d times, expected 1", count)
	}
}

func TestOncev2_DoWithPanic(t *testing.T) {
	var count int

	var once Oncev2

	defer func() {
		if r := recover(); r != nil {
			t.Logf("Recovered from panic: %v", r)
			if count != 1 {
				t.Errorf("Function called %d times, expected 1", count)
			}
		}
	}()

	for i := 0; i < 5; i++ {
		err := once.Do(func() error {
			count++
			panic("the panic for test")
		})
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
		}
	}
}
