use crate::util::address::{Address, ByteSize};
use crate::util::heap::layout::vm_layout::*;
use std::panic;
use std::sync::mpsc;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
#[cfg(feature = "mock_test")]
pub mod fixtures;
#[cfg(feature = "mock_test")]
pub mod mock_method;
#[cfg(feature = "mock_test")]
pub mod mock_vm;
pub(crate) struct MmapTestRegion {
pub start: Address,
pub size: ByteSize,
}
impl MmapTestRegion {
pub const fn reserve_before(prev: MmapTestRegion, size: ByteSize) -> MmapTestRegion {
Self::reserve_before_address(prev.start, size)
}
pub const fn reserve_before_address(addr: Address, size: ByteSize) -> MmapTestRegion {
MmapTestRegion {
start: addr.sub(size),
size,
}
}
}
#[cfg(test)]
mod test {
#[test]
fn verify_test_address() {
assert!(
super::TEST_ADDRESS.as_usize()
<= crate::util::heap::layout::vm_layout::vm_layout()
.heap_start
.as_usize()
);
}
}
#[cfg(target_os = "linux")]
const TEST_ADDRESS: Address =
crate::util::conversions::chunk_align_down(unsafe { Address::from_usize(0x7000_0000) });
#[cfg(target_os = "macos")]
const TEST_ADDRESS: Address =
crate::util::conversions::chunk_align_down(unsafe { Address::from_usize(0x2_0000_0000) });
pub(crate) const CHUNK_STATE_MMAPPER_TEST_REGION: MmapTestRegion =
MmapTestRegion::reserve_before_address(TEST_ADDRESS, BYTES_IN_CHUNK * 2);
pub(crate) const MEMORY_TEST_REGION: MmapTestRegion =
MmapTestRegion::reserve_before(CHUNK_STATE_MMAPPER_TEST_REGION, BYTES_IN_CHUNK);
pub(crate) const RAW_MEMORY_FREELIST_TEST_REGION: MmapTestRegion =
MmapTestRegion::reserve_before(MEMORY_TEST_REGION, BYTES_IN_CHUNK);
pub fn panic_after<T, F>(millis: u64, f: F) -> T
where
T: Send + 'static,
F: FnOnce() -> T,
F: Send + 'static,
{
let (done_tx, done_rx) = mpsc::channel();
let handle = thread::spawn(move || {
let val = f();
done_tx.send(()).expect("Unable to send completion signal");
val
});
match done_rx.recv_timeout(Duration::from_millis(millis)) {
Ok(_) => handle.join().expect("Thread panicked"),
Err(e) => panic!("Thread took too long: {}", e),
}
}
lazy_static! {
static ref SERIAL_TEST_LOCK: Mutex<()> = Mutex::default();
}
pub fn serial_test<F>(f: F)
where
F: FnOnce(),
{
let _guard = SERIAL_TEST_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
f();
}
pub fn with_cleanup<T, C>(test: T, cleanup: C)
where
T: FnOnce() + panic::UnwindSafe,
C: FnOnce(),
{
let res = panic::catch_unwind(test);
cleanup();
if let Err(e) = res {
panic::resume_unwind(e);
}
}