github.com/bhojpur/cache@v0.0.4/pkg/engine/lru_cache_test.go (about) 1 package engine 2 3 // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 import ( 24 "testing" 25 ) 26 27 type CacheValue struct { 28 size int64 29 } 30 31 func cacheValueSize(val interface{}) int64 { 32 return val.(*CacheValue).size 33 } 34 35 func TestInitialState(t *testing.T) { 36 cache := NewLRUCache(5, cacheValueSize) 37 l, sz, c, e := cache.Len(), cache.UsedCapacity(), cache.MaxCapacity(), cache.Evictions() 38 if l != 0 { 39 t.Errorf("length = %v, want 0", l) 40 } 41 if sz != 0 { 42 t.Errorf("size = %v, want 0", sz) 43 } 44 if c != 5 { 45 t.Errorf("capacity = %v, want 5", c) 46 } 47 if e != 0 { 48 t.Errorf("evictions = %v, want 0", c) 49 } 50 } 51 52 func TestSetInsertsValue(t *testing.T) { 53 cache := NewLRUCache(100, cacheValueSize) 54 data := &CacheValue{0} 55 key := "key" 56 cache.Set(key, data) 57 58 v, ok := cache.Get(key) 59 if !ok || v.(*CacheValue) != data { 60 t.Errorf("Cache has incorrect value: %v != %v", data, v) 61 } 62 63 values := cache.Items() 64 if len(values) != 1 || values[0].Key != key { 65 t.Errorf("Cache.Values() returned incorrect values: %v", values) 66 } 67 } 68 69 func TestGetValueWithMultipleTypes(t *testing.T) { 70 cache := NewLRUCache(100, cacheValueSize) 71 data := &CacheValue{0} 72 key := "key" 73 cache.Set(key, data) 74 75 v, ok := cache.Get("key") 76 if !ok || v.(*CacheValue) != data { 77 t.Errorf("Cache has incorrect value for \"key\": %v != %v", data, v) 78 } 79 80 v, ok = cache.Get(string([]byte{'k', 'e', 'y'})) 81 if !ok || v.(*CacheValue) != data { 82 t.Errorf("Cache has incorrect value for []byte {'k','e','y'}: %v != %v", data, v) 83 } 84 } 85 86 func TestSetUpdatesSize(t *testing.T) { 87 cache := NewLRUCache(100, cacheValueSize) 88 emptyValue := &CacheValue{0} 89 key := "key1" 90 cache.Set(key, emptyValue) 91 if sz := cache.UsedCapacity(); sz != 0 { 92 t.Errorf("cache.UsedCapacity() = %v, expected 0", sz) 93 } 94 someValue := &CacheValue{20} 95 key = "key2" 96 cache.Set(key, someValue) 97 if sz := cache.UsedCapacity(); sz != 20 { 98 t.Errorf("cache.UsedCapacity() = %v, expected 20", sz) 99 } 100 } 101 102 func TestSetWithOldKeyUpdatesValue(t *testing.T) { 103 cache := NewLRUCache(100, cacheValueSize) 104 emptyValue := &CacheValue{0} 105 key := "key1" 106 cache.Set(key, emptyValue) 107 someValue := &CacheValue{20} 108 cache.Set(key, someValue) 109 110 v, ok := cache.Get(key) 111 if !ok || v.(*CacheValue) != someValue { 112 t.Errorf("Cache has incorrect value: %v != %v", someValue, v) 113 } 114 } 115 116 func TestSetWithOldKeyUpdatesSize(t *testing.T) { 117 cache := NewLRUCache(100, cacheValueSize) 118 emptyValue := &CacheValue{0} 119 key := "key1" 120 cache.Set(key, emptyValue) 121 122 if sz := cache.UsedCapacity(); sz != 0 { 123 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, 0) 124 } 125 126 someValue := &CacheValue{20} 127 cache.Set(key, someValue) 128 expected := int64(someValue.size) 129 if sz := cache.UsedCapacity(); sz != expected { 130 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, expected) 131 } 132 } 133 134 func TestGetNonExistent(t *testing.T) { 135 cache := NewLRUCache(100, cacheValueSize) 136 137 if _, ok := cache.Get("notthere"); ok { 138 t.Error("Cache returned a notthere value after no inserts.") 139 } 140 } 141 142 func TestDelete(t *testing.T) { 143 cache := NewLRUCache(100, cacheValueSize) 144 value := &CacheValue{1} 145 key := "key" 146 147 cache.Delete(key) 148 cache.Set(key, value) 149 cache.Delete(key) 150 151 if sz := cache.UsedCapacity(); sz != 0 { 152 t.Errorf("cache.UsedCapacity() = %v, expected 0", sz) 153 } 154 155 if _, ok := cache.Get(key); ok { 156 t.Error("Cache returned a value after deletion.") 157 } 158 } 159 160 func TestClear(t *testing.T) { 161 cache := NewLRUCache(100, cacheValueSize) 162 value := &CacheValue{1} 163 key := "key" 164 165 cache.Set(key, value) 166 cache.Clear() 167 168 if sz := cache.UsedCapacity(); sz != 0 { 169 t.Errorf("cache.UsedCapacity() = %v, expected 0 after Clear()", sz) 170 } 171 } 172 173 func TestCapacityIsObeyed(t *testing.T) { 174 size := int64(3) 175 cache := NewLRUCache(100, cacheValueSize) 176 cache.SetCapacity(size) 177 value := &CacheValue{1} 178 179 // Insert up to the cache's capacity. 180 cache.Set("key1", value) 181 cache.Set("key2", value) 182 cache.Set("key3", value) 183 if sz := cache.UsedCapacity(); sz != size { 184 t.Errorf("cache.UsedCapacity() = %v, expected %v", sz, size) 185 } 186 // Insert one more; something should be evicted to make room. 187 cache.Set("key4", value) 188 sz, evictions := cache.UsedCapacity(), cache.Evictions() 189 if sz != size { 190 t.Errorf("post-evict cache.UsedCapacity() = %v, expected %v", sz, size) 191 } 192 if evictions != 1 { 193 t.Errorf("post-evict cache.Evictions() = %v, expected 1", evictions) 194 } 195 196 // Check various other stats 197 if l := cache.Len(); int64(l) != size { 198 t.Errorf("cache.Len() returned bad length: %v", l) 199 } 200 if s := cache.UsedCapacity(); s != size { 201 t.Errorf("cache.UsedCapacity() returned bad size: %v", s) 202 } 203 if c := cache.MaxCapacity(); c != size { 204 t.Errorf("cache.UsedCapacity() returned bad length: %v", c) 205 } 206 } 207 208 func TestLRUIsEvicted(t *testing.T) { 209 size := int64(3) 210 cache := NewLRUCache(size, cacheValueSize) 211 212 cache.Set("key1", &CacheValue{1}) 213 cache.Set("key2", &CacheValue{1}) 214 cache.Set("key3", &CacheValue{1}) 215 // lru: [key3, key2, key1] 216 217 // Look up the elements. This will rearrange the LRU ordering. 218 cache.Get("key3") 219 cache.Get("key2") 220 cache.Get("key1") 221 // lru: [key1, key2, key3] 222 223 cache.Set("key0", &CacheValue{1}) 224 // lru: [key0, key1, key2] 225 226 // The least recently used one should have been evicted. 227 if _, ok := cache.Get("key3"); ok { 228 t.Error("Least recently used element was not evicted.") 229 } 230 231 if e, want := cache.Evictions(), int64(1); e != want { 232 t.Errorf("evictions: %d, want: %d", e, want) 233 } 234 }