use super::NumaBuffer;
use crate::NumaNode;
const ABSURD_NODE: u32 = u32::MAX - 1;
#[test]
fn an_unplaced_buffer_allocates() {
let buffer = NumaBuffer::new(4096, None).expect("an unplaced allocation");
assert!(!buffer.as_ptr().is_null());
}
#[test]
fn node_zero_allocates() {
let buffer = NumaBuffer::new(4096, Some(NumaNode::new(0))).expect("node 0 exists everywhere");
assert!(!buffer.as_ptr().is_null());
}
#[test]
fn the_reported_length_is_the_requested_one_not_the_rounded_one() {
for len in [1_usize, 100, 4095, 4096, 4097, 65536] {
let buffer = NumaBuffer::new(len, None).expect("a valid allocation");
assert_eq!(buffer.len(), len, "for a request of {len} bytes");
}
}
#[test]
fn a_fresh_allocation_is_zeroed() {
let mut buffer = NumaBuffer::new(8192, None).expect("a valid allocation");
let bytes = unsafe { std::slice::from_raw_parts(buffer.as_mut_ptr(), buffer.len()) };
assert!(bytes.iter().all(|&b| b == 0));
}
#[test]
fn bytes_written_read_back() {
let mut buffer = NumaBuffer::new(4096, None).expect("a valid allocation");
let len = buffer.len();
let bytes = unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr(), len) };
for (index, byte) in bytes.iter_mut().enumerate() {
*byte = (index % 251) as u8;
}
let read = unsafe { std::slice::from_raw_parts(buffer.as_ptr(), len) };
assert!(read.iter().enumerate().all(|(i, &b)| b == (i % 251) as u8));
}
#[test]
fn the_address_is_stable_across_reads() {
let mut buffer = NumaBuffer::new(4096, None).expect("a valid allocation");
let first = buffer.as_ptr();
assert_eq!(buffer.as_ptr(), first);
assert_eq!(buffer.as_mut_ptr().cast_const(), first);
assert_eq!(buffer.as_ptr(), first);
}
#[test]
fn an_address_survives_a_move() {
let buffer = NumaBuffer::new(4096, None).expect("a valid allocation");
let before = buffer.as_ptr();
let moved = buffer;
assert_eq!(moved.as_ptr(), before);
}
#[test]
fn separate_buffers_do_not_alias() {
let buffers: Vec<NumaBuffer> = (0..8)
.map(|_| NumaBuffer::new(4096, None).expect("a valid allocation"))
.collect();
let mut addresses: Vec<*const u8> = buffers.iter().map(NumaBuffer::as_ptr).collect();
addresses.sort_unstable();
let before = addresses.len();
addresses.dedup();
assert_eq!(addresses.len(), before, "every slot must be its own memory");
}
#[test]
fn a_zero_length_request_is_refused() {
let error = NumaBuffer::new(0, None).expect_err("a zero-length mapping is not allocatable");
assert!(error.raw_os_error().is_some(), "and it is an OS error");
}
#[test]
fn a_node_the_machine_does_not_have_is_refused() {
let error = NumaBuffer::new(4096, Some(NumaNode::new(ABSURD_NODE)))
.expect_err("no machine has this node number");
assert!(error.raw_os_error().is_some(), "and it is an OS error");
}
#[test]
fn a_request_the_address_space_cannot_hold_is_refused() {
let error = NumaBuffer::new(usize::MAX, None).expect_err("no process has this much space");
assert!(error.raw_os_error().is_some(), "and it is an OS error");
}
#[test]
fn a_refused_allocation_leaves_the_allocator_usable() {
let _ = NumaBuffer::new(4096, Some(NumaNode::new(ABSURD_NODE))).expect_err("refused");
let buffer = NumaBuffer::new(4096, None).expect("the next allocation still works");
assert!(!buffer.as_ptr().is_null());
}
#[test]
fn many_buffers_allocate_and_free() {
for _ in 0..512 {
let buffer = NumaBuffer::new(65536, None).expect("a valid allocation");
assert!(!buffer.as_ptr().is_null());
}
}
#[test]
fn a_buffer_is_send() {
fn assert_send<T: Send>() {}
assert_send::<NumaBuffer>();
let buffer = NumaBuffer::new(4096, None).expect("a valid allocation");
let address = buffer.as_ptr() as usize;
let moved = std::thread::spawn(move || buffer.as_ptr() as usize)
.join()
.expect("the thread completes");
assert_eq!(moved, address, "and the address travels with it");
}