github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/cmap/cmap_test.go (about)

     1  package cmap
     2  
     3  import (
     4  	"encoding/json"
     5  	"hash/fnv"
     6  	"sort"
     7  	"strconv"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  type animal struct {
    14  	name string
    15  }
    16  
    17  func TestMapCreation(t *testing.T) {
    18  	m := New()
    19  	if m == nil {
    20  		t.Error("map is null.")
    21  	}
    22  
    23  	if m.Count() != 0 {
    24  		t.Error("new map should be empty.")
    25  	}
    26  }
    27  
    28  func TestInsert(t *testing.T) {
    29  	m := New()
    30  	elephant := animal{"elephant"}
    31  	monkey := animal{"monkey"}
    32  
    33  	m.Set("elephant", elephant)
    34  	m.Set("monkey", monkey)
    35  
    36  	if m.Count() != 2 {
    37  		t.Error("map should contain exactly two elements.")
    38  	}
    39  }
    40  
    41  func TestInsertAbsent(t *testing.T) {
    42  	m := New()
    43  	elephant := animal{"elephant"}
    44  	monkey := animal{"monkey"}
    45  
    46  	m.SetIfAbsent("elephant", elephant)
    47  	if ok := m.SetIfAbsent("elephant", monkey); ok {
    48  		t.Error("map set a new value even the entry is already present")
    49  	}
    50  }
    51  
    52  func TestGet(t *testing.T) {
    53  	m := New()
    54  
    55  	// Get a missing element.
    56  	val, ok := m.Get("Money")
    57  	assert.False(t, ok, "ok should be false when item is missing from map.")
    58  
    59  	if val != nil {
    60  		t.Error("Missing values should return as null.")
    61  	}
    62  
    63  	elephant := animal{"elephant"}
    64  	m.Set("elephant", elephant)
    65  
    66  	// Retrieve inserted element.
    67  	tmp, ok := m.Get("elephant")
    68  	if ok == false {
    69  		t.Error("ok should be true for item stored within the map.")
    70  	}
    71  
    72  	elephant, ok = tmp.(animal) // Type assertion.
    73  	if !ok {
    74  		t.Error("expecting an element, not null.")
    75  	}
    76  
    77  	if elephant.name != "elephant" {
    78  		t.Error("item was modified.")
    79  	}
    80  }
    81  
    82  func TestHas(t *testing.T) {
    83  	m := New()
    84  
    85  	// Get a missing element.
    86  	if m.Has("Money") == true {
    87  		t.Error("element shouldn't exists")
    88  	}
    89  
    90  	elephant := animal{"elephant"}
    91  	m.Set("elephant", elephant)
    92  
    93  	if m.Has("elephant") == false {
    94  		t.Error("element exists, expecting Has to return True.")
    95  	}
    96  }
    97  
    98  func TestRemove(t *testing.T) {
    99  	m := New()
   100  
   101  	monkey := animal{"monkey"}
   102  	m.Set("monkey", monkey)
   103  	m.Del("monkey")
   104  
   105  	if m.Count() != 0 {
   106  		t.Error("Expecting count to be zero once item was removed.")
   107  	}
   108  
   109  	temp, ok := m.Get("monkey")
   110  
   111  	if ok != false {
   112  		t.Error("Expecting ok to be false for missing items.")
   113  	}
   114  
   115  	if temp != nil {
   116  		t.Error("Expecting item to be nil after its removal.")
   117  	}
   118  
   119  	// Remove a none existing element.
   120  	m.Del("noone")
   121  }
   122  
   123  func TestRemoveCb(t *testing.T) {
   124  	m := New()
   125  
   126  	monkey := animal{"monkey"}
   127  	m.Set("monkey", monkey)
   128  	elephant := animal{"elephant"}
   129  	m.Set("elephant", elephant)
   130  
   131  	var (
   132  		mapKey   string
   133  		mapVal   interface{}
   134  		wasFound bool
   135  	)
   136  	cb := func(key string, val interface{}, exists bool) bool {
   137  		mapKey = key
   138  		mapVal = val
   139  		wasFound = exists
   140  
   141  		if animal, ok := val.(animal); ok {
   142  			return animal.name == "monkey"
   143  		}
   144  		return false
   145  	}
   146  
   147  	// Monkey should be removed
   148  	result := m.RemoveCb("monkey", cb)
   149  	if !result {
   150  		t.Errorf("Result was not true")
   151  	}
   152  
   153  	if mapKey != "monkey" {
   154  		t.Error("Wrong key was provided to the callback")
   155  	}
   156  
   157  	if mapVal != monkey {
   158  		t.Errorf("Wrong value was provided to the value")
   159  	}
   160  
   161  	if !wasFound {
   162  		t.Errorf("Key was not found")
   163  	}
   164  
   165  	if m.Has("monkey") {
   166  		t.Errorf("Key was not removed")
   167  	}
   168  
   169  	// Elephant should not be removed
   170  	result = m.RemoveCb("elephant", cb)
   171  	if result {
   172  		t.Errorf("Result was true")
   173  	}
   174  
   175  	if mapKey != "elephant" {
   176  		t.Error("Wrong key was provided to the callback")
   177  	}
   178  
   179  	if mapVal != elephant {
   180  		t.Errorf("Wrong value was provided to the value")
   181  	}
   182  
   183  	if !wasFound {
   184  		t.Errorf("Key was not found")
   185  	}
   186  
   187  	if !m.Has("elephant") {
   188  		t.Errorf("Key was removed")
   189  	}
   190  
   191  	// Unset key should remain unset
   192  	result = m.RemoveCb("horse", cb)
   193  	if result {
   194  		t.Errorf("Result was true")
   195  	}
   196  
   197  	if mapKey != "horse" {
   198  		t.Error("Wrong key was provided to the callback")
   199  	}
   200  
   201  	if mapVal != nil {
   202  		t.Errorf("Wrong value was provided to the value")
   203  	}
   204  
   205  	if wasFound {
   206  		t.Errorf("Key was found")
   207  	}
   208  
   209  	if m.Has("horse") {
   210  		t.Errorf("Key was created")
   211  	}
   212  }
   213  
   214  func TestPop(t *testing.T) {
   215  	m := New()
   216  
   217  	monkey := animal{"monkey"}
   218  	m.Set("monkey", monkey)
   219  
   220  	v, exists := m.Pop("monkey")
   221  
   222  	if !exists {
   223  		t.Error("Pop didn't find a monkey.")
   224  	}
   225  
   226  	m1, ok := v.(animal)
   227  
   228  	if !ok || m1 != monkey {
   229  		t.Error("Pop found something else, but monkey.")
   230  	}
   231  
   232  	v2, exists2 := m.Pop("monkey")
   233  	m1, ok = v2.(animal)
   234  
   235  	if exists2 || ok || m1 == monkey {
   236  		t.Error("Pop keeps finding monkey")
   237  	}
   238  
   239  	if m.Count() != 0 {
   240  		t.Error("Expecting count to be zero once item was Pop'ed.")
   241  	}
   242  
   243  	temp, ok := m.Get("monkey")
   244  
   245  	if ok != false {
   246  		t.Error("Expecting ok to be false for missing items.")
   247  	}
   248  
   249  	if temp != nil {
   250  		t.Error("Expecting item to be nil after its removal.")
   251  	}
   252  }
   253  
   254  func TestCount(t *testing.T) {
   255  	m := New()
   256  	for i := 0; i < 100; i++ {
   257  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   258  	}
   259  
   260  	if m.Count() != 100 {
   261  		t.Error("Expecting 100 element within map.")
   262  	}
   263  }
   264  
   265  func TestIsEmpty(t *testing.T) {
   266  	m := New()
   267  
   268  	if m.IsEmpty() == false {
   269  		t.Error("new map should be empty")
   270  	}
   271  
   272  	m.Set("elephant", animal{"elephant"})
   273  
   274  	if m.IsEmpty() != false {
   275  		t.Error("map shouldn't be empty.")
   276  	}
   277  }
   278  
   279  func TestIterator(t *testing.T) {
   280  	m := New()
   281  
   282  	// Insert 100 elements.
   283  	for i := 0; i < 100; i++ {
   284  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   285  	}
   286  
   287  	counter := 0
   288  	// Iterate over elements.
   289  	for item := range m.Iter() {
   290  		val := item.Val
   291  
   292  		if val == nil {
   293  			t.Error("Expecting an object.")
   294  		}
   295  		counter++
   296  	}
   297  
   298  	if counter != 100 {
   299  		t.Error("We should have counted 100 elements.")
   300  	}
   301  }
   302  
   303  func TestBufferedIterator(t *testing.T) {
   304  	m := New()
   305  
   306  	// Insert 100 elements.
   307  	for i := 0; i < 100; i++ {
   308  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   309  	}
   310  
   311  	counter := 0
   312  	// Iterate over elements.
   313  	for item := range m.Iter() {
   314  		val := item.Val
   315  
   316  		if val == nil {
   317  			t.Error("Expecting an object.")
   318  		}
   319  		counter++
   320  	}
   321  
   322  	if counter != 100 {
   323  		t.Error("We should have counted 100 elements.")
   324  	}
   325  }
   326  
   327  func TestClear(t *testing.T) {
   328  	m := New()
   329  
   330  	// Insert 100 elements.
   331  	for i := 0; i < 100; i++ {
   332  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   333  	}
   334  
   335  	m.Clear()
   336  
   337  	if m.Count() != 0 {
   338  		t.Error("We should have 0 elements.")
   339  	}
   340  }
   341  
   342  func TestIterCb(t *testing.T) {
   343  	m := New()
   344  
   345  	// Insert 100 elements.
   346  	for i := 0; i < 100; i++ {
   347  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   348  	}
   349  
   350  	counter := 0
   351  	// Iterate over elements.
   352  	m.IterCb(func(key string, v interface{}) {
   353  		_, ok := v.(animal)
   354  		if !ok {
   355  			t.Error("Expecting an animal object")
   356  		}
   357  
   358  		counter++
   359  	})
   360  	if counter != 100 {
   361  		t.Error("We should have counted 100 elements.")
   362  	}
   363  }
   364  
   365  func TestItems(t *testing.T) {
   366  	m := New()
   367  
   368  	// Insert 100 elements.
   369  	for i := 0; i < 100; i++ {
   370  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   371  	}
   372  
   373  	items := m.Items()
   374  
   375  	if len(items) != 100 {
   376  		t.Error("We should have counted 100 elements.")
   377  	}
   378  }
   379  
   380  func TestConcurrent(t *testing.T) {
   381  	m := New()
   382  	ch := make(chan int)
   383  	const iterations = 1000
   384  	var a [iterations]int
   385  
   386  	// Using go routines insert 1000 ints into our map.
   387  	go func() {
   388  		for i := 0; i < iterations/2; i++ {
   389  			// Add item to map.
   390  			m.Set(strconv.Itoa(i), i)
   391  
   392  			// Retrieve item from map.
   393  			val, _ := m.Get(strconv.Itoa(i))
   394  
   395  			// Write to channel inserted value.
   396  			ch <- val.(int)
   397  		} // Call go routine with current index.
   398  	}()
   399  
   400  	go func() {
   401  		for i := iterations / 2; i < iterations; i++ {
   402  			// Add item to map.
   403  			m.Set(strconv.Itoa(i), i)
   404  
   405  			// Retrieve item from map.
   406  			val, _ := m.Get(strconv.Itoa(i))
   407  
   408  			// Write to channel inserted value.
   409  			ch <- val.(int)
   410  		} // Call go routine with current index.
   411  	}()
   412  
   413  	// Wait for all go routines to finish.
   414  	counter := 0
   415  	for elem := range ch {
   416  		a[counter] = elem
   417  		counter++
   418  		if counter == iterations {
   419  			break
   420  		}
   421  	}
   422  
   423  	// Sorts array, will make is simpler to verify all inserted values we're returned.
   424  	sort.Ints(a[0:iterations])
   425  
   426  	// Make sure map contains 1000 elements.
   427  	if m.Count() != iterations {
   428  		t.Error("Expecting 1000 elements.")
   429  	}
   430  
   431  	// Make sure all inserted values we're fetched from map.
   432  	for i := 0; i < iterations; i++ {
   433  		if i != a[i] {
   434  			t.Error("missing value", i)
   435  		}
   436  	}
   437  }
   438  
   439  func TestJsonMarshal(t *testing.T) {
   440  	expected := "{\"a\":1,\"b\":2}"
   441  	m := New(WithShardCount(2))
   442  	m.Set("a", 1)
   443  	m.Set("b", 2)
   444  	j, err := json.Marshal(m)
   445  	if err != nil {
   446  		t.Error(err)
   447  	}
   448  
   449  	if string(j) != expected {
   450  		t.Error("json", string(j), "differ from expected", expected)
   451  		return
   452  	}
   453  }
   454  
   455  func TestKeys(t *testing.T) {
   456  	m := New()
   457  
   458  	// Insert 100 elements.
   459  	for i := 0; i < 100; i++ {
   460  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   461  	}
   462  
   463  	keys := m.Keys()
   464  	if len(keys) != 100 {
   465  		t.Error("We should have counted 100 elements.")
   466  	}
   467  }
   468  
   469  func TestMInsert(t *testing.T) {
   470  	animals := map[string]interface{}{
   471  		"elephant": animal{"elephant"},
   472  		"monkey":   animal{"monkey"},
   473  	}
   474  	m := New()
   475  	m.MSet(animals)
   476  
   477  	if m.Count() != 2 {
   478  		t.Error("map should contain exactly two elements.")
   479  	}
   480  }
   481  
   482  func TestFnv32(t *testing.T) {
   483  	key := []byte("ABC")
   484  
   485  	hasher := fnv.New32()
   486  	_, err := hasher.Write(key)
   487  	if err != nil {
   488  		t.Errorf(err.Error())
   489  	}
   490  	if fnv32(string(key)) != hasher.Sum32() {
   491  		t.Errorf("Bundled fnv32 produced %d, expected result from hash/fnv32 is %d", fnv32(string(key)), hasher.Sum32())
   492  	}
   493  }
   494  
   495  func TestUpsert(t *testing.T) {
   496  	dolphin := animal{"dolphin"}
   497  	whale := animal{"whale"}
   498  	tiger := animal{"tiger"}
   499  	lion := animal{"lion"}
   500  
   501  	cb := func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
   502  		nv := newValue.(animal)
   503  		if !exists {
   504  			return []animal{nv}
   505  		}
   506  		res := valueInMap.([]animal)
   507  		return append(res, nv)
   508  	}
   509  
   510  	m := New()
   511  	m.Set("marine", []animal{dolphin})
   512  	m.Upsert("marine", whale, cb)
   513  	m.Upsert("predator", tiger, cb)
   514  	m.Upsert("predator", lion, cb)
   515  
   516  	if m.Count() != 2 {
   517  		t.Error("map should contain exactly two elements.")
   518  	}
   519  
   520  	compare := func(a, b []animal) bool {
   521  		if a == nil || b == nil {
   522  			return false
   523  		}
   524  
   525  		if len(a) != len(b) {
   526  			return false
   527  		}
   528  
   529  		for i, v := range a {
   530  			if v != b[i] {
   531  				return false
   532  			}
   533  		}
   534  		return true
   535  	}
   536  
   537  	marineAnimals, ok := m.Get("marine")
   538  	if !ok || !compare(marineAnimals.([]animal), []animal{dolphin, whale}) {
   539  		t.Error("Set, then Upsert failed")
   540  	}
   541  
   542  	predators, ok := m.Get("predator")
   543  	if !ok || !compare(predators.([]animal), []animal{tiger, lion}) {
   544  		t.Error("Upsert, then Upsert failed")
   545  	}
   546  }
   547  
   548  func TestKeysWhenRemoving(t *testing.T) {
   549  	m := New()
   550  
   551  	// Insert 100 elements.
   552  	Total := 100
   553  	for i := 0; i < Total; i++ {
   554  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   555  	}
   556  
   557  	// Remove 10 elements concurrently.
   558  	Num := 10
   559  	for i := 0; i < Num; i++ {
   560  		go func(c *Map, n int) {
   561  			c.Del(strconv.Itoa(n))
   562  		}(m, i)
   563  	}
   564  	keys := m.Keys()
   565  	for _, k := range keys {
   566  		if k == "" {
   567  			t.Error("Empty keys returned")
   568  		}
   569  	}
   570  }
   571  
   572  func TestUnDrainedIter(t *testing.T) {
   573  	m := New()
   574  	// Insert 100 elements.
   575  	Total := 100
   576  	for i := 0; i < Total; i++ {
   577  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   578  	}
   579  	counter := 0
   580  	// Iterate over elements.
   581  	ch := m.Iter()
   582  	for item := range ch {
   583  		val := item.Val
   584  
   585  		if val == nil {
   586  			t.Error("Expecting an object.")
   587  		}
   588  		counter++
   589  		if counter == 42 {
   590  			break
   591  		}
   592  	}
   593  	for i := Total; i < 2*Total; i++ {
   594  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   595  	}
   596  	for item := range ch {
   597  		val := item.Val
   598  
   599  		if val == nil {
   600  			t.Error("Expecting an object.")
   601  		}
   602  		counter++
   603  	}
   604  
   605  	if counter != 100 {
   606  		t.Error("We should have been right where we stopped")
   607  	}
   608  
   609  	counter = 0
   610  	for item := range m.Iter() {
   611  		val := item.Val
   612  
   613  		if val == nil {
   614  			t.Error("Expecting an object.")
   615  		}
   616  		counter++
   617  	}
   618  
   619  	if counter != 200 {
   620  		t.Error("We should have counted 200 elements.")
   621  	}
   622  }
   623  
   624  func TestUnDrainedIterBuffered(t *testing.T) {
   625  	m := New()
   626  	// Insert 100 elements.
   627  	Total := 100
   628  	for i := 0; i < Total; i++ {
   629  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   630  	}
   631  	counter := 0
   632  	// Iterate over elements.
   633  	ch := m.Iter()
   634  	for item := range ch {
   635  		val := item.Val
   636  
   637  		if val == nil {
   638  			t.Error("Expecting an object.")
   639  		}
   640  		counter++
   641  		if counter == 42 {
   642  			break
   643  		}
   644  	}
   645  	for i := Total; i < 2*Total; i++ {
   646  		m.Set(strconv.Itoa(i), animal{strconv.Itoa(i)})
   647  	}
   648  	for item := range ch {
   649  		val := item.Val
   650  
   651  		if val == nil {
   652  			t.Error("Expecting an object.")
   653  		}
   654  		counter++
   655  	}
   656  
   657  	if counter != 100 {
   658  		t.Error("We should have been right where we stopped")
   659  	}
   660  
   661  	counter = 0
   662  	for item := range m.Iter() {
   663  		val := item.Val
   664  
   665  		if val == nil {
   666  			t.Error("Expecting an object.")
   667  		}
   668  		counter++
   669  	}
   670  
   671  	if counter != 200 {
   672  		t.Error("We should have counted 200 elements.")
   673  	}
   674  }