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 }