use super::{
alloc,
free,
ContractPhase,
DynamicAllocation,
DynamicAllocator,
};
use crate::{
alloc,
traits::{
KeyPtr,
SpreadLayout,
},
};
use pro_env::{
test,
DefaultEnvironment,
};
use pro_primitives::Key;
fn run_default_test<F>(f: F)
where
F: FnOnce(),
{
alloc::initialize(ContractPhase::Deploy);
test::run_test::<DefaultEnvironment, _>(|_| {
f();
Ok(())
})
.unwrap();
}
#[test]
fn alloc_works() {
run_default_test(|| {
assert_eq!(alloc(), DynamicAllocation(0));
})
}
cfg_if::cfg_if! {
if #[cfg(miri)] {
const TEST_ALLOCATIONS: u32 = 10;
} else {
const TEST_ALLOCATIONS: u32 = 10_000;
}
}
#[test]
fn many_allocs_works() {
run_default_test(|| {
for i in 0..TEST_ALLOCATIONS {
assert_eq!(alloc(), DynamicAllocation(i));
}
})
}
#[test]
fn free_works() {
run_default_test(|| {
free(alloc());
})
}
#[test]
fn many_alloc_and_free_works() {
run_default_test(|| {
for i in 0..TEST_ALLOCATIONS {
assert_eq!(alloc(), DynamicAllocation(i));
}
for i in 0..TEST_ALLOCATIONS {
free(DynamicAllocation(i))
}
assert_eq!(alloc(), DynamicAllocation(0));
})
}
#[test]
fn alloc_free_in_the_middle() {
run_default_test(|| {
for i in 0..TEST_ALLOCATIONS {
assert_eq!(alloc(), DynamicAllocation(i));
}
for i in 0..TEST_ALLOCATIONS {
free(DynamicAllocation(i));
assert_eq!(alloc(), DynamicAllocation(i));
}
})
}
#[test]
#[should_panic(expected = "encountered double free of dynamic storage: at index 0")]
fn double_free_panics() {
run_default_test(|| {
let a0 = alloc();
let _ = alloc();
free(a0);
free(a0);
})
}
#[test]
#[should_panic(expected = "invalid dynamic storage allocation")]
fn free_out_of_bounds() {
run_default_test(|| {
free(DynamicAllocation(0));
})
}
fn spread_layout_alloc_setup() -> DynamicAllocator {
let mut alloc = DynamicAllocator::default();
assert_eq!(alloc.alloc(), DynamicAllocation(0));
assert_eq!(alloc.alloc(), DynamicAllocation(1));
assert_eq!(alloc.alloc(), DynamicAllocation(2));
assert_eq!(alloc.alloc(), DynamicAllocation(3));
assert_eq!(alloc.alloc(), DynamicAllocation(4));
alloc.free(DynamicAllocation(3));
alloc.free(DynamicAllocation(1));
alloc
}
#[test]
fn spread_pull_push_works() {
run_default_test(|| {
let mut alloc = spread_layout_alloc_setup();
let root_key = Key::from([0x77; 32]);
SpreadLayout::push_spread(&alloc, &mut KeyPtr::from(root_key));
assert_eq!(alloc.alloc(), DynamicAllocation(1));
assert_eq!(alloc.alloc(), DynamicAllocation(3));
let mut alloc2 =
<DynamicAllocator as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
assert_eq!(alloc2.alloc(), DynamicAllocation(1));
assert_eq!(alloc2.alloc(), DynamicAllocation(3));
assert_eq!(alloc2, alloc);
})
}
#[test]
#[should_panic(expected = "encountered empty storage cell")]
fn spread_clear_works() {
run_default_test(|| {
let alloc = spread_layout_alloc_setup();
let root_key = Key::from([0x42; 32]);
SpreadLayout::push_spread(&alloc, &mut KeyPtr::from(root_key));
let alloc2 =
<DynamicAllocator as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
assert_eq!(alloc2, alloc);
SpreadLayout::clear_spread(&alloc2, &mut KeyPtr::from(root_key));
let alloc3 =
<DynamicAllocator as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
let mut alloc3 = core::mem::ManuallyDrop::new(alloc3);
let _ = alloc3.alloc();
})
}
#[test]
fn test_call_setup_works() {
test::run_test::<DefaultEnvironment, _>(|_| {
let mut allocator = DynamicAllocator::default();
assert_eq!(allocator.alloc(), DynamicAllocation(0));
assert_eq!(allocator.alloc(), DynamicAllocation(1));
let root_key = Key::from([0xFE; 32]);
DynamicAllocator::push_spread(&allocator, &mut KeyPtr::from(root_key));
alloc::initialize(ContractPhase::Call);
assert_eq!(alloc(), DynamicAllocation(2));
assert_eq!(alloc(), DynamicAllocation(3));
free(DynamicAllocation(0));
free(DynamicAllocation(2));
Ok(())
})
.unwrap();
}