use std::fmt; use std::sync::mpsc::channel; use std::thread; use std::time::Duration; use arctree::{Node, NodeEdge}; fn timeout(f: F, duration: Duration) where F: FnOnce() + Send + 'static, { let (start_tx, start_rx) = channel::<()>(); let (end_tx, end_rx) = channel::<()>(); let guard = thread::spawn(move || { start_tx.send(()).unwrap(); f(); end_tx.send(()).unwrap(); }); // Wait for the thread to start. start_rx.recv().unwrap(); // Wait for the timeout match end_rx.recv_timeout(duration) { Err(_) => { panic!("Timed out"); } _ => (), } guard.join().unwrap(); } #[test] fn it_works() { use std::cell; struct DropTracker<'a>(&'a cell::Cell); impl<'a> Drop for DropTracker<'a> { fn drop(&mut self) { self.0.set(self.0.get() + 1); } } let mut new_counter = 0; let drop_counter = cell::Cell::new(0); let mut new = || { new_counter += 1; Node::new((new_counter, DropTracker(&drop_counter))) }; { let a = new(); // 1 a.append(new()); // 2 a.append(new()); // 3 a.prepend(new()); // 4 let b = new(); // 5 b.append(a.clone()); a.insert_before(new()); // 6 a.insert_before(new()); // 7 a.insert_after(new()); // 8 a.insert_after(new()); // 9 let c = new(); // 10 b.append(c.clone()); assert_eq!(drop_counter.get(), 0); c.previous_sibling().unwrap().detach(); assert_eq!(drop_counter.get(), 1); assert_eq!( b.descendants() .map(|node| { let borrow = node.read(); borrow.0 }) .collect::>(), [5, 6, 7, 1, 4, 2, 3, 9, 10] ); } assert_eq!(drop_counter.get(), 10); } struct TreePrinter(Node); impl fmt::Debug for TreePrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{:?}", self.0.read()).unwrap(); iter_children(&self.0, 1, f); Ok(()) } } fn iter_children(parent: &Node, depth: usize, f: &mut fmt::Formatter<'_>) { for child in parent.children() { for _ in 0..depth { write!(f, " ").unwrap(); } writeln!(f, "{:?}", child.read()).unwrap(); iter_children(&child, depth + 1, f); } } #[test] fn make_copy_1() { let node1 = Node::new(1); let node2 = Node::new(2); node1.append(node2); let node1_copy = node1.make_copy(); node1.append(node1_copy); assert_eq!( format!("{:?}", TreePrinter(node1)), "1 2 1 " ); } #[test] fn make_deep_copy_1() { let node1 = Node::new(1); let node2 = Node::new(2); node1.append(node2.clone()); node2.append(node1.make_deep_copy()); assert_eq!( format!("{:?}", TreePrinter(node1)), "1 2 1 2 " ); } #[test] #[should_panic] fn append_1() { let node1 = Node::new(1); let node1_2 = node1.clone(); node1.append(node1_2); } #[test] #[should_panic] fn prepend_1() { let node1 = Node::new(1); let node1_2 = node1.clone(); node1.prepend(node1_2); } #[test] #[should_panic] fn insert_before_1() { let node1 = Node::new(1); let node1_2 = node1.clone(); node1.insert_before(node1_2); } #[test] #[should_panic] fn insert_after_1() { let node1 = Node::new(1); let node1_2 = node1.clone(); node1.insert_after(node1_2); } /// Test that the thread blocks when trying to modify the tree while iterating over it. /// /// This test is expected to panic with a timeout since the thread will block forever. #[test] #[should_panic] fn iter_1() { timeout( || { let node1 = Node::new(1); let node2 = Node::new(2); node1.append(node2.clone()); node2.append(node1.make_deep_copy()); let _n = node2.write(); for _ in node1.descendants() {} }, Duration::from_millis(100), ); } #[test] fn stack_overflow() { let mut parent = Node::new(1); for _ in 0..200_000 { let node = Node::new(1); node.append(parent.clone()); parent = node; } } fn fan_tree(depth: i32, width: usize) -> Node { let node = Node::new(depth); if depth > 0 { for _ in 0..width { node.append(fan_tree(depth - 1, width)); } } node } #[test] fn drop_keeps_strong_refs() { const CHILD_COUNT: usize = 3; let (keep1, keep2) = { let root = fan_tree(5, CHILD_COUNT); ( root.first_child().unwrap().first_child().unwrap(), root.first_child().unwrap().next_sibling().unwrap(), ) }; assert_eq!(keep1.children().count(), CHILD_COUNT); assert_eq!(keep2.children().count(), CHILD_COUNT); } #[test] fn weak_1() { let node1 = Node::new("node1"); let weak1 = node1.downgrade(); let weak2 = weak1.clone(); let node2 = weak1.upgrade().unwrap(); assert_eq!(node1, node2); let node3 = weak2.upgrade().unwrap(); assert_eq!(node1, node3); } #[test] fn weak_2() { let weak; { let node1 = Node::new("node1"); weak = node1.downgrade(); } assert_eq!(None, weak.upgrade()); } #[test] fn children_1() { let node1 = Node::new("node1"); let node2 = Node::new("node2"); let node3 = Node::new("node3"); node1.append(node2.clone()); node1.append(node3.clone()); let mut children = node1.children(); let c = children.next(); assert!(c.is_some()); let c = c.unwrap(); assert_eq!(c, node2); let c = children.next(); assert!(c.is_some()); let c = c.unwrap(); assert_eq!(c, node3); assert!(children.next().is_none()); assert!(children.next_back().is_none()); } #[test] fn children_2() { let node1 = Node::new("node1"); let node2 = Node::new("node2"); let node3 = Node::new("node3"); node1.append(node2.clone()); node1.append(node3.clone()); let mut children = node1.children(); let c = children.next_back(); assert!(c.is_some()); let c = c.unwrap(); assert_eq!(c, node3); let c = children.next_back(); assert!(c.is_some()); let c = c.unwrap(); assert_eq!(c, node2); assert!(children.next().is_none()); assert!(children.next_back().is_none()); } #[test] fn traverse_1() { let node1 = Node::new("node1"); let node2 = Node::new("node2"); let node3 = Node::new("node3"); node1.append(node2.clone()); node1.append(node3.clone()); let mut traverse = node1.traverse(); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node1.clone())); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node2.clone())); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node2.clone())); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node3.clone())); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node3.clone())); let t = traverse.next(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node1.clone())); assert!(traverse.next().is_none()); assert!(traverse.next_back().is_none()); } #[test] fn traverse_2() { let node1 = Node::new("node1"); let node2 = Node::new("node2"); let node3 = Node::new("node3"); node1.append(node2.clone()); node1.append(node3.clone()); let mut traverse = node1.traverse(); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node1.clone())); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node3.clone())); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node3.clone())); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::End(node2.clone())); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node2.clone())); let t = traverse.next_back(); assert!(t.is_some()); let t = t.unwrap(); assert_eq!(t, NodeEdge::Start(node1.clone())); assert!(traverse.next().is_none()); assert!(traverse.next_back().is_none()); }