From 8f8764ff4ea3482c98afefa2b7a7ce8d922d93bc Mon Sep 17 00:00:00 2001 From: Michael Gaffney Date: Wed, 23 Aug 2023 14:07:16 -0400 Subject: [PATCH] test: Add tests for eviction callback This adds tests to verify that calling Add, ContainsOrAdd, or PeekOrAdd with a key that is already in the cache does not trigger an eviction or an eviction callback. --- expirable/expirable_lru_test.go | 44 ++++++++++ lru_test.go | 148 ++++++++++++++++++++++++++++++++ simplelru/lru_test.go | 48 ++++++++++- 3 files changed, 239 insertions(+), 1 deletion(-) diff --git a/expirable/expirable_lru_test.go b/expirable/expirable_lru_test.go index cc328e3..11fb7e3 100644 --- a/expirable/expirable_lru_test.go +++ b/expirable/expirable_lru_test.go @@ -517,3 +517,47 @@ func getRand(tb testing.TB) int64 { } return out.Int64() } + +func (c *LRU[K, V]) wantKeys(t *testing.T, want []K) { + t.Helper() + got := c.Keys() + if !reflect.DeepEqual(got, want) { + t.Errorf("wrong keys got: %v, want: %v ", got, want) + } +} + +func TestCache_EvictionSameKey(t *testing.T) { + var evictedKeys []int + + cache := NewLRU[int, struct{}]( + 2, + func(key int, _ struct{}) { + evictedKeys = append(evictedKeys, key) + }, + 0) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("First 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1}) + + if evicted := cache.Add(2, struct{}{}); evicted { + t.Error("2: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("Second 1: got unexpected eviction") + } + cache.wantKeys(t, []int{2, 1}) + + if evicted := cache.Add(3, struct{}{}); !evicted { + t.Error("3: did not get expected eviction") + } + cache.wantKeys(t, []int{1, 3}) + + want := []int{2} + if !reflect.DeepEqual(evictedKeys, want) { + t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want) + } +} diff --git a/lru_test.go b/lru_test.go index 9da0b23..36cbfff 100644 --- a/lru_test.go +++ b/lru_test.go @@ -4,6 +4,7 @@ package lru import ( + "reflect" "testing" ) @@ -293,3 +294,150 @@ func TestLRUResize(t *testing.T) { t.Errorf("Cache should have contained 2 elements") } } + +func (c *Cache[K, V]) wantKeys(t *testing.T, want []K) { + t.Helper() + got := c.Keys() + if !reflect.DeepEqual(got, want) { + t.Errorf("wrong keys got: %v, want: %v ", got, want) + } +} + +func TestCache_EvictionSameKey(t *testing.T) { + t.Run("Add", func(t *testing.T) { + var evictedKeys []int + + cache, _ := NewWithEvict( + 2, + func(key int, _ struct{}) { + evictedKeys = append(evictedKeys, key) + }) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("First 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1}) + + if evicted := cache.Add(2, struct{}{}); evicted { + t.Error("2: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("Second 1: got unexpected eviction") + } + cache.wantKeys(t, []int{2, 1}) + + if evicted := cache.Add(3, struct{}{}); !evicted { + t.Error("3: did not get expected eviction") + } + cache.wantKeys(t, []int{1, 3}) + + want := []int{2} + if !reflect.DeepEqual(evictedKeys, want) { + t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want) + } + }) + + t.Run("ContainsOrAdd", func(t *testing.T) { + var evictedKeys []int + + cache, _ := NewWithEvict( + 2, + func(key int, _ struct{}) { + evictedKeys = append(evictedKeys, key) + }) + + contained, evicted := cache.ContainsOrAdd(1, struct{}{}) + if contained { + t.Error("First 1: got unexpected contained") + } + if evicted { + t.Error("First 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1}) + + contained, evicted = cache.ContainsOrAdd(2, struct{}{}) + if contained { + t.Error("2: got unexpected contained") + } + if evicted { + t.Error("2: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + contained, evicted = cache.ContainsOrAdd(1, struct{}{}) + if !contained { + t.Error("Second 1: did not get expected contained") + } + if evicted { + t.Error("Second 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + contained, evicted = cache.ContainsOrAdd(3, struct{}{}) + if contained { + t.Error("3: got unexpected contained") + } + if !evicted { + t.Error("3: did not get expected eviction") + } + cache.wantKeys(t, []int{2, 3}) + + want := []int{1} + if !reflect.DeepEqual(evictedKeys, want) { + t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want) + } + }) + + t.Run("PeekOrAdd", func(t *testing.T) { + var evictedKeys []int + + cache, _ := NewWithEvict( + 2, + func(key int, _ struct{}) { + evictedKeys = append(evictedKeys, key) + }) + + _, contained, evicted := cache.PeekOrAdd(1, struct{}{}) + if contained { + t.Error("First 1: got unexpected contained") + } + if evicted { + t.Error("First 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1}) + + _, contained, evicted = cache.PeekOrAdd(2, struct{}{}) + if contained { + t.Error("2: got unexpected contained") + } + if evicted { + t.Error("2: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + _, contained, evicted = cache.PeekOrAdd(1, struct{}{}) + if !contained { + t.Error("Second 1: did not get expected contained") + } + if evicted { + t.Error("Second 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + _, contained, evicted = cache.PeekOrAdd(3, struct{}{}) + if contained { + t.Error("3: got unexpected contained") + } + if !evicted { + t.Error("3: did not get expected eviction") + } + cache.wantKeys(t, []int{2, 3}) + + want := []int{1} + if !reflect.DeepEqual(evictedKeys, want) { + t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want) + } + }) +} diff --git a/simplelru/lru_test.go b/simplelru/lru_test.go index a6b247f..19a8fac 100644 --- a/simplelru/lru_test.go +++ b/simplelru/lru_test.go @@ -3,7 +3,10 @@ package simplelru -import "testing" +import ( + "reflect" + "testing" +) func TestLRU(t *testing.T) { evictCounter := 0 @@ -207,3 +210,46 @@ func TestLRU_Resize(t *testing.T) { t.Errorf("Cache should have contained 2 elements") } } + +func (c *LRU[K, V]) wantKeys(t *testing.T, want []K) { + t.Helper() + got := c.Keys() + if !reflect.DeepEqual(got, want) { + t.Errorf("wrong keys got: %v, want: %v ", got, want) + } +} + +func TestCache_EvictionSameKey(t *testing.T) { + var evictedKeys []int + + cache, _ := NewLRU( + 2, + func(key int, _ struct{}) { + evictedKeys = append(evictedKeys, key) + }) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("First 1: got unexpected eviction") + } + cache.wantKeys(t, []int{1}) + + if evicted := cache.Add(2, struct{}{}); evicted { + t.Error("2: got unexpected eviction") + } + cache.wantKeys(t, []int{1, 2}) + + if evicted := cache.Add(1, struct{}{}); evicted { + t.Error("Second 1: got unexpected eviction") + } + cache.wantKeys(t, []int{2, 1}) + + if evicted := cache.Add(3, struct{}{}); !evicted { + t.Error("3: did not get expected eviction") + } + cache.wantKeys(t, []int{1, 3}) + + want := []int{2} + if !reflect.DeepEqual(evictedKeys, want) { + t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want) + } +}