github.com/lrita/cmap@v0.0.0-20231108122212-cb084a67f554/map_test.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package cmap_test
     5  
     6  import (
     7  	"math/rand"
     8  	"runtime"
     9  	"sync"
    10  	"testing"
    11  	"testing/quick"
    12  
    13  	"github.com/lrita/cmap"
    14  )
    15  
    16  type StringMap struct {
    17  	m cmap.Map[string, interface{}]
    18  }
    19  
    20  func (m *StringMap) Load(k interface{}) (interface{}, bool) {
    21  	return m.m.Load(k.(string))
    22  }
    23  
    24  func (m *StringMap) Store(key, value interface{}) {
    25  	m.m.Store(key.(string), value)
    26  }
    27  
    28  func (m *StringMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
    29  	return m.m.LoadOrStore(key.(string), value)
    30  }
    31  
    32  func (m *StringMap) Delete(key interface{}) {
    33  	m.m.Delete(key.(string))
    34  }
    35  
    36  func (m *StringMap) Range(fn func(key, value interface{}) bool) {
    37  	m.m.Range(func(k string, v interface{}) bool {
    38  		return fn(k, v)
    39  	})
    40  }
    41  
    42  func applyGMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    43  	return applyCalls(new(StringMap), calls)
    44  }
    45  
    46  func TestGMapMatchesRWMutex(t *testing.T) {
    47  	if err := quick.CheckEqual(applyGMap, applyRWMutexMap, nil); err != nil {
    48  		t.Error(err)
    49  	}
    50  }
    51  
    52  func TestGMapMatchesDeepCopy(t *testing.T) {
    53  	if err := quick.CheckEqual(applyGMap, applyDeepCopyMap, nil); err != nil {
    54  		t.Error(err)
    55  	}
    56  }
    57  
    58  func TestGMapConcurrentRange(t *testing.T) {
    59  	const mapSize = 1 << 10
    60  
    61  	m := new(cmap.Map[int64, any])
    62  	for n := int64(1); n <= mapSize; n++ {
    63  		m.Store(n, int64(n))
    64  	}
    65  
    66  	done := make(chan struct{})
    67  	var wg sync.WaitGroup
    68  	defer func() {
    69  		close(done)
    70  		wg.Wait()
    71  	}()
    72  	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
    73  		r := rand.New(rand.NewSource(g))
    74  		wg.Add(1)
    75  		go func(g int64) {
    76  			defer wg.Done()
    77  			for i := int64(0); ; i++ {
    78  				select {
    79  				case <-done:
    80  					return
    81  				default:
    82  				}
    83  				for n := int64(1); n < mapSize; n++ {
    84  					if r.Int63n(mapSize) == 0 {
    85  						m.Store(n, n*i*g)
    86  					} else {
    87  						m.Load(n)
    88  					}
    89  				}
    90  			}
    91  		}(g)
    92  	}
    93  
    94  	iters := 1 << 10
    95  	if testing.Short() {
    96  		iters = 16
    97  	}
    98  	for n := iters; n > 0; n-- {
    99  		seen := make(map[int64]bool, mapSize)
   100  
   101  		m.Range(func(ki int64, vi interface{}) bool {
   102  			k, v := ki, vi.(int64)
   103  			if v%k != 0 {
   104  				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   105  			}
   106  			if seen[k] {
   107  				t.Fatalf("Range visited key %v twice", k)
   108  			}
   109  			seen[k] = true
   110  			return true
   111  		})
   112  
   113  		if len(seen) != mapSize {
   114  			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   115  		}
   116  	}
   117  }
   118  
   119  func TestGMapCreation(t *testing.T) {
   120  	m := cmap.Map[int, int]{}
   121  
   122  	if m.Count() != 0 {
   123  		t.Error("new map should be empty.")
   124  	}
   125  	if !m.IsEmpty() {
   126  		t.Error("new map should be empty.")
   127  	}
   128  }
   129  
   130  func TestGMapStoreOperationDuplicatedKey(t *testing.T) {
   131  	m := cmap.Map[string, interface{}]{}
   132  	m.Store("t", "")
   133  	m.Store("t", "")
   134  	if v := m.Count(); v != 1 {
   135  		t.Errorf("map Count() should be %d, got %d", 1, v)
   136  	}
   137  	m.LoadOrStore("m", "")
   138  	if v := m.Count(); v != 2 {
   139  		t.Errorf("map Count() should be %d, got %d", 2, v)
   140  	}
   141  	m.Delete("t")
   142  	if v := m.Count(); v != 1 {
   143  		t.Errorf("map Count() should be %d, got %d", 1, v)
   144  	}
   145  	m.Delete("t")
   146  	if v := m.Count(); v != 1 {
   147  		t.Errorf("map Count() should be %d, got %d", 1, v)
   148  	}
   149  }
   150  
   151  func TestGMapStoreAndLoad(t *testing.T) {
   152  	const mapSize = 1 << 14
   153  
   154  	var (
   155  		m    cmap.Map[int64, interface{}]
   156  		wg   sync.WaitGroup
   157  		seen = make(map[int64]bool, mapSize)
   158  	)
   159  
   160  	for n := int64(1); n <= mapSize; n++ {
   161  		nn := n
   162  		wg.Add(1)
   163  		go func() {
   164  			defer wg.Done()
   165  			m.Store(nn, nn)
   166  		}()
   167  	}
   168  
   169  	wg.Wait()
   170  
   171  	m.Range(func(ki int64, vi interface{}) bool {
   172  		k, v := ki, vi.(int64)
   173  		if v%k != 0 {
   174  			t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   175  		}
   176  		if seen[k] {
   177  			t.Fatalf("Range visited key %v twice", k)
   178  		}
   179  		seen[k] = true
   180  		return true
   181  	})
   182  
   183  	if len(seen) != mapSize {
   184  		t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   185  	}
   186  
   187  	for n := int64(1); n <= mapSize; n++ {
   188  		nn := n
   189  		wg.Add(1)
   190  		go func() {
   191  			defer wg.Done()
   192  			m.Delete(nn)
   193  		}()
   194  	}
   195  
   196  	wg.Wait()
   197  
   198  	if !m.IsEmpty() {
   199  		t.Fatalf("Map should be empty, remained %v", m.Count())
   200  	}
   201  }