set/threadsafeset/set_test.go

138 lines
2.6 KiB
Go
Raw Permalink Normal View History

package threadsafeset
import (
"bufio"
"context"
"math/rand/v2"
"os"
"runtime"
"slices"
"strings"
"sync"
"testing"
"time"
)
var Words = func() []string {
f, err := os.Open("../words")
if err != nil {
panic("error opening ../words: " + err.Error())
}
defer f.Close()
scanner := bufio.NewScanner(f)
results := make([]string, 0)
for scanner.Scan() {
if line := strings.TrimSpace(scanner.Text()); len(line) > 0 {
results = append(results, line)
}
}
if err := scanner.Err(); err != nil {
panic("error from scanner.Err(): " + err.Error())
}
return results
}()
func CloneWords() []string {
results := make([]string, 0, len(Words))
for _, word := range Words {
results = append(results, strings.Clone(word))
}
return results
}
func RandomWord() string {
return Words[rand.IntN(len(Words))]
}
func ContextNotDone(ctx context.Context) bool {
select {
case <-ctx.Done():
return false
default:
return true
}
}
func TestAdd(t *testing.T) {
set := New[string]()
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(t.Context(), time.Second*2)
defer cancel()
for range runtime.NumCPU() * 10 {
wg.Go(func() {
for i := 0; i < len(Words) && ContextNotDone(ctx); i++ {
set.Add(Words[i])
}
})
}
wg.Wait()
}
func TestContains(t *testing.T) {
set := New(Words...)
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(t.Context(), time.Second*2)
defer cancel()
for range runtime.NumCPU() * 10 {
wg.Go(func() {
for i := 0; i < len(Words) && ContextNotDone(ctx); i++ {
if !set.Contains(Words[i]) {
panic("error: " + Words[i] + " not found")
}
}
})
}
wg.Wait()
}
func TestRemove(t *testing.T) {
set := New(Words...)
var wg sync.WaitGroup
for range runtime.NumCPU() * 10 {
wg.Go(func() {
for _, word := range Words {
set.Remove(word)
}
})
}
wg.Wait()
}
func TestSize(t *testing.T) {
set := New[string]()
for index, word := range Words {
if want, got := index, set.Size(); want != got {
t.Fatalf("error: wanted size %d; got %d\n", want, got)
}
set.Add(word)
if want, got := index+1, set.Size(); want != got {
t.Fatalf("error: wanted size %d; got %d\n", want, got)
}
}
}
func TestToSlice(t *testing.T) {
want := CloneWords()
slices.Sort(want)
set := New(Words...)
got := set.ToSlice()
slices.Sort(got)
if !slices.Equal(want, got) {
t.Fatalf("error: mismatched ToSlice() output\n")
}
}
func BenchmarkAdd(b *testing.B) {
set := New[string]()
for b.Loop() {
set.Add(RandomWord())
}
}
func BenchmarkContains(b *testing.B) {
set := New(Words...)
for b.Loop() {
set.Contains(RandomWord())
}
}