diff options
Diffstat (limited to 'library/alloc/src/raw_vec')
-rw-r--r-- | library/alloc/src/raw_vec/tests.rs | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs new file mode 100644 index 000000000..ff322f0da --- /dev/null +++ b/library/alloc/src/raw_vec/tests.rs @@ -0,0 +1,163 @@ +use super::*; +use std::cell::Cell; + +#[test] +fn allocator_param() { + use crate::alloc::AllocError; + + // Writing a test of integration between third-party + // allocators and `RawVec` is a little tricky because the `RawVec` + // API does not expose fallible allocation methods, so we + // cannot check what happens when allocator is exhausted + // (beyond detecting a panic). + // + // Instead, this just checks that the `RawVec` methods do at + // least go through the Allocator API when it reserves + // storage. + + // A dumb allocator that consumes a fixed amount of fuel + // before allocation attempts start failing. + struct BoundedAlloc { + fuel: Cell<usize>, + } + unsafe impl Allocator for BoundedAlloc { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + let size = layout.size(); + if size > self.fuel.get() { + return Err(AllocError); + } + match Global.allocate(layout) { + ok @ Ok(_) => { + self.fuel.set(self.fuel.get() - size); + ok + } + err @ Err(_) => err, + } + } + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + unsafe { Global.deallocate(ptr, layout) } + } + } + + let a = BoundedAlloc { fuel: Cell::new(500) }; + let mut v: RawVec<u8, _> = RawVec::with_capacity_in(50, a); + assert_eq!(v.alloc.fuel.get(), 450); + v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel) + assert_eq!(v.alloc.fuel.get(), 250); +} + +#[test] +fn reserve_does_not_overallocate() { + { + let mut v: RawVec<u32> = RawVec::new(); + // First, `reserve` allocates like `reserve_exact`. + v.reserve(0, 9); + assert_eq!(9, v.capacity()); + } + + { + let mut v: RawVec<u32> = RawVec::new(); + v.reserve(0, 7); + assert_eq!(7, v.capacity()); + // 97 is more than double of 7, so `reserve` should work + // like `reserve_exact`. + v.reserve(7, 90); + assert_eq!(97, v.capacity()); + } + + { + let mut v: RawVec<u32> = RawVec::new(); + v.reserve(0, 12); + assert_eq!(12, v.capacity()); + v.reserve(12, 3); + // 3 is less than half of 12, so `reserve` must grow + // exponentially. At the time of writing this test grow + // factor is 2, so new capacity is 24, however, grow factor + // of 1.5 is OK too. Hence `>= 18` in assert. + assert!(v.capacity() >= 12 + 12 / 2); + } +} + +struct ZST; + +// A `RawVec` holding zero-sized elements should always look like this. +fn zst_sanity<T>(v: &RawVec<T>) { + assert_eq!(v.capacity(), usize::MAX); + assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr()); + assert_eq!(v.current_memory(), None); +} + +#[test] +fn zst() { + let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into()); + + assert_eq!(std::mem::size_of::<ZST>(), 0); + + // All these different ways of creating the RawVec produce the same thing. + + let v: RawVec<ZST> = RawVec::new(); + zst_sanity(&v); + + let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global); + zst_sanity(&v); + + let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global); + zst_sanity(&v); + + let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global); + zst_sanity(&v); + + let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global); + zst_sanity(&v); + + let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global); + zst_sanity(&v); + + // Check all these operations work as expected with zero-sized elements. + + assert!(!v.needs_to_grow(100, usize::MAX - 100)); + assert!(v.needs_to_grow(101, usize::MAX - 100)); + zst_sanity(&v); + + v.reserve(100, usize::MAX - 100); + //v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below + zst_sanity(&v); + + v.reserve_exact(100, usize::MAX - 100); + //v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below + zst_sanity(&v); + + assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(())); + assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err); + zst_sanity(&v); + + assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(())); + assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err); + zst_sanity(&v); + + assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err); + assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err); + zst_sanity(&v); + + assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err); + assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err); + zst_sanity(&v); +} + +#[test] +#[should_panic(expected = "capacity overflow")] +fn zst_reserve_panic() { + let mut v: RawVec<ZST> = RawVec::new(); + zst_sanity(&v); + + v.reserve(101, usize::MAX - 100); +} + +#[test] +#[should_panic(expected = "capacity overflow")] +fn zst_reserve_exact_panic() { + let mut v: RawVec<ZST> = RawVec::new(); + zst_sanity(&v); + + v.reserve_exact(101, usize::MAX - 100); +} |