#![allow(clippy::unit_arg)] use std::fmt::{Debug, Error, Formatter, Write}; use crate::Vector; use proptest::proptest; use proptest_derive::Arbitrary; #[derive(Arbitrary, Debug)] enum Action { PushFront(A), PushBack(A), PopFront, PopBack, Insert(usize, A), Remove(usize), JoinLeft(Vec), JoinRight(Vec), SplitLeft(usize), SplitRight(usize), } #[derive(Arbitrary)] struct Actions(Vec>) where A: Clone; impl Debug for Actions where A: Debug + Clone, { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { let mut out = String::new(); let mut expected = vec![]; writeln!(out, "let mut vec = Vector::new();")?; for action in &self.0 { match action { Action::PushFront(ref value) => { expected.insert(0, value.clone()); writeln!(out, "vec.push_front({:?});", value)? } Action::PushBack(ref value) => { expected.push(value.clone()); writeln!(out, "vec.push_back({:?});", value)? } Action::PopFront => { if !expected.is_empty() { expected.remove(0); } writeln!(out, "vec.pop_front();")? } Action::PopBack => { expected.pop(); writeln!(out, "vec.pop_back();")? } Action::Insert(ref index, ref value) => { let index = cap_index(expected.len(), *index); expected.insert(index, value.clone()); writeln!(out, "vec.insert({:?}, {:?});", index, value)? } Action::Remove(ref index) => { if !expected.is_empty() { let index = cap_index(expected.len(), *index); expected.remove(index); writeln!(out, "vec.remove({:?})", index)? } else { continue; } } Action::JoinLeft(ref vec) => { let mut vec_new = vec.clone(); vec_new.append(&mut expected); expected = vec_new; writeln!( out, "let mut vec_new = Vector::from(vec!{:?}); // size {:?}", vec, vec.len() )?; writeln!(out, "vec_new.append(vec);")?; writeln!(out, "vec = vec_new;")? } Action::JoinRight(ref vec) => { expected.append(&mut vec.clone()); writeln!( out, "vec.append(Vector::from(vec!{:?})); // size {:?}", vec, vec.len() )? } Action::SplitLeft(ref index) => { let index = cap_index(expected.len(), *index); expected.truncate(index); writeln!(out, "vec.split_off({:?});", index)? } Action::SplitRight(ref index) => { let index = cap_index(expected.len(), *index); expected = expected.split_off(index); writeln!(out, "vec = vec.split_off({:?});", index)? } } writeln!(out, "// len = {:?}", expected.len())?; } writeln!(out, "let expected = vec!{:?};", expected)?; writeln!(out, "assert_eq!(Vector::from(expected), vec);")?; write!(f, "{}", super::code_fmt(&out)) } } fn cap_index(len: usize, index: usize) -> usize { if len == 0 { 0 } else { index % len } } proptest! { #[test] fn comprehensive(actions: Actions) { let mut vec = Vector::new(); let mut nat = Vec::new(); vec.assert_invariants(); for action in actions.0 { match action { Action::PushFront(value) => { let len = vec.len(); nat.insert(0, value); vec.push_front(value); assert_eq!(len + 1, vec.len()); } Action::PushBack(value) => { let len = vec.len(); nat.push(value); vec.push_back(value); assert_eq!(len + 1, vec.len()); } Action::PopFront => { if vec.is_empty() { assert_eq!(None, vec.pop_front()); } else { let len = vec.len(); assert_eq!(nat.remove(0), vec.pop_front().unwrap()); assert_eq!(len - 1, vec.len()); } } Action::PopBack => { if vec.is_empty() { assert_eq!(None, vec.pop_back()); } else { let len = vec.len(); assert_eq!(nat.pop(), vec.pop_back()); assert_eq!(len - 1, vec.len()); } } Action::Insert(index, value) => { let index = cap_index(vec.len(), index); let len = vec.len(); nat.insert(index, value); vec.insert(index, value); assert_eq!(len + 1, vec.len()); } Action::Remove(index) => { if vec.is_empty() { continue; } let index = cap_index(vec.len(), index); let len = vec.len(); assert_eq!(nat.remove(index), vec.remove(index)); assert_eq!(len - 1, vec.len()); } Action::JoinLeft(mut new_nat) => { let mut new_vec = new_nat.iter().cloned().collect::>(); let add_len = new_nat.len(); let len = vec.len(); new_vec.append(vec); vec = new_vec; new_nat.append(&mut nat); nat = new_nat; assert_eq!(len + add_len, vec.len()); } Action::JoinRight(mut new_nat) => { let new_vec = new_nat.iter().cloned().collect::>(); let add_len = new_nat.len(); let len = vec.len(); vec.append(new_vec); nat.append(&mut new_nat); assert_eq!(len + add_len, vec.len()); } Action::SplitLeft(index) => { let index = cap_index(vec.len(), index); let len = vec.len(); let vec_right = vec.split_off(index); let nat_right = nat.split_off(index); assert_eq!(index, vec.len()); assert_eq!(len - index, vec_right.len()); assert_eq!(nat_right.iter().cloned().collect::>(), vec_right); } Action::SplitRight(index) => { let index = cap_index(vec.len(), index); let len = vec.len(); let vec_right = vec.split_off(index); let nat_right = nat.split_off(index); assert_eq!(index, vec.len()); assert_eq!(len - index, vec_right.len()); assert_eq!(nat.iter().cloned().collect::>(), vec); vec = vec_right; nat = nat_right; } } vec.assert_invariants(); assert_eq!(nat.len(),vec.len()); assert_eq!(nat.iter().cloned().collect::>(), vec); } } } #[test] fn test_inserts() { const N: usize = 2000; let mut v = Vector::new(); for i in 0..N { v.insert(v.len() / 2, i); } let mut rv: Vec = Vec::new(); rv.extend((0..N).skip(1).step_by(2)); rv.extend((0..N).step_by(2).rev()); assert_eq!(rv.iter().cloned().collect::>(), v); }