//! Always use `cargo miri test --all-features`, and never just `cargo test`. #[cfg(all(miri, not(feature = "unstable")))] #[test] #[allow(warnings)] fn aaaaaaaaaa_first_alphabetical() { let you_should_specify_dash_dash_all_features = std::ptr::null::<()>(); unsafe { *you_should_specify_dash_dash_all_features; } } use rand::{thread_rng, Rng}; use super::{dyn_vec, DynVec}; use std::{ any::Any, fmt::Debug, sync::atomic::{AtomicBool, Ordering}, }; trait DebugExt: Debug { fn debug(&self) -> String { format!("{self:?}") } } impl DebugExt for T {} #[test] fn basic_push() { let mut vec: DynVec = DynVec::new(); vec.push(3); vec.push(5); vec.push(7); assert_eq!(vec, [3, 5, 7]); } #[test] fn box_push() { let mut vec: DynVec = DynVec::new(); vec.push_box(Box::new(1) as _); // makes r-a happy, idk vec.push_box(Box::new(String::from("foo"))); vec.push_box(Box::new(true)); assert_eq!(vec.debug(), "[1, \"foo\", true]"); } #[test] fn unsize_push() { let mut vec: DynVec = DynVec::new(); vec.push_unsize_stable(1, |v| v as _); vec.push_unsize_stable(String::from("foo"), |v| v as _); vec.push_unsize_stable(true, |v| v as _); assert_eq!(vec.debug(), "[1, \"foo\", true]"); } #[test] fn all_macro() { let vec: DynVec = dyn_vec![3, 5, 7]; assert_eq!(vec, [3, 5, 7]); let vec2: DynVec = dyn_vec![box: Box::new(1) as _, Box::new(String::from("foo")) as _, Box::new(true) as _, ]; let vec3: DynVec = dyn_vec![unsized: 1, String::from("foo"), true]; assert_eq!(vec2.debug(), vec3.debug()); let vec4: DynVec = dyn_vec![3; 5]; assert_eq!(vec4, [3; 5]); } #[test] fn dropped() { static DROPPED: AtomicBool = AtomicBool::new(false); #[derive(Debug)] // for dyn Debug struct FunkyDrop; impl Drop for FunkyDrop { fn drop(&mut self) { DROPPED.store(true, Ordering::SeqCst); } } let vec: DynVec = dyn_vec![unsized: 1, FunkyDrop, true]; assert!(!DROPPED.load(Ordering::SeqCst)); drop(vec); assert!(DROPPED.load(Ordering::SeqCst)); } #[test] fn get() { let vec: DynVec = dyn_vec![3, 5, 7]; assert_eq!(vec.get(0).copied(), Some(3)); assert_eq!(vec.get(1).copied(), Some(5)); assert_eq!(vec.get(2).copied(), Some(7)); assert_eq!(vec.get(3).copied(), None); } #[test] #[should_panic = "index out of bounds: the len is 3 but the index is 3"] fn index() { let vec: DynVec = dyn_vec![3, 5, 7]; assert_eq!(vec[0], 3); assert_eq!(vec[1], 5); assert_eq!(vec[2], 7); let _ = vec[3]; } #[test] fn slice_flatten() { let mut vec: DynVec<[i32]> = dyn_vec![unsized: [1, 2, 3], [4, 5], [6, 7, 8, 9]]; assert_eq!(vec.as_slice_flatten(), [1, 2, 3, 4, 5, 6, 7, 8, 9]); vec.as_mut_slice_flatten()[4] = 10; assert_eq!(vec[1], [4, 10]); } #[test] fn iteration() { let mut vec: DynVec = dyn_vec![unsized: 1, String::from("foo"), true]; let mut iter = vec.iter(); assert_eq!(iter.next().unwrap().debug(), "1"); assert_eq!(iter.next().unwrap().debug(), "\"foo\""); assert_eq!(iter.next().unwrap().debug(), "true"); assert_eq!(iter.next().map(|_| ()), None); let mut iter = vec.iter_mut(); // TODO: create a trait to properly test this assert_eq!(iter.next().unwrap().debug(), "1"); assert_eq!(iter.next().unwrap().debug(), "\"foo\""); assert_eq!(iter.next().unwrap().debug(), "true"); assert_eq!(iter.next().map(|_| ()), None); let mut debugs = DynVec::new(); // using custom vec instead of std vec >:) for item in vec { debugs.push(item.debug()); } assert_eq!(debugs, ["1", "\"foo\"", "true"]); } #[test] fn zst() { #[derive(Debug, PartialEq, Eq)] struct Zst; let vec: DynVec = dyn_vec![Zst, Zst, Zst]; assert_eq!(vec[1], Zst); for el in vec.iter() { let _ = el; } assert_eq!(vec.debug(), "[Zst, Zst, Zst]"); let vec: DynVec = dyn_vec![unsized: Zst, (), Zst]; assert_eq!(vec[1].debug(), "()"); for el in vec.iter() { let _ = el; } assert_eq!(vec.debug(), "[Zst, (), Zst]"); } #[test] fn downcast() { let mut vec: DynVec = dyn_vec![unsized: 1, String::from("foo"), true]; assert_eq!(vec.downcast_get::(0), None); assert_eq!(vec.downcast_get::(0), Some(&1)); assert_eq!(vec.downcast_get_mut::(1), None); assert_eq!( vec.downcast_get_mut::(1), Some(&mut String::from("foo")) ); assert_eq!(vec.downcast_pop::(), None); assert_eq!(vec.downcast_pop::(), Some(true)); } #[test] fn pop() { let mut vec: DynVec = dyn_vec![unsized: 1, String::from("foo"), true]; assert_eq!(vec.pop().debug(), "Some(true)"); assert_eq!(vec.pop().debug(), "Some(\"foo\")"); assert_eq!(vec.pop().debug(), "Some(1)"); assert_eq!(vec.pop().debug(), "None"); } #[test] fn with_capacity() { // 4 and not 3 cause of `Layout::pad_to_align` let mut vec = DynVec::with_capacity(4); let prev_ptr = vec.as_ptr(); vec.push(1); vec.push(2); vec.push(3); vec.push(4); assert_eq!(prev_ptr, vec.as_ptr()); vec.push(5); // should have realloc'ed by now assert_ne!(prev_ptr, vec.as_ptr()); } #[test] fn unsize() { let vec = dyn_vec![1, 2, 3]; let mut vec: DynVec = vec.unsize_stable(|v| v as _); vec.push_unsize_stable(String::from("foo"), |v| v as _); assert_eq!(vec.debug(), "[1, 2, 3, \"foo\"]"); } #[test] fn remove() { let mut vec: DynVec = dyn_vec![unsized: 1, String::from("foo"), true]; assert_eq!(vec.remove(1).unwrap().debug(), "\"foo\""); assert_eq!(vec.debug(), "[1, true]"); } #[test] fn stress_test() { let mut vec: DynVec = DynVec::new(); let mut rng = thread_rng(); let mut len = 0; let iterations = if cfg!(miri) { 100 } else { 1_000_000 }; for _ in 0..iterations { if len == 0 || rng.gen_bool(0.7) { len += 1; match rng.gen_range(1..=3) { 1 => vec.push_unsize_stable("a string", |v| v as _), 2 => vec.push_unsize_stable(1, |v| v as _), 3 => vec.push_unsize_stable(true, |v| v as _), _ => unreachable!(), } } else { len -= 1; vec.pop(); } assert_eq!(len, vec.len()); } }