github.com/searKing/golang/go@v1.2.117/exp/container/lru/lru_test.go (about)

     1  // Copyright 2022 The searKing Author. 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 lru_test
     6  
     7  import (
     8  	"slices"
     9  	"testing"
    10  
    11  	"github.com/searKing/golang/go/exp/container/lru"
    12  )
    13  
    14  func TestLRU(t *testing.T) {
    15  	evictCounter := 0
    16  	onEvicted := func(k int, v int) {
    17  		if k != v {
    18  			t.Fatalf("Evict values not equal (%v!=%v)", k, v)
    19  		}
    20  		evictCounter++
    21  	}
    22  	l := lru.New[int, int](128)
    23  	l.SetEvictCallback(onEvicted)
    24  
    25  	for i := 0; i < 256; i++ {
    26  		if i%2 == 0 {
    27  			l.Store(i, i)
    28  			continue
    29  		}
    30  		l.Add(i, i)
    31  	}
    32  	if l.Len() != 128 {
    33  		t.Fatalf("bad len: %v", l.Len())
    34  	}
    35  
    36  	if evictCounter != 128 {
    37  		t.Fatalf("bad evict count: %v", evictCounter)
    38  	}
    39  
    40  	for i, k := range l.Keys() {
    41  		if v, ok := l.Get(k); !ok || v != k || v != i+128 {
    42  			t.Fatalf("bad key: %v", k)
    43  		}
    44  	}
    45  	for i := 0; i < 128; i++ {
    46  		_, ok := l.Get(i)
    47  		if ok {
    48  			t.Fatalf("should be evicted")
    49  		}
    50  	}
    51  	for i := 128; i < 256; i++ {
    52  		_, ok := l.Get(i)
    53  		if !ok {
    54  			t.Fatalf("should not be evicted")
    55  		}
    56  	}
    57  	for i := 128; i < 192; i++ {
    58  		v, ok := l.LoadAndDelete(i)
    59  		if !ok {
    60  			t.Fatalf("should be contained")
    61  		}
    62  		if v != i {
    63  			t.Fatalf("bad key: %v", i)
    64  		}
    65  		ok = l.Remove(i)
    66  		if ok {
    67  			t.Fatalf("should not be contained")
    68  		}
    69  		_, ok = l.Get(i)
    70  		if ok {
    71  			t.Fatalf("should be deleted")
    72  		}
    73  	}
    74  
    75  	l.Get(192) // expect 192 to be last key in l.Keys()
    76  
    77  	for i, k := range l.Keys() {
    78  		if (i < 63 && k != i+193) || (i == 63 && k != 192) {
    79  			t.Fatalf("out of order key: %v", k)
    80  		}
    81  	}
    82  
    83  	l.Purge()
    84  	if l.Len() != 0 {
    85  		t.Fatalf("bad len: %v", l.Len())
    86  	}
    87  	if _, ok := l.Get(200); ok {
    88  		t.Fatalf("should contain nothing")
    89  	}
    90  }
    91  
    92  // Test that Resize can upsize and downsize
    93  func TestLRU_Resize(t *testing.T) {
    94  	onEvictCounter := 0
    95  	onEvicted := func(k int, v int) { onEvictCounter++ }
    96  
    97  	l := lru.New[int, int](2).SetEvictCallback(onEvicted)
    98  
    99  	// Downsize
   100  	l.Add(1, 1)
   101  	l.Add(2, 2)
   102  	evicted := l.Resize(1)
   103  	if evicted != 1 {
   104  		t.Errorf("1 element should have been evicted: %v", evicted)
   105  	}
   106  	if onEvictCounter != 1 {
   107  		t.Errorf("onEvicted should have been called 1 time: %v", onEvictCounter)
   108  	}
   109  
   110  	l.Add(3, 3)
   111  	if l.Contains(1) {
   112  		t.Errorf("Element 1 should have been evicted")
   113  	}
   114  
   115  	// Upsize
   116  	evicted = l.Resize(2)
   117  	if evicted != 0 {
   118  		t.Errorf("0 elements should have been evicted: %v", evicted)
   119  	}
   120  
   121  	l.Add(4, 4)
   122  	if !l.Contains(3) || !l.Contains(4) {
   123  		t.Errorf("Cache should have contained 2 elements")
   124  	}
   125  }
   126  
   127  // Test that Contains doesn't update recent-ness
   128  func TestLRU_Contains(t *testing.T) {
   129  	l := lru.New[int, int](2)
   130  
   131  	l.Add(1, 1)
   132  	l.Add(2, 2)
   133  	if !l.Contains(1) {
   134  		t.Errorf("1 should be contained")
   135  	}
   136  
   137  	l.Add(3, 3)
   138  	if l.Contains(1) {
   139  		t.Errorf("Contains should not have updated recent-ness of 1")
   140  	}
   141  }
   142  
   143  // Test that Peek doesn't update recent-ness
   144  func TestLRU_Peek(t *testing.T) {
   145  	l := lru.New[int, int](2)
   146  
   147  	l.Add(1, 1)
   148  	l.Add(2, 2)
   149  	if v, ok := l.Peek(1); !ok || v != 1 {
   150  		t.Errorf("1 should be set to 1: %v, %v", v, ok)
   151  	}
   152  
   153  	l.Add(3, 3)
   154  	if l.Contains(1) {
   155  		t.Errorf("should not have updated recent-ness of 1")
   156  	}
   157  }
   158  
   159  // Test that Add returns true/false if an eviction occurred
   160  func TestLRU_Add(t *testing.T) {
   161  	evictCounter := 0
   162  	onEvicted := func(k int, v int) { evictCounter++ }
   163  
   164  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   165  
   166  	if l.Add(1, 1) == true || evictCounter != 0 {
   167  		t.Errorf("should not have an eviction")
   168  	}
   169  	if l.Add(1, -1) == true || evictCounter != 0 {
   170  		t.Errorf("should not have an eviction")
   171  	}
   172  	if l.Add(2, 2) == false || evictCounter != 1 {
   173  		t.Errorf("should have an eviction")
   174  	}
   175  }
   176  
   177  func TestLRU_Store(t *testing.T) {
   178  	evictCounter := 0
   179  	onEvicted := func(k int, v int) { evictCounter++ }
   180  
   181  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   182  
   183  	l.Store(1, 1)
   184  	if l.Len() != 1 || evictCounter != 0 {
   185  		t.Errorf("should not have an eviction")
   186  	}
   187  	l.Store(1, -1)
   188  	if l.Len() != 1 || evictCounter != 0 {
   189  		t.Errorf("should not have an eviction")
   190  	}
   191  	l.Store(2, 2)
   192  	if l.Len() != 1 || evictCounter != 1 {
   193  		t.Errorf("should have an eviction")
   194  	}
   195  }
   196  
   197  func TestLRU_LoadOrStore(t *testing.T) {
   198  	evictCounter := 0
   199  	onEvicted := func(k int, v int) { evictCounter++ }
   200  
   201  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   202  
   203  	{
   204  		_, loaded := l.LoadOrStore(1, 1)
   205  		if loaded {
   206  			t.Errorf("should not loaded")
   207  		}
   208  		if evictCounter != 0 {
   209  			t.Errorf("should not have an eviction")
   210  		}
   211  	}
   212  	{
   213  		old, loaded := l.LoadOrStore(1, -1)
   214  		if !loaded {
   215  			t.Errorf("should loaded")
   216  		}
   217  		if old != 1 {
   218  			t.Errorf("should load old value 1")
   219  		}
   220  		if evictCounter != 0 {
   221  			t.Errorf("should not have an eviction")
   222  		}
   223  	}
   224  
   225  	{
   226  		_, loaded := l.LoadOrStore(2, 2)
   227  		if loaded {
   228  			t.Errorf("should not loaded")
   229  		}
   230  		if evictCounter != 1 {
   231  			t.Errorf("should not have an eviction")
   232  		}
   233  	}
   234  }
   235  
   236  func TestLRU_LoadAndDelete(t *testing.T) {
   237  	evictCounter := 0
   238  	onEvicted := func(k int, v int) { evictCounter++ }
   239  
   240  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   241  	l.Add(1, 1)
   242  	l.Add(2, 2)
   243  
   244  	{
   245  		_, loaded := l.LoadAndDelete(-1)
   246  		if loaded {
   247  			t.Errorf("should not loaded")
   248  		}
   249  	}
   250  	{
   251  		_, loaded := l.LoadAndDelete(1)
   252  		if loaded {
   253  			t.Errorf("should not loaded")
   254  		}
   255  	}
   256  
   257  	{
   258  		old, loaded := l.LoadAndDelete(2)
   259  		if !loaded {
   260  			t.Errorf("should not loaded")
   261  		}
   262  		if old != 2 {
   263  			t.Errorf("should load old value 2")
   264  		}
   265  	}
   266  }
   267  
   268  func TestLRU_Delete(t *testing.T) {
   269  	evictCounter := 0
   270  	onEvicted := func(k int, v int) { evictCounter++ }
   271  
   272  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   273  	l.Add(1, 1)
   274  	l.Add(2, 2)
   275  
   276  	{
   277  		l.Delete(-1)
   278  		if l.Len() != 1 {
   279  			t.Errorf("should not deleted")
   280  		}
   281  	}
   282  	{
   283  		l.Delete(1)
   284  		if l.Len() != 1 {
   285  			t.Errorf("should not deleted")
   286  		}
   287  	}
   288  	{
   289  		l.Delete(2)
   290  		if l.Len() != 0 {
   291  			t.Errorf("should not deleted")
   292  		}
   293  	}
   294  }
   295  
   296  func TestLRU_Remove(t *testing.T) {
   297  	evictCounter := 0
   298  	onEvicted := func(k int, v int) { evictCounter++ }
   299  
   300  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   301  	l.Add(1, 1)
   302  	l.Add(2, 2)
   303  
   304  	{
   305  		loaded := l.Remove(-1)
   306  		if loaded {
   307  			t.Errorf("should not loaded")
   308  		}
   309  	}
   310  	{
   311  		loaded := l.Remove(1)
   312  		if loaded {
   313  			t.Errorf("should not loaded")
   314  		}
   315  	}
   316  
   317  	{
   318  		loaded := l.Remove(2)
   319  		if !loaded {
   320  			t.Errorf("should not loaded")
   321  		}
   322  	}
   323  }
   324  
   325  func TestLRU_Swap(t *testing.T) {
   326  	evictCounter := 0
   327  	onEvicted := func(k int, v int) { evictCounter++ }
   328  
   329  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   330  
   331  	if _, loaded := l.Swap(1, 1); loaded == true || evictCounter != 0 {
   332  		t.Errorf("should not have an eviction")
   333  	}
   334  	if pre, loaded := l.Swap(1, -1); loaded == false || pre != 1 || evictCounter != 0 {
   335  		t.Errorf("should not have an eviction")
   336  	}
   337  	if _, loaded := l.Swap(2, 2); loaded == true || evictCounter != 1 {
   338  		t.Errorf("should have an eviction")
   339  	}
   340  }
   341  
   342  func TestLRU_CompareAndSwap(t *testing.T) {
   343  	evictCounter := 0
   344  	onEvicted := func(k int, v int) { evictCounter++ }
   345  
   346  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   347  	l.Add(1, 1)
   348  	l.Add(2, 2)
   349  
   350  	if swapped := l.CompareAndSwap(-1, -1, -2); swapped {
   351  		t.Errorf("should not swapped")
   352  	}
   353  	if swapped := l.CompareAndSwap(1, 1, -1); swapped {
   354  		t.Errorf("should not swapped")
   355  	}
   356  	if swapped := l.CompareAndSwap(2, -2, 2); swapped {
   357  		t.Errorf("should not swapped")
   358  	}
   359  	if swapped := l.CompareAndSwap(2, 2, -2); !swapped {
   360  		t.Errorf("should swapped")
   361  	} else {
   362  		if val, ok := l.Peek(2); !ok || val != -2 {
   363  			t.Errorf("should swapped with value -2")
   364  		}
   365  	}
   366  }
   367  
   368  func TestLRU_CompareAndDelete(t *testing.T) {
   369  	evictCounter := 0
   370  	onEvicted := func(k int, v int) { evictCounter++ }
   371  
   372  	l := lru.New[int, int](1).SetEvictCallback(onEvicted)
   373  	l.Add(1, 1)
   374  	l.Add(2, 2)
   375  
   376  	if deleted := l.CompareAndDelete(-1, -1); deleted {
   377  		t.Errorf("should not deleted")
   378  	}
   379  	if deleted := l.CompareAndDelete(1, 1); deleted {
   380  		t.Errorf("should not deleted")
   381  	}
   382  	if deleted := l.CompareAndDelete(2, -2); deleted {
   383  		t.Errorf("should not deleted")
   384  	}
   385  	if deleted := l.CompareAndDelete(2, 2); !deleted {
   386  		t.Errorf("should deleted")
   387  	} else {
   388  		if l.Len() != 0 {
   389  			t.Errorf("should empty")
   390  		}
   391  	}
   392  }
   393  
   394  func TestLRU_Keys(t *testing.T) {
   395  	evictCounter := 0
   396  	onEvicted := func(k int, v int) { evictCounter++ }
   397  
   398  	l := lru.New[int, int](2).SetEvictCallback(onEvicted)
   399  	l.Add(1, 1)
   400  	l.Add(2, 2)
   401  	l.Add(3, 3)
   402  
   403  	if !slices.Equal(l.Keys(), []int{2, 3}) {
   404  		t.Fatalf("bad key order: %v", l.Keys())
   405  	}
   406  }
   407  
   408  func TestLRU_Range(t *testing.T) {
   409  	evictCounter := 0
   410  	onEvicted := func(k int, v int) { evictCounter++ }
   411  
   412  	l := lru.New[int, int](2).SetEvictCallback(onEvicted)
   413  	l.Add(1, 1)
   414  	l.Add(2, 2)
   415  	l.Add(3, 3)
   416  
   417  	var keys, vals []int
   418  	l.Range(func(key int, value int) bool {
   419  		keys = append(keys, key)
   420  		vals = append(vals, value)
   421  		return true
   422  	})
   423  
   424  	if !slices.Equal(l.Keys(), keys) {
   425  		t.Fatalf("bad key order: %v", l.Keys())
   426  	}
   427  	if !slices.Equal(keys, vals) {
   428  		t.Fatalf("mismatched kv pairs: %v:%v", keys, vals)
   429  	}
   430  }
   431  
   432  func TestLRU_GetOldest(t *testing.T) {
   433  	l := lru.New[int, int](128)
   434  
   435  	for i := 0; i < 256; i++ {
   436  		l.Add(i, i)
   437  	}
   438  	k, _, ok := l.GetOldest()
   439  	if !ok {
   440  		t.Fatalf("missing")
   441  	}
   442  	if k != 128 {
   443  		t.Fatalf("bad: %v", k)
   444  	}
   445  }
   446  
   447  func TestLRU_GetOldest_RemoveOldest(t *testing.T) {
   448  	l := lru.New[int, int](128)
   449  
   450  	for i := 0; i < 256; i++ {
   451  		l.Add(i, i)
   452  	}
   453  	k, _, ok := l.GetOldest()
   454  	if !ok {
   455  		t.Fatalf("missing")
   456  	}
   457  	if k != 128 {
   458  		t.Fatalf("bad: %v", k)
   459  	}
   460  
   461  	k, _, ok = l.RemoveOldest()
   462  	if !ok {
   463  		t.Fatalf("missing")
   464  	}
   465  	if k != 128 {
   466  		t.Fatalf("bad: %v", k)
   467  	}
   468  
   469  	k, _, ok = l.RemoveOldest()
   470  	if !ok {
   471  		t.Fatalf("missing")
   472  	}
   473  	if k != 129 {
   474  		t.Fatalf("bad: %v", k)
   475  	}
   476  }
   477  
   478  func TestLRU_PeekAndDeleteOldest(t *testing.T) {
   479  	l := lru.New[int, int](128)
   480  
   481  	for i := 0; i < 256; i++ {
   482  		l.Add(i, i)
   483  	}
   484  	k, _, ok := l.PeekOldest()
   485  	if !ok {
   486  		t.Fatalf("missing")
   487  	}
   488  	if k != 128 {
   489  		t.Fatalf("bad: %v", k)
   490  	}
   491  
   492  	k, v, ok := l.PeekAndDeleteOldest()
   493  	if !ok {
   494  		t.Fatalf("missing")
   495  	}
   496  	if k != 128 {
   497  		t.Fatalf("bad key: %v", k)
   498  	}
   499  	if v != 128 {
   500  		t.Fatalf("bad value: %v", k)
   501  	}
   502  
   503  	k, _, ok = l.PeekAndDeleteOldest()
   504  	if !ok {
   505  		t.Fatalf("missing")
   506  	}
   507  	if k != 129 {
   508  		t.Fatalf("bad: %v", k)
   509  	}
   510  }
   511  
   512  func TestLRU_RemoveOldest(t *testing.T) {
   513  	l := lru.New[int, int](128)
   514  
   515  	for i := 0; i < 256; i++ {
   516  		l.Add(i, i)
   517  	}
   518  	k, _, ok := l.GetOldest()
   519  	if !ok {
   520  		t.Fatalf("missing")
   521  	}
   522  	if k != 128 {
   523  		t.Fatalf("bad: %v", k)
   524  	}
   525  
   526  	k, _, ok = l.RemoveOldest()
   527  	if !ok {
   528  		t.Fatalf("missing")
   529  	}
   530  	if k != 128 {
   531  		t.Fatalf("bad: %v", k)
   532  	}
   533  
   534  	k, _, ok = l.RemoveOldest()
   535  	if !ok {
   536  		t.Fatalf("missing")
   537  	}
   538  	if k != 129 {
   539  		t.Fatalf("bad: %v", k)
   540  	}
   541  }