#![allow(clippy::unwrap_used, clippy::panic)]
use std::sync::Arc;
use panes::runtime::LayoutRuntime;
use panes::{ActivePanelVariant, Axis, Placement, StrategyKind};
fn kinds(n: usize) -> Vec<Arc<str>> {
(0..n).map(|i| Arc::from(format!("p{i}"))).collect()
}
fn sequence_kinds(rt: &LayoutRuntime) -> Vec<String> {
(0..rt.sequence().len())
.map(|i| {
let pid = rt.sequence().get(i).unwrap();
rt.tree().panel_kind(pid).unwrap().to_owned()
})
.collect()
}
fn sequence_runtime(n: usize) -> LayoutRuntime {
LayoutRuntime::from_strategy(
StrategyKind::Sequence {
axis: Axis::Row,
gap: 0.0,
ratio: None,
},
&kinds(n),
)
.unwrap()
}
#[test]
fn sequence_add_panel_inserts_after_focused() {
let mut rt = sequence_runtime(3);
let p1 = rt.sequence().get(1).unwrap();
rt.focus(p1);
rt.add_panel(Arc::from("new")).unwrap();
assert_eq!(sequence_kinds(&rt), ["p0", "p1", "new", "p2"]);
}
#[test]
fn sequence_add_panel_with_before() {
let mut rt = sequence_runtime(3);
let p1 = rt.sequence().get(1).unwrap();
rt.focus(p1);
rt.add_panel_with(Arc::from("new"), Placement::Before)
.unwrap();
assert_eq!(sequence_kinds(&rt), ["p0", "new", "p1", "p2"]);
}
#[test]
fn sequence_add_panel_with_end() {
let mut rt = sequence_runtime(3);
let p1 = rt.sequence().get(1).unwrap();
rt.focus(p1);
rt.add_panel_with(Arc::from("new"), Placement::End).unwrap();
assert_eq!(sequence_kinds(&rt), ["p0", "p1", "p2", "new"]);
}
#[test]
fn sequence_add_panel_with_after() {
let mut rt = sequence_runtime(3);
let p1 = rt.sequence().get(1).unwrap();
rt.focus(p1);
rt.add_panel_with(Arc::from("new"), Placement::After)
.unwrap();
assert_eq!(sequence_kinds(&rt), ["p0", "p1", "new", "p2"]);
}
fn master_stack_runtime(n: usize) -> LayoutRuntime {
LayoutRuntime::from_strategy(
StrategyKind::MasterStack {
master_ratio: 0.5,
gap: 0.0,
},
&kinds(n),
)
.unwrap()
}
#[test]
fn master_stack_add_panel_rebuilds_correctly() {
let mut rt = master_stack_runtime(3);
rt.add_panel(Arc::from("new")).unwrap();
rt.tree().validate().unwrap();
assert_eq!(rt.sequence().len(), 4);
}
#[test]
fn master_stack_swap_after_add() {
let mut rt = master_stack_runtime(3);
rt.add_panel(Arc::from("new")).unwrap();
rt.swap_next().unwrap();
rt.tree().validate().unwrap();
}
#[test]
fn tabbed_add_panel_creates_tab_decoration() {
let mut rt = LayoutRuntime::from_strategy(
StrategyKind::ActivePanel {
variant: ActivePanelVariant::Tabbed,
bar_height: 30.0,
},
&[Arc::from("editor"), Arc::from("terminal")],
)
.unwrap();
let new_pid = rt.add_panel(Arc::from("logs")).unwrap();
assert_eq!(rt.focused(), Some(new_pid));
assert_eq!(rt.sequence().len(), 3);
rt.tree().validate().unwrap();
let frame = rt.resolve(800.0, 600.0).unwrap();
let logs_tab = frame
.layout()
.decoration_panels()
.iter()
.any(|d| d.role == panes::DecorationRole::Tab && d.content_kind.as_ref() == "logs");
assert!(
logs_tab,
"tabbed add_panel should create tab decoration for logs"
);
}
#[test]
fn stacked_add_panel_creates_title_decoration() {
let mut rt = LayoutRuntime::from_strategy(
StrategyKind::ActivePanel {
variant: ActivePanelVariant::Stacked,
bar_height: 30.0,
},
&[Arc::from("editor"), Arc::from("terminal")],
)
.unwrap();
rt.add_panel(Arc::from("logs")).unwrap();
rt.tree().validate().unwrap();
let frame = rt.resolve(800.0, 600.0).unwrap();
let logs_title = frame
.layout()
.decoration_panels()
.iter()
.any(|d| d.role == panes::DecorationRole::Title && d.content_kind.as_ref() == "logs");
assert!(
logs_title,
"stacked add_panel should create title decoration for logs"
);
}
#[test]
fn deck_move_preserves_visibility() {
let mut rt = LayoutRuntime::from_strategy(
StrategyKind::Deck {
master_ratio: 0.5,
gap: 0.0,
},
&kinds(4),
)
.unwrap();
let p2 = rt.sequence().get(2).unwrap();
rt.focus(p2);
rt.move_panel(p2, 3).unwrap();
let focused = rt.focused().unwrap();
let c = rt.tree().panel_constraints(focused).unwrap();
assert!(
c.grow.is_some(),
"focused panel should be visible after move"
);
}
#[test]
fn monocle_move_preserves_visibility() {
let mut rt = LayoutRuntime::from_strategy(
StrategyKind::ActivePanel {
variant: ActivePanelVariant::Monocle,
bar_height: 0.0,
},
&kinds(3),
)
.unwrap();
let p1 = rt.sequence().get(1).unwrap();
rt.focus(p1);
rt.move_panel(p1, 2).unwrap();
let focused = rt.focused().unwrap();
let c = rt.tree().panel_constraints(focused).unwrap();
assert!(
c.grow.is_some(),
"focused panel should be visible after move"
);
}
#[test]
fn swap_next_after_add_on_all_strategies() {
let strategies: Vec<StrategyKind> = vec![
StrategyKind::Sequence {
axis: Axis::Row,
gap: 0.0,
ratio: None,
},
StrategyKind::MasterStack {
master_ratio: 0.5,
gap: 0.0,
},
StrategyKind::CenteredMaster {
master_ratio: 0.5,
gap: 0.0,
},
StrategyKind::BinarySplit {
spiral: false,
ratio: 0.5,
gap: 0.0,
},
StrategyKind::Dashboard {
columns: panes::GridColumnMode::Fixed(2),
gap: 0.0,
spans: std::sync::Arc::from([]),
auto_rows: false,
},
];
for strategy in strategies {
let mut rt = LayoutRuntime::from_strategy(strategy, &kinds(3)).unwrap();
rt.add_panel(Arc::from("new")).unwrap();
rt.swap_next().unwrap();
rt.tree().validate().unwrap();
}
}