use crate::soc::cache::policies::{
FifoPolicy, LruPolicy, MruPolicy, PlruPolicy, RandomPolicy, ReplacementPolicy,
};
#[test]
fn lru_initial_victim_is_last_way() {
let mut policy = LruPolicy::new(1, 4);
assert_eq!(policy.get_victim(0), 3);
}
#[test]
fn lru_sequential_access_reorders() {
let mut policy = LruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 2);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn lru_evicts_true_lru_after_reaccess() {
let mut policy = LruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 2);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 2);
}
#[test]
fn lru_repeated_access_same_way() {
let mut policy = LruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 2);
policy.update(0, 3);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn lru_independent_sets() {
let mut policy = LruPolicy::new(2, 4);
for w in 0..4 {
policy.update(0, w);
}
assert_eq!(policy.get_victim(0), 0);
assert_eq!(policy.get_victim(1), 3);
for w in (0..4).rev() {
policy.update(1, w);
}
assert_eq!(policy.get_victim(1), 3);
}
#[test]
fn lru_two_way() {
let mut policy = LruPolicy::new(1, 2);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
}
#[test]
fn fifo_round_robin_eviction_order() {
let mut policy = FifoPolicy::new(1, 4);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 2);
policy.update(0, 2);
assert_eq!(policy.get_victim(0), 3);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn fifo_access_non_head_ignored() {
let mut policy = FifoPolicy::new(1, 4);
policy.update(0, 2);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn fifo_access_head_advances_pointer() {
let mut policy = FifoPolicy::new(1, 4);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
}
#[test]
fn fifo_wraps_two_way() {
let mut policy = FifoPolicy::new(1, 2);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 0); }
#[test]
fn plru_initial_victim_is_zero() {
let mut policy = PlruPolicy::new(1, 4);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn plru_access_protects_way() {
let mut policy = PlruPolicy::new(1, 4);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 2);
policy.update(0, 2);
assert_eq!(policy.get_victim(0), 3);
}
#[test]
fn plru_wraps_when_all_bits_set() {
let mut policy = PlruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 2);
assert_eq!(policy.get_victim(0), 3);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn plru_reaccess_way() {
let mut policy = PlruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 2);
}
#[test]
fn plru_two_way() {
let mut policy = PlruPolicy::new(1, 2);
assert_eq!(policy.get_victim(0), 0);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn mru_initial_victim() {
let mut policy = MruPolicy::new(1, 4);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn mru_evicts_most_recently_used() {
let mut policy = MruPolicy::new(1, 4);
policy.update(0, 2);
assert_eq!(policy.get_victim(0), 2, "MRU should evict the most recently used way");
policy.update(0, 1);
assert_eq!(policy.get_victim(0), 1);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 3);
}
#[test]
fn mru_sequential_access() {
let mut policy = MruPolicy::new(1, 4);
for w in 0..4 {
policy.update(0, w);
assert_eq!(policy.get_victim(0), w);
}
}
#[test]
fn mru_opposite_of_lru() {
let mut policy = MruPolicy::new(1, 4);
policy.update(0, 0);
policy.update(0, 1);
policy.update(0, 2);
policy.update(0, 3);
assert_eq!(policy.get_victim(0), 3);
policy.update(0, 0);
assert_eq!(policy.get_victim(0), 0);
}
#[test]
fn random_victim_always_in_range() {
let ways = 4;
let mut policy = RandomPolicy::new(1, ways);
for _ in 0..200 {
let victim = policy.get_victim(0);
assert!(victim < ways, "Victim {} out of range [0, {})", victim, ways);
}
}
#[test]
fn random_victim_various_way_counts() {
for ways in [1, 2, 3, 4, 8, 16] {
let mut policy = RandomPolicy::new(1, ways);
for _ in 0..50 {
let victim = policy.get_victim(0);
assert!(victim < ways, "ways={}, victim {} out of range", ways, victim);
}
}
}
#[test]
fn random_update_is_noop() {
let mut policy = RandomPolicy::new(1, 4);
let v1 = policy.get_victim(0);
policy.update(0, v1);
let v2 = policy.get_victim(0);
assert!(v1 < 4);
assert!(v2 < 4);
}
#[test]
fn random_not_stuck() {
let mut policy = RandomPolicy::new(1, 8);
let mut seen = std::collections::HashSet::new();
for _ in 0..100 {
seen.insert(policy.get_victim(0));
}
assert!(
seen.len() > 1,
"Random policy produced only {} distinct values over 100 calls",
seen.len()
);
}