github.com/min1324/cmap@v1.0.3-0.20220418125848-74e72bbe3be4/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  	"sync/atomic"
    13  	"testing"
    14  	"testing/quick"
    15  
    16  	"github.com/min1324/cmap"
    17  )
    18  
    19  type mapOp string
    20  
    21  const (
    22  	opLoad          = mapOp("Load")
    23  	opStore         = mapOp("Store")
    24  	opLoadOrStore   = mapOp("LoadOrStore")
    25  	opLoadAndDelete = mapOp("LoadAndDelete")
    26  	opDelete        = mapOp("Delete")
    27  )
    28  
    29  var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opLoadAndDelete, opDelete}
    30  
    31  // mapCall is a quick.Generator for calls on mapInterface.
    32  type mapCall struct {
    33  	op   mapOp
    34  	k, v interface{}
    35  }
    36  
    37  func (c mapCall) apply(m mapInterface) (interface{}, bool) {
    38  	switch c.op {
    39  	case opLoad:
    40  		return m.Load(c.k)
    41  	case opStore:
    42  		m.Store(c.k, c.v)
    43  		return nil, false
    44  	case opLoadOrStore:
    45  		return m.LoadOrStore(c.k, c.v)
    46  	case opLoadAndDelete:
    47  		return m.LoadAndDelete(c.k)
    48  	case opDelete:
    49  		m.Delete(c.k)
    50  		return nil, false
    51  	default:
    52  		panic("invalid mapOp")
    53  	}
    54  }
    55  
    56  type mapResult struct {
    57  	value interface{}
    58  	ok    bool
    59  }
    60  
    61  func randValue(r *rand.Rand) interface{} {
    62  	b := make([]byte, r.Intn(4))
    63  	for i := range b {
    64  		b[i] = 'a' + byte(rand.Intn(26))
    65  	}
    66  	return string(b)
    67  }
    68  
    69  func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
    70  	c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)}
    71  	switch c.op {
    72  	case opStore, opLoadOrStore:
    73  		c.v = randValue(r)
    74  	}
    75  	return reflect.ValueOf(c)
    76  }
    77  
    78  func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
    79  	for _, c := range calls {
    80  		v, ok := c.apply(m)
    81  		results = append(results, mapResult{v, ok})
    82  	}
    83  
    84  	final = make(map[interface{}]interface{})
    85  	m.Range(func(k, v interface{}) bool {
    86  		final[k] = v
    87  		return true
    88  	})
    89  
    90  	return results, final
    91  }
    92  
    93  func applyCMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    94  	return applyCalls(new(cmap.CMap), calls)
    95  }
    96  
    97  func applyFMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    98  	return applyCalls(new(cmap.FMap), calls)
    99  }
   100  
   101  func applySyncMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
   102  	return applyCalls(new(cmap.Map), calls)
   103  }
   104  
   105  func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
   106  	return applyCalls(new(RWMutexMap), calls)
   107  }
   108  
   109  func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
   110  	return applyCalls(new(DeepCopyMap), calls)
   111  }
   112  
   113  func TestMapEvacute(t *testing.T) {
   114  	var m cmap.CMap
   115  	for i := 0; i < 1<<20; i++ {
   116  		m.Store(i, i)
   117  	}
   118  	v, ok := m.Load(1 << 15)
   119  	if !ok || v != 1<<15 {
   120  		t.Errorf("i!=15")
   121  	}
   122  	if m.Count() != 1<<20 {
   123  		t.Errorf("Count!=1<<20")
   124  	}
   125  }
   126  
   127  func TestMapMatchesSync(t *testing.T) {
   128  	if err := quick.CheckEqual(applyCMap, applySyncMap, nil); err != nil {
   129  		t.Error(err)
   130  	}
   131  }
   132  
   133  func TestFMapMatchesSync(t *testing.T) {
   134  	if err := quick.CheckEqual(applyFMap, applyRWMutexMap, nil); err != nil {
   135  		t.Error(err)
   136  	}
   137  }
   138  
   139  func TestMapMatchesRWMutex(t *testing.T) {
   140  	if err := quick.CheckEqual(applyCMap, applyRWMutexMap, nil); err != nil {
   141  		t.Error(err)
   142  	}
   143  }
   144  
   145  func TestMapMatchesDeepCopy(t *testing.T) {
   146  	if err := quick.CheckEqual(applyCMap, applyDeepCopyMap, nil); err != nil {
   147  		t.Error(err)
   148  	}
   149  }
   150  
   151  func TestConcurrentRange(t *testing.T) {
   152  	const mapSize = 1 << 10
   153  
   154  	m := new(cmap.CMap)
   155  	for n := int64(1); n <= mapSize; n++ {
   156  		m.Store(n, int64(n))
   157  	}
   158  
   159  	done := make(chan struct{})
   160  	var wg sync.WaitGroup
   161  	defer func() {
   162  		close(done)
   163  		wg.Wait()
   164  	}()
   165  	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
   166  		r := rand.New(rand.NewSource(g))
   167  		wg.Add(1)
   168  		go func(g int64) {
   169  			defer wg.Done()
   170  			for i := int64(0); ; i++ {
   171  				select {
   172  				case <-done:
   173  					return
   174  				default:
   175  				}
   176  				for n := int64(1); n < mapSize; n++ {
   177  					if r.Int63n(mapSize) == 0 {
   178  						m.Store(n, n*i*g)
   179  					} else {
   180  						m.Load(n)
   181  					}
   182  				}
   183  			}
   184  		}(g)
   185  	}
   186  
   187  	iters := 1 << 10
   188  	if testing.Short() {
   189  		iters = 16
   190  	}
   191  	for n := iters; n > 0; n-- {
   192  		seen := make(map[int64]bool, mapSize)
   193  
   194  		m.Range(func(ki, vi interface{}) bool {
   195  			k, v := ki.(int64), vi.(int64)
   196  			if v%k != 0 {
   197  				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   198  			}
   199  			if seen[k] {
   200  				t.Fatalf("Range visited key %v twice", k)
   201  			}
   202  			seen[k] = true
   203  			return true
   204  		})
   205  
   206  		if len(seen) != mapSize {
   207  			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   208  		}
   209  	}
   210  }
   211  
   212  func TestIssue40999(t *testing.T) {
   213  	var m cmap.CMap
   214  
   215  	// Since the miss-counting in missLocked (via Delete)
   216  	// compares the miss count with len(m.dirty),
   217  	// add an initial entry to bias len(m.dirty) above the miss count.
   218  	m.Store(nil, struct{}{})
   219  
   220  	var finalized uint32
   221  
   222  	// Set finalizers that count for collected keys. A non-zero count
   223  	// indicates that keys have not been leaked.
   224  	for atomic.LoadUint32(&finalized) == 0 {
   225  		p := new(int)
   226  		runtime.SetFinalizer(p, func(*int) {
   227  			atomic.AddUint32(&finalized, 1)
   228  		})
   229  		m.Store(p, struct{}{})
   230  		m.Delete(p)
   231  		runtime.GC()
   232  	}
   233  }
   234  
   235  func TestMapStoreAndLoad(t *testing.T) {
   236  	const mapSize = 1 << 14
   237  
   238  	var (
   239  		m    cmap.CMap
   240  		wg   sync.WaitGroup
   241  		seen = make(map[int64]bool, mapSize)
   242  	)
   243  
   244  	for n := int64(1); n <= mapSize; n++ {
   245  		nn := n
   246  		wg.Add(1)
   247  		go func() {
   248  			defer wg.Done()
   249  			m.Store(nn, nn)
   250  		}()
   251  	}
   252  
   253  	wg.Wait()
   254  
   255  	m.Range(func(ki, vi interface{}) bool {
   256  		k, v := ki.(int64), vi.(int64)
   257  		if v%k != 0 {
   258  			t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   259  		}
   260  		if seen[k] {
   261  			t.Fatalf("Range visited key %v twice", k)
   262  		}
   263  		seen[k] = true
   264  		return true
   265  	})
   266  
   267  	if len(seen) != mapSize {
   268  		t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   269  	}
   270  
   271  	for n := int64(1); n <= mapSize; n++ {
   272  		nn := n
   273  		wg.Add(1)
   274  		go func() {
   275  			defer wg.Done()
   276  			m.Delete(nn)
   277  		}()
   278  	}
   279  
   280  	wg.Wait()
   281  
   282  	m.Range(func(key, value interface{}) bool {
   283  		t.Fatalf("Map should be empty")
   284  		return false
   285  	})
   286  }
   287  
   288  func TestCount(t *testing.T) {
   289  	const want = 1025
   290  	tests := []struct {
   291  		name string
   292  		m    cmap.Interface
   293  		want int
   294  	}{
   295  		// TODO: Add test cases.
   296  		{
   297  			"fmap",
   298  			&cmap.FMap{},
   299  			want,
   300  		},
   301  		{
   302  			"cmap",
   303  			&cmap.CMap{},
   304  			want,
   305  		},
   306  		{
   307  			"map",
   308  			&cmap.Map{},
   309  			want,
   310  		},
   311  	}
   312  	for _, tt := range tests {
   313  		for i := 0; i < tt.want; i++ {
   314  			tt.m.Store(i, i)
   315  		}
   316  		t.Run(tt.name, func(t *testing.T) {
   317  
   318  			if got := tt.m.Count(); int(got) != tt.want {
   319  				t.Errorf("Count() = %v, want %v", got, tt.want)
   320  			}
   321  		})
   322  	}
   323  }