package main

import (
	"slices"
	"sync"
	"testing"
)

func Example_basics() {
	basics()
	// Output:
	// main.UserID int64
	// 1
	// false "" true
}
func Example_copying() {
	copying()
	// Output:
	// array: [1 2 3]
	// inside: [9]
	// outside: [9 2 3]
}
func Example_lengthAndCapacity() {
	lengthAndCapacity()
	// Output:
	// [0 0] 2 4
	// [0 7] 2 3
	// true false 0 0
	// [5]
}
func Example_sharing() {
	sharing()
	// Output:
	// base: [10 20 99 40]
	// left: [10 20] result: [10 20 99]
	// base: [11 20 99 40]
	// fenced: [11 20] detached: [88 20 77]
	// base: [11 20 99 40] clone: [-1 20 99 40]
	// nested: [[9 2]]
}
func Example_mapBasics() {
	mapBasics()
	// Output:
	// 0 0 false
	// 0 true
	// a 7
	// b 2
	// 7 8
	// 2 0
}
func Example_mapValues() {
	mapValues()
	// Output:
	// 2
	// 2
}
func Example_textUnits() {
	textUnits()
	// Output:
	// 8 3
	// 41 e4 b8 ad f0 9f 99 82
	// 0 U+0041
	// 1 U+4E2D
	// 4 U+1F642
	// false
	// A中🙂 B中🙂 C中🙂
	// A 65
}
func Example_invalidText() {
	invalidText()
	// Output:
	// false
	// 0 U+FFFD
	// 1 U+0041
	// 1 2
	// false
}

func TestRuntimePanics(t *testing.T) {
	tests := []struct {
		name string
		run  func()
	}{
		{"index uses len", func() { s := make([]int, 2, 4); _ = s[2] }},
		{"write nil map", func() { var m map[string]int; m["x"] = 1 }},
		{"slice key in any", func() { m := map[any]int{}; m[[]int{1}] = 1 }},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			defer func() {
				if recover() == nil {
					t.Fatal("expected panic")
				}
			}()
			tc.run()
		})
	}
}

func TestCopyUsesLength(t *testing.T) {
	src := []int{1, 2, 3}
	dst := make([]int, 0, 3)
	if n := copy(dst, src); n != 0 {
		t.Fatalf("copied %d", n)
	}
	dst = dst[:3]
	if n := copy(dst, src); n != 3 || !slices.Equal(dst, src) {
		t.Fatalf("copy: n=%d, dst=%v", n, dst)
	}
	dst[0] = 9
	if src[0] != 1 {
		t.Fatal("copy shares integer storage")
	}
}

func TestMapWithMutex(t *testing.T) {
	m := make(map[string]int)
	var mu sync.Mutex
	var wg sync.WaitGroup
	for range 4 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for range 250 {
				mu.Lock()
				m["n"]++
				mu.Unlock()
			}
		}()
	}
	wg.Wait()
	if m["n"] != 1000 {
		t.Fatalf("got %d", m["n"])
	}
}
