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

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cmap_test
     6  
     7  import (
     8  	"math/rand"
     9  	"reflect"
    10  	"runtime"
    11  	"sync"
    12  	"testing"
    13  	"testing/quick"
    14  
    15  	"github.com/lrita/cmap"
    16  )
    17  
    18  type mapOp string
    19  
    20  const (
    21  	opLoad        = mapOp("Load")
    22  	opStore       = mapOp("Store")
    23  	opLoadOrStore = mapOp("LoadOrStore")
    24  	opDelete      = mapOp("Delete")
    25  )
    26  
    27  var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opDelete}
    28  
    29  // mapCall is a quick.Generator for calls on mapInterface.
    30  type mapCall struct {
    31  	op   mapOp
    32  	k, v interface{}
    33  }
    34  
    35  func (c mapCall) apply(m mapInterface) (interface{}, bool) {
    36  	switch c.op {
    37  	case opLoad:
    38  		return m.Load(c.k)
    39  	case opStore:
    40  		m.Store(c.k, c.v)
    41  		return nil, false
    42  	case opLoadOrStore:
    43  		return m.LoadOrStore(c.k, c.v)
    44  	case opDelete:
    45  		m.Delete(c.k)
    46  		return nil, false
    47  	default:
    48  		panic("invalid mapOp")
    49  	}
    50  }
    51  
    52  type mapResult struct {
    53  	value interface{}
    54  	ok    bool
    55  }
    56  
    57  func randValue(r *rand.Rand) interface{} {
    58  	b := make([]byte, r.Intn(4))
    59  	for i := range b {
    60  		b[i] = 'a' + byte(rand.Intn(26))
    61  	}
    62  	return string(b)
    63  }
    64  
    65  func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
    66  	c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)}
    67  	switch c.op {
    68  	case opStore, opLoadOrStore:
    69  		c.v = randValue(r)
    70  	}
    71  	return reflect.ValueOf(c)
    72  }
    73  
    74  func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
    75  	for _, c := range calls {
    76  		v, ok := c.apply(m)
    77  		results = append(results, mapResult{v, ok})
    78  	}
    79  
    80  	final = make(map[interface{}]interface{})
    81  	m.Range(func(k, v interface{}) bool {
    82  		final[k] = v
    83  		return true
    84  	})
    85  
    86  	return results, final
    87  }
    88  
    89  func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    90  	return applyCalls(new(cmap.Cmap), calls)
    91  }
    92  
    93  func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    94  	return applyCalls(new(RWMutexMap), calls)
    95  }
    96  
    97  func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    98  	return applyCalls(new(DeepCopyMap), calls)
    99  }
   100  
   101  func TestMapMatchesRWMutex(t *testing.T) {
   102  	if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
   103  		t.Error(err)
   104  	}
   105  }
   106  
   107  func TestMapMatchesDeepCopy(t *testing.T) {
   108  	if err := quick.CheckEqual(applyMap, applyDeepCopyMap, nil); err != nil {
   109  		t.Error(err)
   110  	}
   111  }
   112  
   113  func TestConcurrentRange(t *testing.T) {
   114  	const mapSize = 1 << 10
   115  
   116  	m := new(cmap.Cmap)
   117  	for n := int64(1); n <= mapSize; n++ {
   118  		m.Store(n, int64(n))
   119  	}
   120  
   121  	done := make(chan struct{})
   122  	var wg sync.WaitGroup
   123  	defer func() {
   124  		close(done)
   125  		wg.Wait()
   126  	}()
   127  	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
   128  		r := rand.New(rand.NewSource(g))
   129  		wg.Add(1)
   130  		go func(g int64) {
   131  			defer wg.Done()
   132  			for i := int64(0); ; i++ {
   133  				select {
   134  				case <-done:
   135  					return
   136  				default:
   137  				}
   138  				for n := int64(1); n < mapSize; n++ {
   139  					if r.Int63n(mapSize) == 0 {
   140  						m.Store(n, n*i*g)
   141  					} else {
   142  						m.Load(n)
   143  					}
   144  				}
   145  			}
   146  		}(g)
   147  	}
   148  
   149  	iters := 1 << 10
   150  	if testing.Short() {
   151  		iters = 16
   152  	}
   153  	for n := iters; n > 0; n-- {
   154  		seen := make(map[int64]bool, mapSize)
   155  
   156  		m.Range(func(ki, vi interface{}) bool {
   157  			k, v := ki.(int64), vi.(int64)
   158  			if v%k != 0 {
   159  				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   160  			}
   161  			if seen[k] {
   162  				t.Fatalf("Range visited key %v twice", k)
   163  			}
   164  			seen[k] = true
   165  			return true
   166  		})
   167  
   168  		if len(seen) != mapSize {
   169  			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   170  		}
   171  	}
   172  }
   173  
   174  func TestMapCreation(t *testing.T) {
   175  	m := cmap.Cmap{}
   176  
   177  	if m.Count() != 0 {
   178  		t.Error("new map should be empty.")
   179  	}
   180  	if !m.IsEmpty() {
   181  		t.Error("new map should be empty.")
   182  	}
   183  }
   184  
   185  func TestStoreOperationDuplicatedKey(t *testing.T) {
   186  	m := cmap.Cmap{}
   187  	m.Store(t, "")
   188  	m.Store(t, "")
   189  	if v := m.Count(); v != 1 {
   190  		t.Errorf("map Count() should be %d, got %d", 1, v)
   191  	}
   192  	m.LoadOrStore("m", "")
   193  	if v := m.Count(); v != 2 {
   194  		t.Errorf("map Count() should be %d, got %d", 2, v)
   195  	}
   196  	m.Delete(t)
   197  	if v := m.Count(); v != 1 {
   198  		t.Errorf("map Count() should be %d, got %d", 1, v)
   199  	}
   200  	m.Delete(t)
   201  	if v := m.Count(); v != 1 {
   202  		t.Errorf("map Count() should be %d, got %d", 1, v)
   203  	}
   204  }
   205  
   206  func TestMapStoreAndLoad(t *testing.T) {
   207  	const mapSize = 1 << 14
   208  
   209  	var (
   210  		m    cmap.Cmap
   211  		wg   sync.WaitGroup
   212  		seen = make(map[int64]bool, mapSize)
   213  	)
   214  
   215  	for n := int64(1); n <= mapSize; n++ {
   216  		nn := n
   217  		wg.Add(1)
   218  		go func() {
   219  			defer wg.Done()
   220  			m.Store(nn, nn)
   221  		}()
   222  	}
   223  
   224  	wg.Wait()
   225  
   226  	m.Range(func(ki, vi interface{}) bool {
   227  		k, v := ki.(int64), vi.(int64)
   228  		if v%k != 0 {
   229  			t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   230  		}
   231  		if seen[k] {
   232  			t.Fatalf("Range visited key %v twice", k)
   233  		}
   234  		seen[k] = true
   235  		return true
   236  	})
   237  
   238  	if len(seen) != mapSize {
   239  		t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   240  	}
   241  
   242  	for n := int64(1); n <= mapSize; n++ {
   243  		nn := n
   244  		wg.Add(1)
   245  		go func() {
   246  			defer wg.Done()
   247  			m.Delete(nn)
   248  		}()
   249  	}
   250  
   251  	wg.Wait()
   252  
   253  	if !m.IsEmpty() {
   254  		t.Fatalf("Map should be empty, remained %v", m.Count())
   255  	}
   256  }