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); }