Skip to content

Commit 4831d47

Browse files
committed
test: add LRU proptest
1 parent 2e683a3 commit 4831d47

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

stacks-common/src/util/lru_cache.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,46 @@ mod tests {
304304

305305
assert_eq!(flushed, [(3, 3), (2, 2)]);
306306
}
307+
308+
pub struct SimpleLRU {
309+
pub cache: Vec<u32>,
310+
capacity: usize,
311+
}
312+
313+
impl SimpleLRU {
314+
pub fn new(capacity: usize) -> Self {
315+
SimpleLRU {
316+
cache: Vec::with_capacity(capacity),
317+
capacity,
318+
}
319+
}
320+
321+
pub fn insert(&mut self, key: u32) {
322+
if let Some(pos) = self.cache.iter().position(|&x| x == key) {
323+
self.cache.remove(pos);
324+
} else if self.cache.len() == self.capacity {
325+
self.cache.remove(0);
326+
}
327+
self.cache.push(key);
328+
}
329+
330+
pub fn get(&mut self, key: u32) -> Option<u32> {
331+
if let Some(pos) = self.cache.iter().position(|&x| x == key) {
332+
self.cache.remove(pos);
333+
self.cache.push(key);
334+
Some(key)
335+
} else {
336+
None
337+
}
338+
}
339+
}
307340
}
308341

309342
#[cfg(test)]
310343
mod property_tests {
311344
use proptest::prelude::*;
312345

346+
use super::tests::SimpleLRU;
313347
use super::*;
314348

315349
#[derive(Debug, Clone)]
@@ -359,7 +393,7 @@ mod property_tests {
359393
}
360394

361395
#[test]
362-
fn maintains_lru_order(ops in prop::collection::vec(arbitrary_op(), 1..1000)) {
396+
fn maintains_linked_list_integrity(ops in prop::collection::vec(arbitrary_op(), 1..1000)) {
363397
let mut cache = LruCache::new(10);
364398
for op in ops {
365399
match op {
@@ -385,5 +419,43 @@ mod property_tests {
385419
}
386420
}
387421
}
422+
423+
#[test]
424+
fn maintains_lru_correctness(ops in prop::collection::vec(arbitrary_op(), 1..1000)) {
425+
let mut cache = LruCache::new(5);
426+
let mut simple = SimpleLRU::new(5);
427+
for op in ops {
428+
match op {
429+
CacheOp::Insert(v) => {
430+
cache.insert(v, v);
431+
simple.insert(v);
432+
}
433+
CacheOp::Get(v) => {
434+
let actual = cache.get(&v);
435+
let expected = simple.get(v);
436+
prop_assert_eq!(actual, expected);
437+
}
438+
CacheOp::InsertClean(v) => {
439+
cache.insert_clean(v, v);
440+
simple.insert(v);
441+
}
442+
CacheOp::Flush => cache.flush(|_, _| Ok::<(), ()>(())).unwrap(),
443+
};
444+
445+
// The cache should have the same order as the simple LRU
446+
let mut curr = cache.head;
447+
let mut count = 0;
448+
while curr != cache.capacity {
449+
if count >= cache.order.len() {
450+
prop_assert!(false, "Linked list cycle detected");
451+
}
452+
let idx = simple.cache.len() - count - 1;
453+
prop_assert_eq!(cache.order[curr].key, simple.cache[idx]);
454+
prop_assert_eq!(cache.order[curr].value, simple.cache[idx]);
455+
curr = cache.order[curr].next;
456+
count += 1;
457+
}
458+
}
459+
}
388460
}
389461
}

0 commit comments

Comments
 (0)