feat(domain): add memory module with page pool, per-process tracking, and region table
This commit is contained in:
207
crates/domain/src/memory/tests.rs
Normal file
207
crates/domain/src/memory/tests.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
use super::page_pool::PagePool;
|
||||
use super::process_memory::ProcessMemory;
|
||||
use super::*;
|
||||
use types::address::PhysicalAddress;
|
||||
use types::bounded::PageCount;
|
||||
use types::generation::Generation;
|
||||
use types::id::{ProcessId, RegionId};
|
||||
|
||||
fn base() -> PhysicalAddress {
|
||||
PhysicalAddress::from_raw(0x8000_0000)
|
||||
}
|
||||
|
||||
fn process(id: u16) -> ProcessId {
|
||||
ProcessId::from_raw(id)
|
||||
}
|
||||
|
||||
fn pages(n: u16) -> PageCount {
|
||||
PageCount::new(n).unwrap()
|
||||
}
|
||||
|
||||
// --- PagePool tests ---
|
||||
|
||||
#[test]
|
||||
fn new_pool_has_all_pages_free() {
|
||||
let pool = PagePool::new(base(), 100);
|
||||
assert_eq!(pool.free_count(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_reduces_free_count() {
|
||||
let mut pool = PagePool::new(base(), 100);
|
||||
pool.allocate(10).unwrap();
|
||||
assert_eq!(pool.free_count(), 90);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_returns_base_aligned_address() {
|
||||
let mut pool = PagePool::new(base(), 100);
|
||||
let addr = pool.allocate(1).unwrap();
|
||||
assert_eq!(addr, base());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_sequential_returns_contiguous() {
|
||||
let mut pool = PagePool::new(base(), 100);
|
||||
let a = pool.allocate(4).unwrap();
|
||||
let b = pool.allocate(4).unwrap();
|
||||
assert_eq!(a, base());
|
||||
assert_eq!(b, base().offset(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_too_many_returns_none() {
|
||||
let mut pool = PagePool::new(base(), 10);
|
||||
assert!(pool.allocate(11).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn free_then_reallocate() {
|
||||
let mut pool = PagePool::new(base(), 10);
|
||||
let addr = pool.allocate(5).unwrap();
|
||||
assert_eq!(pool.free_count(), 5);
|
||||
assert!(pool.free(addr, 5));
|
||||
assert_eq!(pool.free_count(), 10);
|
||||
let addr2 = pool.allocate(5).unwrap();
|
||||
assert_eq!(addr2, base());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn free_out_of_range_returns_false() {
|
||||
let mut pool = PagePool::new(base(), 10);
|
||||
assert!(!pool.free(PhysicalAddress::from_raw(0), 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_fragmented_finds_gap() {
|
||||
let mut pool = PagePool::new(base(), 10);
|
||||
let a = pool.allocate(3).unwrap();
|
||||
let _b = pool.allocate(3).unwrap();
|
||||
let _c = pool.allocate(3).unwrap();
|
||||
pool.free(a, 3);
|
||||
// now pages 0-2 are free, 3-8 allocated, 9 free
|
||||
// asking for 3 contiguous should find 0-2
|
||||
let d = pool.allocate(3).unwrap();
|
||||
assert_eq!(d, base());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_exact_remaining() {
|
||||
let mut pool = PagePool::new(base(), 5);
|
||||
let addr = pool.allocate(5).unwrap();
|
||||
assert_eq!(addr, base());
|
||||
assert_eq!(pool.free_count(), 0);
|
||||
assert!(pool.allocate(1).is_none());
|
||||
}
|
||||
|
||||
// --- ProcessMemory tests ---
|
||||
|
||||
#[test]
|
||||
fn new_process_memory_has_zero_pages() {
|
||||
let pm = ProcessMemory::new(process(0), 100);
|
||||
assert_eq!(pm.page_count(), 0);
|
||||
assert_eq!(pm.limit(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grant_pages_within_limit() {
|
||||
let mut pm = ProcessMemory::new(process(0), 100);
|
||||
assert!(pm.grant(10).is_ok());
|
||||
assert_eq!(pm.page_count(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grant_pages_exceeding_limit_fails() {
|
||||
let mut pm = ProcessMemory::new(process(0), 10);
|
||||
assert!(pm.grant(11).is_err());
|
||||
assert_eq!(pm.page_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_pages_reduces_count() {
|
||||
let mut pm = ProcessMemory::new(process(0), 100);
|
||||
pm.grant(20).unwrap();
|
||||
assert!(pm.release(5).is_ok());
|
||||
assert_eq!(pm.page_count(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_more_than_owned_fails() {
|
||||
let mut pm = ProcessMemory::new(process(0), 100);
|
||||
pm.grant(5).unwrap();
|
||||
assert!(pm.release(10).is_err());
|
||||
assert_eq!(pm.page_count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grant_up_to_exact_limit() {
|
||||
let mut pm = ProcessMemory::new(process(0), 10);
|
||||
pm.grant(10).unwrap();
|
||||
assert!(pm.grant(1).is_err());
|
||||
}
|
||||
|
||||
// --- MemoryRegion tests ---
|
||||
|
||||
#[test]
|
||||
fn memory_region_construction_and_accessors() {
|
||||
let region = MemoryRegion::new(
|
||||
RegionId::from_raw(1),
|
||||
process(0),
|
||||
base(),
|
||||
pages(4),
|
||||
Generation::initial(),
|
||||
);
|
||||
assert_eq!(region.id(), RegionId::from_raw(1));
|
||||
assert_eq!(region.owner(), process(0));
|
||||
assert_eq!(region.base(), base());
|
||||
assert_eq!(region.size(), pages(4));
|
||||
assert_eq!(region.generation(), &Generation::initial());
|
||||
}
|
||||
|
||||
// --- RegionTable tests ---
|
||||
|
||||
#[test]
|
||||
fn region_table_insert_and_get() {
|
||||
let mut table = RegionTable::new();
|
||||
let id = table.insert(MemoryRegion::new(
|
||||
RegionId::from_raw(0),
|
||||
process(0),
|
||||
base(),
|
||||
pages(4),
|
||||
Generation::initial(),
|
||||
));
|
||||
assert!(id.is_some());
|
||||
let rid = id.unwrap();
|
||||
assert!(table.get(rid).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn region_table_remove() {
|
||||
let mut table = RegionTable::new();
|
||||
let id = table.insert(MemoryRegion::new(
|
||||
RegionId::from_raw(0),
|
||||
process(0),
|
||||
base(),
|
||||
pages(4),
|
||||
Generation::initial(),
|
||||
)).unwrap();
|
||||
let removed = table.remove(id);
|
||||
assert!(removed.is_some());
|
||||
assert!(table.get(id).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn region_table_regions_for_process() {
|
||||
let mut table = RegionTable::new();
|
||||
table.insert(MemoryRegion::new(
|
||||
RegionId::from_raw(0), process(0), base(), pages(4), Generation::initial(),
|
||||
));
|
||||
table.insert(MemoryRegion::new(
|
||||
RegionId::from_raw(1), process(1), base(), pages(4), Generation::initial(),
|
||||
));
|
||||
table.insert(MemoryRegion::new(
|
||||
RegionId::from_raw(2), process(0), base(), pages(2), Generation::initial(),
|
||||
));
|
||||
assert_eq!(table.regions_for_process(process(0)).count(), 2);
|
||||
assert_eq!(table.regions_for_process(process(1)).count(), 1);
|
||||
}
|
||||
Reference in New Issue
Block a user