1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.commons.collections;
18
19 import static org.junit.jupiter.api.Assertions.*;
20 import static org.apache.juneau.commons.collections.CacheMode.*;
21 import static org.apache.juneau.junit.bct.BctAssertions.*;
22
23 import java.util.*;
24 import java.util.concurrent.*;
25 import java.util.concurrent.atomic.*;
26
27 import org.apache.juneau.*;
28 import org.junit.jupiter.api.*;
29
30 class Cache2_Test extends TestBase {
31
32
33
34
35
36 @Test
37 void a01_defaultSupplier_cacheMiss() {
38 var callCount = new AtomicInteger();
39 var x = Cache2.of(String.class, Integer.class, String.class)
40 .supplier((k1, k2) -> {
41 callCount.incrementAndGet();
42 return k1 + ":" + k2;
43 })
44 .build();
45
46 var result = x.get("user", 123);
47
48 assertEquals("user:123", result);
49 assertEquals(1, callCount.get());
50 assertSize(1, x);
51 assertEquals(0, x.getCacheHits());
52 }
53
54 @Test
55 void a02_defaultSupplier_cacheHit() {
56 var callCount = new AtomicInteger();
57 var x = Cache2.of(String.class, Integer.class, String.class)
58 .supplier((k1, k2) -> {
59 callCount.incrementAndGet();
60 return k1 + ":" + k2;
61 })
62 .build();
63
64
65 var result1 = x.get("user", 123);
66
67
68 var result2 = x.get("user", 123);
69
70 assertEquals("user:123", result1);
71 assertEquals("user:123", result2);
72 assertSame(result1, result2);
73 assertEquals(1, callCount.get());
74 assertSize(1, x);
75 assertEquals(1, x.getCacheHits());
76 }
77
78 @Test
79 void a03_multipleKeys() {
80 var callCount = new AtomicInteger();
81 var x = Cache2.of(String.class, Integer.class, String.class)
82 .supplier((k1, k2) -> {
83 callCount.incrementAndGet();
84 return k1 + ":" + k2;
85 })
86 .build();
87
88 var v1 = x.get("user", 123);
89 var v2 = x.get("admin", 456);
90 var v3 = x.get("guest", 789);
91
92 assertEquals("user:123", v1);
93 assertEquals("admin:456", v2);
94 assertEquals("guest:789", v3);
95 assertEquals(3, callCount.get());
96 assertSize(3, x);
97 assertEquals(0, x.getCacheHits());
98 }
99
100
101
102
103
104 @Test
105 void b01_overrideSupplier() {
106 var x = Cache2.of(String.class, Integer.class, String.class)
107 .supplier((k1, k2) -> k1 + ":" + k2)
108 .build();
109
110
111 var result = x.get("user", 123, () -> "OVERRIDE");
112
113 assertEquals("OVERRIDE", result);
114 assertSize(1, x);
115 }
116
117 @Test
118 void b02_overrideSupplier_cachesResult() {
119 var defaultCalls = new AtomicInteger();
120 var overrideCalls = new AtomicInteger();
121 var x = Cache2.of(String.class, Integer.class, String.class)
122 .supplier((k1, k2) -> {
123 defaultCalls.incrementAndGet();
124 return "DEFAULT";
125 })
126 .build();
127
128
129 var result1 = x.get("user", 123, () -> {
130 overrideCalls.incrementAndGet();
131 return "OVERRIDE";
132 });
133
134
135 var result2 = x.get("user", 123);
136
137 assertEquals("OVERRIDE", result1);
138 assertEquals("OVERRIDE", result2);
139 assertEquals(0, defaultCalls.get());
140 assertEquals(1, overrideCalls.get());
141 assertEquals(1, x.getCacheHits());
142 }
143
144
145
146
147
148 @Test
149 void c01_nullKeys_defaultSupplier() {
150 var x = Cache2.of(String.class, Integer.class, String.class)
151 .supplier((k1, k2) -> "value-" + k1 + "-" + k2)
152 .build();
153
154
155 assertEquals("value-null-123", x.get(null, 123));
156 assertEquals("value-user-null", x.get("user", null));
157 assertEquals("value-null-null", x.get(null, null));
158
159
160 assertEquals("value-null-123", x.get(null, 123));
161 assertEquals("value-user-null", x.get("user", null));
162 }
163
164 @Test
165 void c02_nullKeys_overrideSupplier() {
166 var x = Cache2.of(String.class, Integer.class, String.class).build();
167
168
169 assertEquals("value", x.get(null, 123, () -> "value"));
170 assertEquals("value", x.get("user", null, () -> "value"));
171 assertEquals("value", x.get(null, null, () -> "value"));
172
173
174 assertEquals("value", x.get(null, 123, () -> "should-not-be-called"));
175 assertEquals("value", x.get("user", null, () -> "should-not-be-called"));
176 }
177
178
179
180
181
182 @Test
183 void d01_disableCaching_alwaysCallsSupplier() {
184 var defaultCallCount = new AtomicInteger();
185 var overrideCallCount = new AtomicInteger();
186 var x = Cache2.of(String.class, Integer.class, String.class)
187 .cacheMode(NONE)
188 .supplier((k1, k2) -> {
189 defaultCallCount.incrementAndGet();
190 return k1 + ":" + k2;
191 })
192 .build();
193
194
195 assertEquals("user:123", x.get("user", 123, () -> {
196 overrideCallCount.incrementAndGet();
197 return "user:123";
198 }));
199 assertEquals(0, defaultCallCount.get());
200 assertEquals(1, overrideCallCount.get());
201
202
203 assertEquals("user:123", x.get("user", 123, () -> {
204 overrideCallCount.incrementAndGet();
205 return "user:123";
206 }));
207 assertEquals(0, defaultCallCount.get());
208 assertEquals(2, overrideCallCount.get());
209
210
211 assertEquals("user:456", x.get("user", 456));
212 assertEquals(1, defaultCallCount.get());
213
214 assertEquals("user:456", x.get("user", 456));
215 assertEquals(2, defaultCallCount.get());
216
217 assertEmpty(x);
218 }
219
220
221
222
223
224 @Test
225 void d02_weakMode_basicCaching() {
226 var callCount = new AtomicInteger();
227 var x = Cache2.of(String.class, Integer.class, String.class)
228 .cacheMode(WEAK)
229 .supplier((k1, k2) -> {
230 callCount.incrementAndGet();
231 return k1 + ":" + k2;
232 })
233 .build();
234
235
236 var result1 = x.get("user", 123);
237
238
239 var result2 = x.get("user", 123);
240
241 assertEquals("user:123", result1);
242 assertEquals("user:123", result2);
243 assertSame(result1, result2);
244 assertEquals(1, callCount.get());
245 assertSize(1, x);
246 assertEquals(1, x.getCacheHits());
247 }
248
249 @Test
250 void d03_weakMode_multipleKeys() {
251 var x = Cache2.of(String.class, Integer.class, String.class)
252 .cacheMode(WEAK)
253 .supplier((k1, k2) -> k1 + ":" + k2)
254 .build();
255
256 x.get("user", 123);
257 x.get("admin", 456);
258 x.get("guest", 789);
259
260 assertSize(3, x);
261 assertEquals(0, x.getCacheHits());
262
263
264 assertEquals("user:123", x.get("user", 123));
265 assertEquals("admin:456", x.get("admin", 456));
266 assertEquals("guest:789", x.get("guest", 789));
267 assertEquals(3, x.getCacheHits());
268 }
269
270 @Test
271 void d04_weakMode_clear() {
272 var x = Cache2.of(String.class, Integer.class, String.class)
273 .cacheMode(WEAK)
274 .supplier((k1, k2) -> k1 + ":" + k2)
275 .build();
276
277 x.get("user", 123);
278 x.get("admin", 456);
279 assertSize(2, x);
280
281 x.clear();
282 assertEmpty(x);
283 }
284
285 @Test
286 void d05_weakMode_maxSize() {
287 var x = Cache2.of(String.class, Integer.class, String.class)
288 .cacheMode(WEAK)
289 .maxSize(2)
290 .supplier((k1, k2) -> k1 + ":" + k2)
291 .build();
292
293 x.get("k1", 1);
294 x.get("k2", 2);
295 assertSize(2, x);
296
297
298 x.get("k3", 3);
299 assertSize(3, x);
300
301
302 x.get("k4", 4);
303 assertSize(1, x);
304 }
305
306 @Test
307 void d06_weakMethod_basicCaching() {
308
309 var callCount = new AtomicInteger();
310 var x = Cache2.of(String.class, Integer.class, String.class)
311 .weak()
312 .supplier((k1, k2) -> {
313 callCount.incrementAndGet();
314 return k1 + ":" + k2;
315 })
316 .build();
317
318
319 var result1 = x.get("user", 123);
320
321
322 var result2 = x.get("user", 123);
323
324 assertEquals("user:123", result1);
325 assertEquals("user:123", result2);
326 assertSame(result1, result2);
327 assertEquals(1, callCount.get());
328 assertSize(1, x);
329 assertEquals(1, x.getCacheHits());
330 }
331
332 @Test
333 void d07_weakMethod_chaining() {
334
335 var x = Cache2.of(String.class, Integer.class, String.class)
336 .weak()
337 .maxSize(100)
338 .supplier((k1, k2) -> k1 + ":" + k2)
339 .build();
340
341 var result = x.get("user", 123);
342 assertEquals("user:123", result);
343 assertSize(1, x);
344 }
345
346
347
348
349
350 @Test
351 void e01_maxSize_clearsWhenExceeded() {
352 var x = Cache2.of(String.class, Integer.class, String.class)
353 .maxSize(2)
354 .supplier((k1, k2) -> k1 + ":" + k2)
355 .build();
356
357 x.get("k1", 1);
358 x.get("k2", 2);
359 assertSize(2, x);
360
361
362 x.get("k3", 3);
363 assertSize(3, x);
364
365
366 x.get("k4", 4);
367 assertSize(1, x);
368 }
369
370
371
372
373
374 @Test
375 void f01_cacheHitsTracking() {
376 var x = Cache2.of(String.class, Integer.class, String.class)
377 .supplier((k1, k2) -> k1 + ":" + k2)
378 .build();
379
380 assertEquals(0, x.getCacheHits());
381
382 x.get("user", 123);
383 assertEquals(0, x.getCacheHits());
384
385 x.get("user", 123);
386 assertEquals(1, x.getCacheHits());
387
388 x.get("admin", 456);
389 assertEquals(1, x.getCacheHits());
390
391 x.get("user", 123);
392 x.get("admin", 456);
393 assertEquals(3, x.getCacheHits());
394 }
395
396
397
398
399
400 @Test
401 void g01_clear() {
402 var x = Cache2.of(String.class, Integer.class, String.class)
403 .supplier((k1, k2) -> k1 + ":" + k2)
404 .build();
405
406 x.get("user", 123);
407 x.get("admin", 456);
408 assertSize(2, x);
409
410 x.clear();
411
412 assertEmpty(x);
413 }
414
415
416
417
418
419 @Test
420 void h01_noDefaultSupplier_requiresOverride() {
421 var x = Cache2.of(String.class, Integer.class, String.class).build();
422
423 assertThrows(NullPointerException.class, () -> x.get("user", 123));
424 }
425
426 @Test
427 void h02_noDefaultSupplier_worksWithOverride() {
428 var x = Cache2.of(String.class, Integer.class, String.class).build();
429
430 var result = x.get("user", 123, () -> "CUSTOM");
431
432 assertEquals("CUSTOM", result);
433 assertSize(1, x);
434 }
435
436
437
438
439
440 @Test
441 void i01_put_directInsertion() {
442 var x = Cache2.of(String.class, Integer.class, String.class).build();
443 var previous = x.put("user", 123, "value1");
444 assertNull(previous);
445 assertEquals("value1", x.get("user", 123, () -> "should not be called"));
446 assertSize(1, x);
447 }
448
449 @Test
450 void i02_put_overwritesExisting() {
451 var x = Cache2.of(String.class, Integer.class, String.class).build();
452 x.put("user", 123, "value1");
453 var previous = x.put("user", 123, "value2");
454 assertEquals("value1", previous);
455 assertEquals("value2", x.get("user", 123, () -> "should not be called"));
456 }
457
458 @Test
459 void i03_put_withNullValue() {
460 var x = Cache2.of(String.class, Integer.class, String.class).build();
461 x.put("user", 123, "value1");
462 var previous = x.put("user", 123, null);
463 assertEquals("value1", previous);
464 assertFalse(x.containsKey("user", 123));
465 }
466
467 @Test
468 void i04_put_withNullValue_newKey() {
469 var x = Cache2.of(String.class, Integer.class, String.class).build();
470 var previous = x.put("user", 123, null);
471 assertNull(previous);
472 assertFalse(x.containsKey("user", 123));
473 assertTrue(x.isEmpty());
474 }
475
476
477
478
479
480 @Test
481 void j01_isEmpty_newCache() {
482 var x = Cache2.of(String.class, Integer.class, String.class).build();
483 assertTrue(x.isEmpty());
484 }
485
486 @Test
487 void j02_isEmpty_afterPut() {
488 var x = Cache2.of(String.class, Integer.class, String.class).build();
489 x.put("user", 123, "value");
490 assertFalse(x.isEmpty());
491 }
492
493 @Test
494 void j03_isEmpty_afterClear() {
495 var x = Cache2.of(String.class, Integer.class, String.class).build();
496 x.put("user", 123, "value");
497 x.clear();
498 assertTrue(x.isEmpty());
499 }
500
501
502
503
504
505 @Test
506 void k01_containsKey_notPresent() {
507 var x = Cache2.of(String.class, Integer.class, String.class).build();
508 assertFalse(x.containsKey("user", 123));
509 }
510
511 @Test
512 void k02_containsKey_afterPut() {
513 var x = Cache2.of(String.class, Integer.class, String.class).build();
514 x.put("user", 123, "value");
515 assertTrue(x.containsKey("user", 123));
516 assertFalse(x.containsKey("user", 456));
517 }
518
519 @Test
520 void k03_containsKey_afterGet() {
521 var x = Cache2.of(String.class, Integer.class, String.class)
522 .supplier((k1, k2) -> k1 + ":" + k2)
523 .build();
524 x.get("user", 123);
525 assertTrue(x.containsKey("user", 123));
526 }
527
528
529
530
531
532 @Test
533 void l02_remove_existingKey() {
534 var x = Cache2.of(String.class, Integer.class, String.class).build();
535 x.put("user", 123, "value1");
536 var removed = x.remove("user", 123);
537 assertEquals("value1", removed);
538 assertFalse(x.containsKey("user", 123));
539 }
540
541 @Test
542 void l03_remove_nonExistentKey() {
543 var x = Cache2.of(String.class, Integer.class, String.class).build();
544 var removed = x.remove("user", 123);
545 assertNull(removed);
546 }
547
548
549
550
551
552 @Test
553 void m02_containsValue_present() {
554 var x = Cache2.of(String.class, Integer.class, String.class).build();
555 x.put("user", 123, "value1");
556 x.put("admin", 456, "value2");
557 assertTrue(x.containsValue("value1"));
558 assertTrue(x.containsValue("value2"));
559 assertFalse(x.containsValue("value3"));
560 }
561
562 @Test
563 void m03_containsValue_notPresent() {
564 var x = Cache2.of(String.class, Integer.class, String.class).build();
565 assertFalse(x.containsValue("value1"));
566 }
567
568 @Test
569 void m04_containsValue_nullValue() {
570 var x = Cache2.of(String.class, Integer.class, String.class).build();
571
572 x.get("user", 123, () -> null);
573 assertFalse(x.containsValue(null));
574
575 var x2 = Cache2.of(String.class, Integer.class, String.class).build();
576 assertFalse(x2.containsValue(null));
577 }
578
579
580
581
582
583 @Test
584 void n02_logOnExit_withStringId() {
585 var x = Cache2.of(String.class, Integer.class, String.class)
586 .logOnExit("TestCache2")
587 .supplier((k1, k2) -> k1 + ":" + k2)
588 .build();
589 x.get("user", 123);
590 assertSize(1, x);
591 }
592
593 @Test
594 void n03_logOnExit_withBooleanTrue() {
595 var x = Cache2.of(String.class, Integer.class, String.class)
596 .logOnExit(true, "MyCache2")
597 .supplier((k1, k2) -> k1 + ":" + k2)
598 .build();
599 x.get("user", 123);
600 assertSize(1, x);
601 }
602
603 @Test
604 void n04_logOnExit_withBooleanFalse() {
605 var x = Cache2.of(String.class, Integer.class, String.class)
606 .logOnExit(false, "DisabledCache2")
607 .supplier((k1, k2) -> k1 + ":" + k2)
608 .build();
609 x.get("user", 123);
610 assertSize(1, x);
611 }
612
613
614
615
616
617 @Test
618 void l01_create_basic() {
619 var x = Cache2.<String, Integer, String>create()
620 .supplier((k1, k2) -> k1 + ":" + k2)
621 .build();
622
623 var result = x.get("user", 123);
624 assertEquals("user:123", result);
625 assertSize(1, x);
626 }
627
628
629
630
631
632 @Test
633 void m01_disableCaching() {
634 var callCount = new AtomicInteger();
635 var x = Cache2.of(String.class, Integer.class, String.class)
636 .cacheMode(NONE)
637 .supplier((k1, k2) -> {
638 callCount.incrementAndGet();
639 return "value";
640 })
641 .build();
642
643 x.get("user", 123);
644 x.get("user", 123);
645 assertEquals(2, callCount.get());
646 assertTrue(x.isEmpty());
647 }
648
649
650
651
652
653 @Test
654 void n01_nullValue_notCached() {
655 var callCount = new AtomicInteger();
656 var x = Cache2.of(String.class, Integer.class, String.class).build();
657
658 var result1 = x.get("user", 123, () -> {
659 callCount.incrementAndGet();
660 return null;
661 });
662 assertNull(result1);
663
664 var result2 = x.get("user", 123, () -> {
665 callCount.incrementAndGet();
666 return null;
667 });
668 assertNull(result2);
669 assertEquals(2, callCount.get());
670 assertTrue(x.isEmpty());
671 }
672
673
674
675
676
677 @Test
678 void o01_threadLocal_basicCaching() {
679 var callCount = new AtomicInteger();
680 var x = Cache2.of(String.class, Integer.class, String.class)
681 .threadLocal()
682 .supplier((k1, k2) -> {
683 callCount.incrementAndGet();
684 return k1 + ":" + k2;
685 })
686 .build();
687
688
689 var result1 = x.get("user", 123);
690
691
692 var result2 = x.get("user", 123);
693
694 assertEquals("user:123", result1);
695 assertEquals("user:123", result2);
696 assertSame(result1, result2);
697 assertEquals(1, callCount.get());
698 assertSize(1, x);
699 assertEquals(1, x.getCacheHits());
700 }
701
702 @Test
703 void o02_threadLocal_eachThreadHasOwnCache() throws Exception {
704 var x = Cache2.of(String.class, Integer.class, String.class)
705 .threadLocal()
706 .build();
707 var executor = java.util.concurrent.Executors.newFixedThreadPool(2);
708 var threadValues = new ConcurrentHashMap<Thread, String>();
709
710
711 var future1 = java.util.concurrent.CompletableFuture.runAsync(() -> {
712 var value = x.get("user", 123, () -> "thread1-value");
713 threadValues.put(Thread.currentThread(), value);
714 }, executor);
715
716 var future2 = java.util.concurrent.CompletableFuture.runAsync(() -> {
717 var value = x.get("user", 123, () -> "thread2-value");
718 threadValues.put(Thread.currentThread(), value);
719 }, executor);
720
721 java.util.concurrent.CompletableFuture.allOf(future1, future2).get(5, java.util.concurrent.TimeUnit.SECONDS);
722
723
724 assertEquals(2, threadValues.size());
725 assertTrue(threadValues.containsValue("thread1-value"));
726 assertTrue(threadValues.containsValue("thread2-value"));
727
728
729 var threadValues2 = new ConcurrentHashMap<Thread, String>();
730 var threads = new ArrayList<>(threadValues.keySet());
731
732 future1 = java.util.concurrent.CompletableFuture.runAsync(() -> {
733 var value = x.get("user", 123, () -> "should-not-be-called");
734 threadValues2.put(Thread.currentThread(), value);
735 }, executor);
736
737 future2 = java.util.concurrent.CompletableFuture.runAsync(() -> {
738 var value = x.get("user", 123, () -> "should-not-be-called");
739 threadValues2.put(Thread.currentThread(), value);
740 }, executor);
741
742 java.util.concurrent.CompletableFuture.allOf(future1, future2).get(5, java.util.concurrent.TimeUnit.SECONDS);
743
744
745 for (var thread : threads) {
746 if (threadValues2.containsKey(thread)) {
747 assertEquals(threadValues.get(thread), threadValues2.get(thread),
748 "Thread " + thread + " should get its own cached value");
749 }
750 }
751
752 executor.shutdown();
753 }
754
755 @Test
756 void o03_threadLocal_multipleKeys() {
757 var x = Cache2.of(String.class, Integer.class, String.class)
758 .threadLocal()
759 .supplier((k1, k2) -> k1 + ":" + k2)
760 .build();
761
762 x.get("user", 123);
763 x.get("admin", 456);
764 x.get("guest", 789);
765
766 assertSize(3, x);
767 assertEquals(0, x.getCacheHits());
768
769
770 assertEquals("user:123", x.get("user", 123));
771 assertEquals("admin:456", x.get("admin", 456));
772 assertEquals("guest:789", x.get("guest", 789));
773 assertEquals(3, x.getCacheHits());
774 }
775
776 @Test
777 void o04_threadLocal_clear() {
778 var x = Cache2.of(String.class, Integer.class, String.class)
779 .threadLocal()
780 .supplier((k1, k2) -> k1 + ":" + k2)
781 .build();
782
783 x.get("user", 123);
784 x.get("admin", 456);
785 assertSize(2, x);
786
787 x.clear();
788 assertEmpty(x);
789 }
790
791 @Test
792 void o05_threadLocal_maxSize() {
793 var x = Cache2.of(String.class, Integer.class, String.class)
794 .threadLocal()
795 .maxSize(2)
796 .supplier((k1, k2) -> k1 + ":" + k2)
797 .build();
798
799 x.get("k1", 1);
800 x.get("k2", 2);
801 assertSize(2, x);
802
803
804 x.get("k3", 3);
805 assertSize(3, x);
806
807
808 x.get("k4", 4);
809 assertSize(1, x);
810 }
811
812
813
814
815
816 @Test
817 void p01_threadLocal_weakMode_basicCaching() {
818 var callCount = new AtomicInteger();
819 var x = Cache2.of(String.class, Integer.class, String.class)
820 .threadLocal()
821 .cacheMode(WEAK)
822 .supplier((k1, k2) -> {
823 callCount.incrementAndGet();
824 return k1 + ":" + k2;
825 })
826 .build();
827
828
829 var result1 = x.get("user", 123);
830
831
832 var result2 = x.get("user", 123);
833
834 assertEquals("user:123", result1);
835 assertEquals("user:123", result2);
836 assertSame(result1, result2);
837 assertEquals(1, callCount.get());
838 assertSize(1, x);
839 assertEquals(1, x.getCacheHits());
840 }
841
842 @Test
843 void p02_threadLocal_weakMode_eachThreadHasOwnCache() throws Exception {
844 var x = Cache2.of(String.class, Integer.class, String.class)
845 .threadLocal()
846 .cacheMode(WEAK)
847 .build();
848 var executor = java.util.concurrent.Executors.newFixedThreadPool(2);
849 var threadValues = new ConcurrentHashMap<Thread, String>();
850
851
852 var future1 = java.util.concurrent.CompletableFuture.runAsync(() -> {
853 var value = x.get("user", 123, () -> "thread1-value");
854 threadValues.put(Thread.currentThread(), value);
855 }, executor);
856
857 var future2 = java.util.concurrent.CompletableFuture.runAsync(() -> {
858 var value = x.get("user", 123, () -> "thread2-value");
859 threadValues.put(Thread.currentThread(), value);
860 }, executor);
861
862 java.util.concurrent.CompletableFuture.allOf(future1, future2).get(5, java.util.concurrent.TimeUnit.SECONDS);
863
864
865 assertEquals(2, threadValues.size());
866 assertTrue(threadValues.containsValue("thread1-value"));
867 assertTrue(threadValues.containsValue("thread2-value"));
868
869 executor.shutdown();
870 }
871
872 @Test
873 void p03_threadLocal_weakMode_clear() {
874 var x = Cache2.of(String.class, Integer.class, String.class)
875 .threadLocal()
876 .cacheMode(WEAK)
877 .supplier((k1, k2) -> k1 + ":" + k2)
878 .build();
879
880 x.get("user", 123);
881 x.get("admin", 456);
882 assertSize(2, x);
883
884 x.clear();
885 assertEmpty(x);
886 }
887
888 @Test
889 void p04_threadLocal_weakMode_maxSize() {
890 var x = Cache2.of(String.class, Integer.class, String.class)
891 .threadLocal()
892 .cacheMode(WEAK)
893 .maxSize(2)
894 .supplier((k1, k2) -> k1 + ":" + k2)
895 .build();
896
897 x.get("k1", 1);
898 x.get("k2", 2);
899 assertSize(2, x);
900
901
902 x.get("k3", 3);
903 assertSize(3, x);
904
905
906 x.get("k4", 4);
907 assertSize(1, x);
908 }
909 }
910