use quickcheck::{Arbitrary, Gen};
use super::*;
#[quickcheck]
fn smoke(node: Node) {
node.trans_iter().for_each(|_| ())
}
#[quickcheck]
fn node_count_breadth_first(node: Node) -> bool {
let count = node.count();
node.trans_iter().breadth_first().count() == count
}
#[quickcheck]
fn node_count_depth_first(node: Node) -> bool {
let count = node.count();
node.trans_iter().depth_first().count() == count
}
#[quickcheck]
fn node_count_depth_first_unordered(node: Node) -> bool {
let count = node.count();
node.trans_iter().depth_first_unordered().count() == count
}
#[quickcheck]
fn node_count_prio_queue(node: Node) -> bool {
let count = node.count();
node.trans_prio_queue().count() == count
}
#[quickcheck]
fn node_order_breadth_first(node: Node) -> bool {
fn match_ids(ids: &[u128], offset: usize, reference: &[Node], counts: &[usize]) -> Option<usize> {
if reference.is_empty() {
Some(offset)
} else if let Some((depth_count, counts)) = counts.split_first() {
let (ids, next) = ids.split_at(*depth_count);
let ids = ids.split_at(offset).1;
ids.windows(reference.len())
.position(|ids| ids.iter().eq(reference.iter().map(|n| &n.id)))
.and_then(|pos| {
reference
.iter()
.try_fold(0, |off, sub| match_ids(next, off, sub.children.as_ref(), counts))
.map(|_| offset + pos + reference.len())
})
} else {
Some(offset)
}
}
let ids: Vec<_> = node.clone().trans_iter().breadth_first().map(|n| n.id).collect();
let counts: Vec<_> = (0..).map(|d| node.count_at_depth(d)).take_while(|c| *c > 0).collect();
match_ids(ids.as_ref(), 0, &[node], counts.as_ref()).is_some()
}
#[quickcheck]
fn node_order_depth_first(node: Node) -> bool {
fn match_ids<'a>(ids: &'a [u128], root: &Node) -> Option<&'a [u128]> {
ids.split_first()
.and_then(|(first, ids)| if *first == root.id { Some(ids) } else { None })
.and_then(|ids| root.children.iter().try_fold(ids, |ids, sub| match_ids(ids, sub)))
}
let ids: Vec<_> = node.clone().trans_iter().depth_first().map(|n| n.id).collect();
match_ids(ids.as_ref(), &node) == Some(&[])
}
#[quickcheck]
fn node_order_depth_first_unordered(node: Node) -> bool {
fn match_ids<'a>(ids: &'a [u128], root: &Node) -> Option<&'a [u128]> {
ids.split_first()
.and_then(|(first, ids)| if *first == root.id { Some(ids) } else { None })
.and_then(|ids| root.children.iter().try_rfold(ids, |ids, sub| match_ids(ids, sub)))
}
let ids: Vec<_> = node.clone().trans_iter().depth_first_unordered().map(|n| n.id).collect();
match_ids(ids.as_ref(), &node) == Some(&[])
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Node {
id: u128,
children: Vec<Self>,
}
impl Node {
pub fn count(&self) -> usize {
self.children.iter().map(Self::count).sum::<usize>() + 1
}
pub fn count_at_depth(&self, depth: usize) -> usize {
if let Some(depth) = depth.checked_sub(1) {
self.children.iter().map(|n| n.count_at_depth(depth)).sum::<usize>()
} else {
1
}
}
}
impl<'a> AutoTransIter<&'a Node> for &'a Node {
type RecIter = std::slice::Iter<'a, Node>;
fn recurse(item: &&'a Node) -> Self::RecIter {
item.children.iter()
}
}
impl Arbitrary for Node {
fn arbitrary(g: &mut Gen) -> Self {
let children = if g.size() > 0 {
Arbitrary::arbitrary(&mut Gen::new(g.size() / 2))
} else {
Default::default()
};
Self {id: Arbitrary::arbitrary(g), children}
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(self.children.clone().into_iter())
}
}