@@ -2,6 +2,7 @@ use super::*;
2
2
use proptest:: prelude:: * ;
3
3
use std:: collections:: BTreeMap ;
4
4
use std:: collections:: HashMap ;
5
+ use std:: collections:: HashSet ;
5
6
6
7
fn key_value_pairs (
7
8
min_pairs : usize ,
@@ -163,7 +164,178 @@ fn test_empty_triemap_behavior() {
163
164
}
164
165
165
166
proptest ! {
166
- #[ test]
167
+
168
+ #[ test]
169
+ fn pruning_preserves_values( pairs in key_value_pairs( 1 , 100 ) , to_remove in key_value_pairs( 1 , 50 ) ) {
170
+ let mut trie = TrieMap :: new( ) ;
171
+ let mut reference_map = BTreeMap :: new( ) ;
172
+
173
+ for ( key, value) in & pairs {
174
+ trie. insert( key, * value) ;
175
+ reference_map. insert( key. clone( ) , * value) ;
176
+ }
177
+
178
+ for ( key, _) in & to_remove {
179
+ trie. remove( key) ;
180
+ reference_map. remove( key) ;
181
+ }
182
+
183
+ trie. prune( ) ;
184
+
185
+ for ( key, expected_value) in & reference_map {
186
+ prop_assert_eq!( trie. get( key) , Some ( expected_value) ) ;
187
+ }
188
+
189
+ for ( key, _) in & to_remove {
190
+ if !reference_map. contains_key( key) {
191
+ prop_assert_eq!( trie. get( key) , None ) ;
192
+ }
193
+ }
194
+
195
+ prop_assert_eq!( trie. len( ) , reference_map. len( ) ) ;
196
+ }
197
+ // Test that multiple prune operations are idempotent
198
+ #[ test]
199
+ fn multiple_prunes_are_idempotent(
200
+ pairs in key_value_pairs( 1 , 100 ) ,
201
+ to_remove in key_value_pairs( 1 , 50 )
202
+ ) {
203
+ let mut trie = TrieMap :: new( ) ;
204
+
205
+ // Insert all pairs
206
+ for ( key, value) in & pairs {
207
+ trie. insert( key, * value) ;
208
+ }
209
+
210
+ // Remove some keys
211
+ for ( key, _) in & to_remove {
212
+ trie. remove( key) ;
213
+ }
214
+
215
+ // First prune
216
+ let first_pruned = trie. prune( ) ;
217
+ let size_after_first = trie. len( ) ;
218
+
219
+ // Second prune
220
+ let second_pruned = trie. prune( ) ;
221
+ let size_after_second = trie. len( ) ;
222
+
223
+ // The second prune should not remove any nodes
224
+ prop_assert_eq!( second_pruned, 0 ) ;
225
+
226
+ // Sizes should be the same
227
+ prop_assert_eq!( size_after_first, size_after_second) ;
228
+ }
229
+
230
+ #[ test]
231
+ fn removal_works_correctly( pairs in key_value_pairs( 5 , 100 ) ) {
232
+ let mut trie = TrieMap :: new( ) ;
233
+ let mut reference_map = BTreeMap :: new( ) ;
234
+
235
+ // Insert all pairs
236
+ for ( key, value) in & pairs {
237
+ trie. insert( key, * value) ;
238
+ reference_map. insert( key. clone( ) , * value) ;
239
+ }
240
+
241
+ // Get the unique keys that were actually inserted (last value wins for duplicates)
242
+ let unique_keys: Vec <String > = reference_map. keys( ) . cloned( ) . collect( ) ;
243
+
244
+ // Remove half of the unique keys
245
+ let mut removed = 0 ;
246
+ for ( i, key) in unique_keys. iter( ) . enumerate( ) {
247
+ if i % 2 == 0 { // Only remove every other key
248
+ let expected_value = reference_map. get( key) . copied( ) ;
249
+ let trie_removed = trie. remove( key) ;
250
+ let ref_removed = reference_map. remove( key) ;
251
+
252
+ // The removed value should match between trie and reference map
253
+ prop_assert_eq!( trie_removed, ref_removed) ;
254
+ // And should match what we expected to remove
255
+ prop_assert_eq!( trie_removed, expected_value) ;
256
+
257
+ removed += 1 ;
258
+ }
259
+ }
260
+
261
+ // Check that the size is correct
262
+ prop_assert_eq!( trie. len( ) , reference_map. len( ) ) ;
263
+
264
+ // Check that all remaining keys are accessible
265
+ for ( key, value) in & reference_map {
266
+ prop_assert_eq!( trie. get( key) , Some ( value) ) ;
267
+ }
268
+
269
+ // Check that removed keys are not accessible
270
+ for ( i, key) in unique_keys. iter( ) . enumerate( ) {
271
+ if i % 2 == 0 { // These were removed
272
+ prop_assert_eq!( trie. get( key) , None ) ;
273
+ }
274
+ }
275
+ }
276
+
277
+ #[ test]
278
+ fn iteration_after_removal_is_correct(
279
+ pairs in key_value_pairs( 5 , 100 ) ,
280
+ removal_indices in proptest:: collection:: vec( 0 ..100usize , 1 ..50 )
281
+ ) {
282
+ let mut trie = TrieMap :: new( ) ;
283
+ let mut reference_map = BTreeMap :: new( ) ;
284
+
285
+ // Insert all pairs
286
+ for ( key, value) in & pairs {
287
+ trie. insert( key, * value) ;
288
+ reference_map. insert( key. clone( ) , * value) ;
289
+ }
290
+
291
+ // Create list of keys to remove (using indices to prevent duplicates)
292
+ let keys_to_remove: Vec <String > = removal_indices. iter( )
293
+ . filter( |& idx| * idx < pairs. len( ) )
294
+ . map( |& idx| pairs[ idx] . 0 . clone( ) )
295
+ . collect( ) ;
296
+
297
+ // Remove selected keys
298
+ for key in & keys_to_remove {
299
+ trie. remove( key) ;
300
+ reference_map. remove( key) ;
301
+ }
302
+
303
+ // Get all key-value pairs from trie iteration
304
+ let mut trie_pairs: Vec <( String , i32 ) > = trie. iter( )
305
+ . map( |( k, & v) | ( String :: from_utf8( k) . unwrap( ) , v) )
306
+ . collect( ) ;
307
+
308
+ // Get all key-value pairs from reference map
309
+ let mut ref_pairs: Vec <( String , i32 ) > = reference_map
310
+ . iter( )
311
+ . map( |( k, & v) | ( k. clone( ) , v) )
312
+ . collect( ) ;
313
+
314
+ // Sort both for comparison
315
+ trie_pairs. sort_by( |( k1, _) , ( k2, _) | k1. cmp( k2) ) ;
316
+ ref_pairs. sort_by( |( k1, _) , ( k2, _) | k1. cmp( k2) ) ;
317
+
318
+ // They should be equal
319
+ prop_assert_eq!( trie_pairs, ref_pairs) ;
320
+
321
+ // Size should match
322
+ prop_assert_eq!( trie. len( ) , reference_map. len( ) ) ;
323
+
324
+ // Check iterator count matches expected count
325
+ prop_assert_eq!( trie. iter( ) . count( ) , reference_map. len( ) ) ;
326
+
327
+ // Also check keys() and values() iterators
328
+ prop_assert_eq!( trie. keys( ) . count( ) , reference_map. len( ) ) ;
329
+ prop_assert_eq!( trie. values( ) . count( ) , reference_map. len( ) ) ;
330
+
331
+ // Verify removed keys are not present
332
+ for key in & keys_to_remove {
333
+ prop_assert_eq!( trie. get( key) , None ) ;
334
+ prop_assert!( !trie. keys( ) . any( |k| String :: from_utf8( k) . unwrap( ) == * key) ) ;
335
+ }
336
+ }
337
+
338
+ #[ test]
167
339
fn triemap_correctly_handles_common_prefixes(
168
340
pairs in prefixed_keys( vec![ "app" , "ban" , "car" , "dog" ] , 5 , 50 )
169
341
) {
0 commit comments