@@ -404,7 +404,7 @@ public void WhenValueEvictedItemRemovedEventIsFired()
404404
405405 for ( int i = 0 ; i < 6 ; i ++ )
406406 {
407- lruEvents . GetOrAdd ( i + 1 , i => i + 1 ) ;
407+ lruEvents . GetOrAdd ( i + 1 , i => i + 1 ) ;
408408 }
409409
410410 removedItems . Count . Should ( ) . Be ( 2 ) ;
@@ -461,7 +461,7 @@ public void WhenItemIsRemovedRemovedEventIsFired()
461461 var lruEvents = new ConcurrentLru < int , int > ( 1 , 6 , EqualityComparer < int > . Default ) ;
462462 lruEvents . ItemRemoved += OnLruItemRemoved ;
463463
464- lruEvents . GetOrAdd ( 1 , i => i + 2 ) ;
464+ lruEvents . GetOrAdd ( 1 , i => i + 2 ) ;
465465
466466 lruEvents . TryRemove ( 1 ) . Should ( ) . BeTrue ( ) ;
467467
@@ -581,7 +581,7 @@ public void WhenItemsExistClearRemovesAllItems()
581581 {
582582 lru . AddOrUpdate ( 1 , "1" ) ;
583583 lru . AddOrUpdate ( 2 , "2" ) ;
584-
584+
585585 lru . Clear ( ) ;
586586
587587 lru . Count . Should ( ) . Be ( 0 ) ;
@@ -608,5 +608,219 @@ public void WhenItemsAreDisposableClearDisposesItemsOnRemove()
608608
609609 items . All ( i => i . IsDisposed == true ) . Should ( ) . BeTrue ( ) ;
610610 }
611+
612+ [ Fact ]
613+ public void WhenItemsArClearedAnEventIsFired ( )
614+ {
615+ var lruEvents = new ConcurrentLru < int , int > ( 1 , 9 , EqualityComparer < int > . Default ) ;
616+ lruEvents . ItemRemoved += OnLruItemRemoved ;
617+
618+ for ( int i = 0 ; i < 6 ; i ++ )
619+ {
620+ lruEvents . GetOrAdd ( i + 1 , i => i + 1 ) ;
621+ }
622+
623+ lruEvents . Clear ( ) ;
624+
625+ removedItems . Count . Should ( ) . Be ( 6 ) ;
626+
627+ for ( int i = 0 ; i < 6 ; i ++ )
628+ {
629+ removedItems [ i ] . Reason . Should ( ) . Be ( ItemRemovedReason . Cleared ) ;
630+ }
631+ }
632+
633+ [ Fact ]
634+ public void WhenTrimCountIsZeroThrows ( )
635+ {
636+ lru . Invoking ( l => lru . Trim ( 0 ) ) . Should ( ) . Throw < ArgumentOutOfRangeException > ( ) ;
637+ }
638+
639+ [ Fact ]
640+ public void WhenTrimCountIsMoreThanCapacityThrows ( )
641+ {
642+ lru . Invoking ( l => lru . Trim ( hotCap + warmCap + coldCap + 1 ) ) . Should ( ) . Throw < ArgumentOutOfRangeException > ( ) ;
643+ }
644+
645+ [ Theory ]
646+ [ InlineData ( 1 , new [ ] { 9 , 8 , 7 , 3 , 2 , 1 , 6 , 5 } ) ]
647+ [ InlineData ( 2 , new [ ] { 9 , 8 , 7 , 3 , 2 , 1 , 6 } ) ]
648+ [ InlineData ( 3 , new [ ] { 9 , 8 , 7 , 3 , 2 , 1 } ) ]
649+ [ InlineData ( 4 , new [ ] { 9 , 8 , 7 , 3 , 2 } ) ]
650+ [ InlineData ( 5 , new [ ] { 9 , 8 , 7 , 3 } ) ]
651+ [ InlineData ( 6 , new [ ] { 9 , 8 , 7 } ) ]
652+ [ InlineData ( 7 , new [ ] { 9 , 8 } ) ]
653+ [ InlineData ( 8 , new [ ] { 9 } ) ]
654+ [ InlineData ( 9 , new int [ ] { } ) ]
655+ public void WhenColdItemsExistTrimRemovesExpectedItemCount ( int trimCount , int [ ] expected )
656+ {
657+ // initial state:
658+ // Hot = 9, 8, 7
659+ // Warm = 3, 2, 1
660+ // Cold = 6, 5, 4
661+ lru . AddOrUpdate ( 1 , "1" ) ;
662+ lru . AddOrUpdate ( 2 , "2" ) ;
663+ lru . AddOrUpdate ( 3 , "3" ) ;
664+ lru . GetOrAdd ( 1 , i => i . ToString ( ) ) ;
665+ lru . GetOrAdd ( 2 , i => i . ToString ( ) ) ;
666+ lru . GetOrAdd ( 3 , i => i . ToString ( ) ) ;
667+
668+ lru . AddOrUpdate ( 4 , "4" ) ;
669+ lru . AddOrUpdate ( 5 , "5" ) ;
670+ lru . AddOrUpdate ( 6 , "6" ) ;
671+
672+ lru . AddOrUpdate ( 7 , "7" ) ;
673+ lru . AddOrUpdate ( 8 , "8" ) ;
674+ lru . AddOrUpdate ( 9 , "9" ) ;
675+
676+ lru . Trim ( trimCount ) ;
677+
678+ lru . Keys . Should ( ) . BeEquivalentTo ( expected ) ;
679+ }
680+
681+ [ Theory ]
682+ [ InlineData ( 1 , new [ ] { 6 , 5 , 4 , 3 , 2 } ) ]
683+ [ InlineData ( 2 , new [ ] { 6 , 5 , 4 , 3 } ) ]
684+ [ InlineData ( 3 , new [ ] { 6 , 5 , 4 } ) ]
685+ [ InlineData ( 4 , new [ ] { 6 , 5 } ) ]
686+ [ InlineData ( 5 , new [ ] { 6 } ) ]
687+ [ InlineData ( 6 , new int [ ] { } ) ]
688+ [ InlineData ( 7 , new int [ ] { } ) ]
689+ [ InlineData ( 8 , new int [ ] { } ) ]
690+ [ InlineData ( 9 , new int [ ] { } ) ]
691+ public void WhenHotAndWarmItemsExistTrimRemovesExpectedItemCount ( int itemCount , int [ ] expected )
692+ {
693+ // initial state:
694+ // Hot = 6, 5, 4
695+ // Warm = 3, 2, 1
696+ // Cold = -
697+ lru . AddOrUpdate ( 1 , "1" ) ;
698+ lru . AddOrUpdate ( 2 , "2" ) ;
699+ lru . AddOrUpdate ( 3 , "3" ) ;
700+ lru . GetOrAdd ( 1 , i => i . ToString ( ) ) ;
701+ lru . GetOrAdd ( 2 , i => i . ToString ( ) ) ;
702+ lru . GetOrAdd ( 3 , i => i . ToString ( ) ) ;
703+
704+ lru . AddOrUpdate ( 4 , "4" ) ;
705+ lru . AddOrUpdate ( 5 , "5" ) ;
706+ lru . AddOrUpdate ( 6 , "6" ) ;
707+
708+ lru . Trim ( itemCount ) ;
709+
710+ lru . Keys . Should ( ) . BeEquivalentTo ( expected ) ;
711+ }
712+
713+ [ Theory ]
714+ [ InlineData ( 1 , new [ ] { 3 , 2 } ) ]
715+ [ InlineData ( 2 , new [ ] { 3 } ) ]
716+ [ InlineData ( 3 , new int [ ] { } ) ]
717+ [ InlineData ( 4 , new int [ ] { } ) ]
718+ [ InlineData ( 5 , new int [ ] { } ) ]
719+ [ InlineData ( 6 , new int [ ] { } ) ]
720+ [ InlineData ( 7 , new int [ ] { } ) ]
721+ [ InlineData ( 8 , new int [ ] { } ) ]
722+ [ InlineData ( 9 , new int [ ] { } ) ]
723+ public void WhenHotItemsExistTrimRemovesExpectedItemCount ( int itemCount , int [ ] expected )
724+ {
725+ // initial state:
726+ // Hot = 3, 2, 1
727+ // Warm = -
728+ // Cold = -
729+ lru . AddOrUpdate ( 1 , "1" ) ;
730+ lru . AddOrUpdate ( 2 , "2" ) ;
731+ lru . AddOrUpdate ( 3 , "3" ) ;
732+
733+ lru . Trim ( itemCount ) ;
734+
735+ lru . Keys . Should ( ) . BeEquivalentTo ( expected ) ;
736+ }
737+
738+ [ Theory ]
739+ [ InlineData ( 1 , new [ ] { 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 } ) ]
740+ [ InlineData ( 2 , new [ ] { 9 , 8 , 7 , 6 , 5 , 4 , 3 } ) ]
741+ [ InlineData ( 3 , new [ ] { 9 , 8 , 7 , 6 , 5 , 4 } ) ]
742+ [ InlineData ( 4 , new [ ] { 9 , 8 , 7 , 6 , 5 } ) ]
743+ [ InlineData ( 5 , new [ ] { 9 , 8 , 7 , 6 } ) ]
744+ [ InlineData ( 6 , new [ ] { 9 , 8 , 7 } ) ]
745+ [ InlineData ( 7 , new [ ] { 9 , 8 } ) ]
746+ [ InlineData ( 8 , new [ ] { 9 } ) ]
747+ [ InlineData ( 9 , new int [ ] { } ) ]
748+ public void WhenColdItemsAreTouchedTrimRemovesExpectedItemCount ( int trimCount , int [ ] expected )
749+ {
750+ // initial state:
751+ // Hot = 9, 8, 7
752+ // Warm = 3, 2, 1
753+ // Cold = 6*, 5*, 4*
754+ lru . AddOrUpdate ( 1 , "1" ) ;
755+ lru . AddOrUpdate ( 2 , "2" ) ;
756+ lru . AddOrUpdate ( 3 , "3" ) ;
757+ lru . GetOrAdd ( 1 , i => i . ToString ( ) ) ;
758+ lru . GetOrAdd ( 2 , i => i . ToString ( ) ) ;
759+ lru . GetOrAdd ( 3 , i => i . ToString ( ) ) ;
760+
761+ lru . AddOrUpdate ( 4 , "4" ) ;
762+ lru . AddOrUpdate ( 5 , "5" ) ;
763+ lru . AddOrUpdate ( 6 , "6" ) ;
764+
765+ lru . AddOrUpdate ( 7 , "7" ) ;
766+ lru . AddOrUpdate ( 8 , "8" ) ;
767+ lru . AddOrUpdate ( 9 , "9" ) ;
768+
769+ // touch all items in the cold queue
770+ lru . GetOrAdd ( 4 , i => i . ToString ( ) ) ;
771+ lru . GetOrAdd ( 5 , i => i . ToString ( ) ) ;
772+ lru . GetOrAdd ( 6 , i => i . ToString ( ) ) ;
773+
774+ lru . Trim ( trimCount ) ;
775+
776+ this . testOutputHelper . WriteLine ( "LRU " + string . Join ( " " , lru . Keys ) ) ;
777+ this . testOutputHelper . WriteLine ( "exp " + string . Join ( " " , expected ) ) ;
778+
779+ lru . Keys . Should ( ) . BeEquivalentTo ( expected ) ;
780+ }
781+
782+ [ Fact ]
783+ public void WhenItemsAreDisposableTrimDisposesItems ( )
784+ {
785+ var lruOfDisposable = new ConcurrentLru < int , DisposableItem > ( 1 , 6 , EqualityComparer < int > . Default ) ;
786+
787+ var items = Enumerable . Range ( 1 , 4 ) . Select ( i => new DisposableItem ( ) ) . ToList ( ) ;
788+
789+ for ( int i = 0 ; i < 4 ; i ++ )
790+ {
791+ lruOfDisposable . AddOrUpdate ( i , items [ i ] ) ;
792+ }
793+
794+ lruOfDisposable . Trim ( 2 ) ;
795+
796+ items [ 0 ] . IsDisposed . Should ( ) . BeTrue ( ) ;
797+ items [ 1 ] . IsDisposed . Should ( ) . BeTrue ( ) ;
798+ items [ 2 ] . IsDisposed . Should ( ) . BeFalse ( ) ;
799+ items [ 3 ] . IsDisposed . Should ( ) . BeFalse ( ) ;
800+ }
801+
802+ [ Fact ]
803+ public void WhenItemsAreTrimmedAnEventIsFired ( )
804+ {
805+ var lruEvents = new ConcurrentLru < int , int > ( 1 , 9 , EqualityComparer < int > . Default ) ;
806+ lruEvents . ItemRemoved += OnLruItemRemoved ;
807+
808+ for ( int i = 0 ; i < 6 ; i ++ )
809+ {
810+ lruEvents . GetOrAdd ( i + 1 , i => i + 1 ) ;
811+ }
812+
813+ lruEvents . Trim ( 2 ) ;
814+
815+ removedItems . Count . Should ( ) . Be ( 2 ) ;
816+
817+ removedItems [ 0 ] . Key . Should ( ) . Be ( 1 ) ;
818+ removedItems [ 0 ] . Value . Should ( ) . Be ( 2 ) ;
819+ removedItems [ 0 ] . Reason . Should ( ) . Be ( ItemRemovedReason . Trimmed ) ;
820+
821+ removedItems [ 1 ] . Key . Should ( ) . Be ( 2 ) ;
822+ removedItems [ 1 ] . Value . Should ( ) . Be ( 3 ) ;
823+ removedItems [ 1 ] . Reason . Should ( ) . Be ( ItemRemovedReason . Trimmed ) ;
824+ }
611825 }
612826}
0 commit comments