use redoubt_util::is_vec_fully_zeroized;
use redoubt_zero::{AssertZeroizeOnDrop, ZeroizationProbe};
use crate::allocked_vec::{AllockedVec, AllockedVecBehaviour};
use crate::error::AllockedVecError;
#[test]
fn test_allocked_vec_with_capacity_seals_allocked_vec() {
let vec: AllockedVec<u8> = AllockedVec::with_capacity(10);
assert_eq!(vec.len(), 0);
assert_eq!(vec.capacity(), 10);
assert!(!vec.is_zeroized());
let mut vec = vec;
let result = vec.reserve_exact(20);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::AlreadySealed)));
}
#[test]
fn test_allocked_vec_reserve_exact_seals_vector() {
let mut vec: AllockedVec<u8> = AllockedVec::default();
assert!(vec.is_zeroized());
vec.reserve_exact(5).expect("Failed to reserve_exact");
assert_eq!(vec.capacity(), 5);
assert!(!vec.is_zeroized());
let result = vec.reserve_exact(10);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::AlreadySealed)));
}
#[test]
fn test_allocked_vec_capacity_is_zeroed_on_creation() {
let mut vec = AllockedVec::<u8>::new();
assert!(vec.is_zeroized());
vec.reserve_exact(100).expect("Failed to reserve");
assert!(!vec.is_zeroized());
let slice = unsafe { vec.as_capacity_slice() };
assert_eq!(slice.len(), 100);
assert!(slice.iter().all(|&b| b == 0));
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_push_within_capacity() {
let mut vec = AllockedVec::with_capacity(3);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
vec.push(3u8).expect("Failed to vec.push(3)");
assert_eq!(vec.len(), 3);
assert_eq!(vec.as_slice(), &[1, 2, 3]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_push_exceeds_capacity() {
let mut vec = AllockedVec::with_capacity(2);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
let result = vec.push(3u8);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
assert_eq!(vec.as_slice(), &[1, 2]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_as_slice_and_as_mut_slice() {
let mut vec = AllockedVec::with_capacity(3);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
assert_eq!(vec.as_slice(), &[1, 2]);
vec.as_mut_slice()[0] = 42;
assert_eq!(vec.as_slice(), &[42, 2]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_truncate_zeroizes_removed_elements() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(0u8).expect("Failed to push");
vec.push(0u8).expect("Failed to push");
vec.push(0u8).expect("Failed to push");
vec.push(1u8).expect("Failed to push");
vec.push(2u8).expect("Failed to push");
vec.__unsafe_expose_inner_for_tests(|inner| {
assert!(!is_vec_fully_zeroized(inner));
});
vec.truncate(3);
vec.__unsafe_expose_inner_for_tests(|inner| {
assert!(is_vec_fully_zeroized(inner));
});
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_drain_from_success() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
let mut data = vec![1u8, 2, 3, 4, 5];
assert_eq!(vec.len(), 0);
vec.drain_from(&mut data).expect("Failed to drain_from");
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5]);
assert!(data.iter().all(|&x| x == 0));
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_drain_from_exceeds_capacity() {
let mut vec = AllockedVec::with_capacity(3);
assert!(!vec.is_zeroized());
let mut data = vec![1u8, 2, 3, 4, 5];
let result = vec.drain_from(&mut data);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
assert_eq!(vec.len(), 0);
assert_eq!(data, [1, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_drain_from_partial_fill() {
let mut vec = AllockedVec::with_capacity(10);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
let mut data = vec![3u8, 4, 5];
vec.drain_from(&mut data).expect("Failed to drain_from");
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_realloc_with_noop_when_sufficient() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
let mut hook_has_been_called = false;
vec.realloc_with(5, |_| {
hook_has_been_called = true;
});
assert!(!hook_has_been_called);
assert_eq!(vec.capacity(), 5);
assert_eq!(vec.as_slice(), [1, 2]);
assert!(!vec.is_zeroized());
vec.realloc_with_capacity(3);
assert_eq!(vec.capacity(), 3);
assert_eq!(vec.as_slice(), [1, 2]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_realloc_with_zeroizes_old_allocation() {
let mut vec = AllockedVec::with_capacity(2);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
let result = vec.push(3u8);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
let mut hook_has_been_called = false;
vec.realloc_with(5, |old_allocked_vec| {
old_allocked_vec.__unsafe_expose_inner_for_tests(|vec| {
hook_has_been_called = true;
assert!(is_vec_fully_zeroized(vec));
});
});
assert!(hook_has_been_called);
assert!(!vec.is_zeroized());
vec.push(3u8).expect("Failed to vec.push(3)");
vec.push(4u8).expect("Failed to vec.push(4)");
vec.push(5u8).expect("Failed to vec.push(5)");
assert_eq!(vec.as_slice(), [1u8, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_realloc_with_capacity_noop_when_sufficient() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
vec.realloc_with_capacity(5);
assert_eq!(vec.capacity(), 5);
assert_eq!(vec.as_slice(), [1, 2]);
assert!(!vec.is_zeroized());
vec.realloc_with_capacity(3);
assert_eq!(vec.capacity(), 3);
assert_eq!(vec.as_slice(), [1, 2]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_realloc_with_capacity_preserves_len() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
vec.push(3u8).expect("Failed to vec.push(3)");
vec.push(4u8).expect("Failed to vec.push(4)");
vec.push(5u8).expect("Failed to vec.push(5)");
vec.realloc_with_capacity(10);
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), [1, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_realloc_with_capacity_ok() {
let mut vec = AllockedVec::with_capacity(0);
assert!(!vec.is_zeroized());
vec.realloc_with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
vec.push(3u8).expect("Failed to vec.push(3)");
vec.push(4u8).expect("Failed to vec.push(4)");
vec.push(5u8).expect("Failed to vec.push(5)");
assert_eq!(vec.as_slice(), [1, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_fill_with_default_empty_vec() {
let mut vec = AllockedVec::<u8>::with_capacity(5);
assert!(!vec.is_zeroized());
assert_eq!(vec.len(), 0);
vec.fill_with_default();
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), [0, 0, 0, 0, 0]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_fill_with_default_partial_vec() {
let mut vec = AllockedVec::<u8>::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1).expect("push failed");
vec.push(2).expect("push failed");
assert_eq!(vec.len(), 2);
vec.fill_with_default();
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), [1, 2, 0, 0, 0]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_fill_with_default_full_vec() {
let mut vec = AllockedVec::<u8>::with_capacity(3);
assert!(!vec.is_zeroized());
vec.push(1).expect("push failed");
vec.push(2).expect("push failed");
vec.push(3).expect("push failed");
assert_eq!(vec.len(), 3);
vec.fill_with_default();
assert_eq!(vec.len(), 3);
assert_eq!(vec.as_slice(), [1, 2, 3]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_behaviour_fail_at_push() {
let mut vec = AllockedVec::with_capacity(10);
assert!(!vec.is_zeroized());
vec.change_behaviour(AllockedVecBehaviour::FailAtPush);
let result = vec.push(1u8);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
let result = vec.push(2u8);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
vec.change_behaviour(AllockedVecBehaviour::None);
vec.push(1u8).expect("Failed to vec.push(1)");
assert_eq!(vec.as_slice(), &[1]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_behaviour_fail_at_drain_from() {
let mut vec = AllockedVec::with_capacity(10);
assert!(!vec.is_zeroized());
let mut data = vec![1u8, 2, 3];
vec.change_behaviour(AllockedVecBehaviour::FailAtDrainFrom);
let result = vec.drain_from(&mut data);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
assert_eq!(data, [1, 2, 3]);
let result = vec.drain_from(&mut data);
assert!(result.is_err());
assert!(matches!(result, Err(AllockedVecError::CapacityExceeded)));
vec.change_behaviour(AllockedVecBehaviour::None);
vec.drain_from(&mut data).expect("Failed to drain_from");
assert_eq!(vec.as_slice(), &[1, 2, 3]);
assert!(data.iter().all(|&x| x == 0));
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_as_mut_ptr_write_single_byte() {
let mut vec = AllockedVec::<u8>::with_capacity(1);
assert!(!vec.is_zeroized());
vec.push(0u8).expect("Failed to push initial byte");
let ptr = vec.as_mut_ptr();
unsafe {
*ptr = 0x42;
}
assert_eq!(vec.as_slice(), &[0x42]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_as_capacity_slice_returns_full_capacity() {
let mut vec = AllockedVec::<u8>::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to push");
vec.push(2u8).expect("Failed to push");
assert_eq!(vec.len(), 2);
assert_eq!(vec.capacity(), 5);
let slice = unsafe { vec.as_capacity_slice() };
assert_eq!(slice.len(), 5);
assert_eq!(&slice[..2], &[1, 2]);
assert_eq!(&slice[2..], &[0, 0, 0]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_as_capacity_mut_slice_allows_writing_beyond_len() {
let mut vec = AllockedVec::<u8>::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to push");
vec.push(2u8).expect("Failed to push");
let slice = unsafe { vec.as_capacity_mut_slice() };
slice[2] = 3;
slice[3] = 4;
slice[4] = 5;
assert_eq!(vec.len(), 2);
let slice = unsafe { vec.as_capacity_slice() };
assert_eq!(slice, &[1, 2, 3, 4, 5]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_set_len_can_shrink() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to push(1)");
vec.push(2u8).expect("Failed to push(2)");
vec.push(3u8).expect("Failed to push(3)");
unsafe { vec.set_len(1) };
assert_eq!(vec.len(), 1);
assert_eq!(vec.as_slice(), &[1]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_set_len_can_grow_within_capacity() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to push(1)");
vec.push(2u8).expect("Failed to push(2)");
unsafe { vec.as_capacity_mut_slice()[2] = 3 };
unsafe { vec.as_capacity_mut_slice()[3] = 4 };
unsafe { vec.set_len(4) };
assert_eq!(vec.len(), 4);
assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_default() {
let vec: AllockedVec<u8> = AllockedVec::default();
assert_eq!(vec.len(), 0);
assert_eq!(vec.capacity(), 0);
assert!(vec.is_empty());
assert!(vec.is_zeroized());
}
#[test]
fn test_allocked_vec_deref_to_slice() {
let mut vec = AllockedVec::with_capacity(3);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
assert_eq!(vec[0], 1);
assert_eq!(vec[1], 2);
assert_eq!(vec.len(), 2);
assert!(!vec.is_zeroized());
}
#[test]
fn test_allocked_vec_zeroization_on_drop() {
let vec = AllockedVec::<u8>::default();
vec.assert_zeroize_on_drop();
}
#[test]
fn test_allocked_vec_zeroize_on_drop() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
vec.push(3u8).expect("Failed to vec.push(3)");
assert!(!vec.is_zeroized());
vec.assert_zeroize_on_drop();
}
#[test]
fn test_allocked_vec_partial_eq_equal_vecs() {
let mut vec1 = AllockedVec::with_capacity(5);
vec1.push(1u8).expect("Failed to push");
vec1.push(2u8).expect("Failed to push");
vec1.push(3u8).expect("Failed to push");
let mut vec2 = AllockedVec::with_capacity(5);
vec2.push(1u8).expect("Failed to push");
vec2.push(2u8).expect("Failed to push");
vec2.push(3u8).expect("Failed to push");
assert_eq!(vec1.as_slice(), vec2.as_slice());
assert!(vec1 == vec2);
}
#[test]
fn test_allocked_vec_partial_eq_different_data() {
let mut vec1 = AllockedVec::with_capacity(5);
vec1.push(1u8).expect("Failed to push");
vec1.push(2u8).expect("Failed to push");
let mut vec2 = AllockedVec::with_capacity(5);
vec2.push(1u8).expect("Failed to push");
vec2.push(3u8).expect("Failed to push");
assert_ne!(vec1.as_slice(), vec2.as_slice());
assert!(vec1 != vec2);
}
#[test]
fn test_allocked_vec_partial_eq_different_lengths() {
let mut vec1 = AllockedVec::with_capacity(5);
vec1.push(1u8).expect("Failed to push");
vec1.push(2u8).expect("Failed to push");
let mut vec2 = AllockedVec::with_capacity(5);
vec2.push(1u8).expect("Failed to push");
vec2.push(2u8).expect("Failed to push");
vec2.push(3u8).expect("Failed to push");
assert_ne!(vec1.as_slice(), vec2.as_slice());
assert!(vec1 != vec2);
}
#[test]
fn test_allocked_vec_partial_eq_different_capacities() {
let mut vec1 = AllockedVec::with_capacity(3);
vec1.push(1u8).expect("Failed to push");
vec1.push(2u8).expect("Failed to push");
let mut vec2 = AllockedVec::with_capacity(5);
vec2.push(1u8).expect("Failed to push");
vec2.push(2u8).expect("Failed to push");
assert_eq!(vec1.as_slice(), vec2.as_slice());
assert!(vec1 == vec2);
}
#[test]
fn test_allocked_vec_partial_eq_empty_vecs() {
let vec1 = AllockedVec::<u8>::with_capacity(5);
let vec2 = AllockedVec::<u8>::with_capacity(5);
assert_eq!(vec1.as_slice(), vec2.as_slice());
assert!(vec1 == vec2);
}
#[test]
fn test_allocked_vec_debug_redacted() {
let mut vec = AllockedVec::with_capacity(5);
vec.push(41u8).expect("Failed to push");
vec.push(42u8).expect("Failed to push");
vec.push(43u8).expect("Failed to push");
let debug_output = format!("{:?}", vec);
assert!(debug_output.contains("AllockedVec"));
assert!(debug_output.contains("REDACTED"));
assert!(debug_output.contains("len"));
assert!(debug_output.contains("capacity"));
assert!(!debug_output.contains("41"));
assert!(!debug_output.contains("42"));
assert!(!debug_output.contains("43"));
}
#[test]
fn test_allocked_vec_debug_snapshot() {
let mut vec = AllockedVec::with_capacity(5);
assert!(!vec.is_zeroized());
vec.push(1u8).expect("Failed to vec.push(1)");
vec.push(2u8).expect("Failed to vec.push(2)");
let debug_output = format!("{:?}", vec);
assert_eq!(
debug_output,
"AllockedVec { data: \"REDACTED\", len: 2, capacity: 5 }"
);
}