@@ -89,4 +89,84 @@ describe("VipCache", () => {
8989 expect ( entries [ 0 ] [ 1 ] . accessCount ) . toBe ( 3 ) ;
9090 expect ( entries [ 0 ] [ 1 ] . lastAccess ) . toBeGreaterThan ( 0 ) ;
9191 } ) ;
92+
93+ it ( "acquire/release prevents eviction" , ( ) => {
94+ const cache = new VipCache < string , number > ( 2 , 10 ) ;
95+ cache . set ( "a" , 1 ) ;
96+ cache . set ( "b" , 2 ) ;
97+
98+ const val = cache . acquire ( "a" ) ;
99+ expect ( val ) . toBe ( 1 ) ;
100+
101+ // Insert 3rd — "a" has refCount=1, should not be evicted
102+ cache . set ( "c" , 3 ) ;
103+ expect ( cache . has ( "a" ) ) . toBe ( true ) ;
104+ expect ( cache . has ( "b" ) ) . toBe ( false ) ; // "b" evicted instead
105+ expect ( cache . has ( "c" ) ) . toBe ( true ) ;
106+
107+ cache . release ( "a" ) ;
108+ } ) ;
109+
110+ it ( "delete with refCount>0 defers deletion" , ( ) => {
111+ const cache = new VipCache < string , number > ( 10 ) ;
112+ cache . set ( "a" , 1 ) ;
113+ cache . acquire ( "a" ) ;
114+
115+ cache . delete ( "a" ) ;
116+ // Entry is pending eviction but still in map until release
117+ expect ( cache . size ) . toBe ( 1 ) ;
118+
119+ cache . release ( "a" ) ;
120+ // Now actually removed
121+ expect ( cache . size ) . toBe ( 0 ) ;
122+ expect ( cache . has ( "a" ) ) . toBe ( false ) ;
123+ } ) ;
124+
125+ it ( "invalidateByPrefix defers deletion for acquired entries" , ( ) => {
126+ const cache = new VipCache < string , number > ( 10 ) ;
127+ cache . set ( "tbl/a" , 1 ) ;
128+ cache . set ( "tbl/b" , 2 ) ;
129+ cache . set ( "other" , 3 ) ;
130+
131+ cache . acquire ( "tbl/a" ) ;
132+ const count = cache . invalidateByPrefix ( "tbl/" ) ;
133+ expect ( count ) . toBe ( 2 ) ;
134+
135+ // "tbl/b" deleted immediately, "tbl/a" deferred
136+ expect ( cache . has ( "tbl/b" ) ) . toBe ( false ) ;
137+ expect ( cache . size ) . toBe ( 2 ) ; // "tbl/a" (pending) + "other"
138+
139+ cache . release ( "tbl/a" ) ;
140+ expect ( cache . size ) . toBe ( 1 ) ; // only "other"
141+ } ) ;
142+
143+ it ( "set() clears expiresAt from previous setWithTTL()" , ( ) => {
144+ const cache = new VipCache < string , number > ( 10 ) ;
145+ cache . setWithTTL ( "a" , 1 , 1 ) ; // 1ms TTL
146+
147+ // Overwrite with set() — should clear TTL
148+ cache . set ( "a" , 2 ) ;
149+
150+ // Wait past the original TTL
151+ const start = Date . now ( ) ;
152+ while ( Date . now ( ) - start < 5 ) { /* spin */ }
153+
154+ // Entry should still be accessible (TTL cleared)
155+ expect ( cache . get ( "a" ) ) . toBe ( 2 ) ;
156+ } ) ;
157+
158+ it ( "get() does not delete expired entry with refCount>0" , ( ) => {
159+ const cache = new VipCache < string , number > ( 10 ) ;
160+ cache . setWithTTL ( "a" , 1 , 1 ) ; // 1ms TTL
161+ cache . acquire ( "a" ) ;
162+
163+ const start = Date . now ( ) ;
164+ while ( Date . now ( ) - start < 5 ) { /* spin */ }
165+
166+ // get() returns undefined (expired) but does not delete (refCount > 0)
167+ expect ( cache . get ( "a" ) ) . toBeUndefined ( ) ;
168+ expect ( cache . size ) . toBe ( 1 ) ; // still in map
169+
170+ cache . release ( "a" ) ;
171+ } ) ;
92172} ) ;
0 commit comments