use super::*; fn rect(x: u16, y: u16, width: u16, height: u16) -> PaneRect { PaneRect { x, y, width, height, } } fn leaves(tree: &PaneTree, bounds: PaneRect) -> Vec<(usize, PaneRect)> { let mut leaves = Vec::new(); tree.visit_rects(bounds, |id, rect| leaves.push((id, rect))); leaves } #[test] fn nested_layout_partitions_bounds_and_preserves_ids() { let bounds = rect(3, 5, 11, 9); let mut tree = PaneTree::new(10); assert!(tree.split(10, 20, SplitAxis::Vertical)); assert!(tree.split(20, 30, SplitAxis::Horizontal)); assert!(!tree.split(99, 40, SplitAxis::Horizontal)); assert!(!tree.split(10, 30, SplitAxis::Horizontal)); assert!(!tree.split(10, 10, SplitAxis::Horizontal)); assert_eq!(tree.len(), 3); let panes = leaves(&tree, bounds); assert_eq!( panes, vec![ (10, rect(3, 5, 5, 9)), (20, rect(8, 5, 6, 4)), (30, rect(8, 9, 6, 5)) ] ); let mut cells = std::collections::HashSet::new(); for (_, pane) in panes { for y in pane.y..pane.y + pane.height { for x in pane.x..pane.x + pane.width { assert!(cells.insert((x, y)), "overlapping pane cell"); } } } assert_eq!( cells.len(), usize::from(bounds.width) * usize::from(bounds.height) ); assert!(leaves(&tree, rect(0, 0, 0, 10)).is_empty()); assert!(leaves(&tree, rect(0, 0, 10, 0)).is_empty()); } #[test] fn closing_expands_nested_sibling_and_refuses_last() { let bounds = rect(0, 0, 20, 12); let mut tree = PaneTree::new(1); tree.split(1, 2, SplitAxis::Vertical); tree.split(2, 3, SplitAxis::Horizontal); assert_eq!(tree.close(1), Some(2)); assert_eq!( leaves(&tree, bounds), vec![(2, rect(0, 0, 20, 6)), (3, rect(0, 6, 20, 6))] ); assert_eq!(tree.close(99), None); assert_eq!(tree.close(2), Some(3)); assert_eq!(leaves(&tree, bounds), vec![(3, bounds)]); assert_eq!(tree.close(3), None); assert_eq!(tree.len(), 1); assert!(!tree.contains(1)); assert!(tree.contains(3)); } #[test] fn directional_focus_handles_unequal_nested_regions() { let bounds = rect(0, 0, 20, 12); let mut tree = PaneTree::new(1); tree.split(1, 2, SplitAxis::Vertical); tree.split(2, 3, SplitAxis::Horizontal); tree.split(3, 4, SplitAxis::Horizontal); assert_eq!(tree.neighbor(1, PaneDirection::Right, bounds), Some(3)); assert_eq!(tree.neighbor(2, PaneDirection::Down, bounds), Some(3)); assert_eq!(tree.neighbor(3, PaneDirection::Down, bounds), Some(4)); assert_eq!(tree.neighbor(4, PaneDirection::Up, bounds), Some(3)); assert_eq!(tree.neighbor(4, PaneDirection::Left, bounds), Some(1)); assert_eq!(tree.neighbor(1, PaneDirection::Left, bounds), None); assert_eq!(tree.neighbor(99, PaneDirection::Right, bounds), None); assert_eq!( tree.neighbor(1, PaneDirection::Right, rect(0, 0, 0, 0)), None ); } #[test] fn navigation_prefers_overlap_then_edge_and_breaks_ties_by_id() { let current = rect(10, 10, 10, 10); let candidates = [ (1, rect(20, 0, 5, 5)), (2, rect(25, 10, 5, 10)), (4, rect(22, 10, 5, 10)), (3, rect(22, 10, 5, 10)), (0, rect(20, 10, 0, 10)), ]; assert_eq!( directional_neighbor(current, PaneDirection::Right, candidates.into_iter()), Some(3) ); assert_eq!( directional_neighbor(current, PaneDirection::Right, candidates.into_iter().rev()), Some(3) ); assert_eq!( directional_neighbor( current, PaneDirection::Up, [(7, rect(10, 0, 10, 5))].into_iter() ), Some(7) ); assert_eq!( directional_neighbor(current, PaneDirection::Left, candidates.into_iter()), None ); }