use std::collections::HashSet;
use super::*;
use crate::tree::TreeNode;
use insta::assert_snapshot;
use crate::{Badge, BadgeAnchor, BadgeStack};
use ratatui::{backend::TestBackend, Terminal};
fn render(name: &str, popup: TreePopup<'_>, state: &mut TreeState) {
let backend = TestBackend::new(60, 20);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| f.render_stateful_widget(popup, f.area(), state))
.unwrap();
assert_snapshot!(name, terminal.backend());
}
fn sample_nodes() -> Vec<TreeNode<'static>> {
vec![
TreeNode {
text: "src".into(),
children: vec![
TreeNode { text: "main.rs".into(), children: vec![], id: 2 },
TreeNode { text: "lib.rs".into(), children: vec![], id: 3 },
],
id: 1,
},
TreeNode {
text: "Cargo.toml".into(),
children: vec![],
id: 4,
},
]
}
#[test]
fn resolve_rect_delegates_to_popup() {
let popup = TreePopup::new(sample_nodes())
.width(PopupSize::Fixed(30))
.height(PopupSize::Fixed(10));
let state = TreeState::default();
assert_eq!(popup.resolve_rect(Rect::new(0, 0, 100, 50), &state).width, 30);
assert_eq!(popup.resolve_rect(Rect::new(0, 0, 100, 50), &state).height, 10);
}
#[test]
fn resolve_rect_clamps_when_larger_than_area() {
let popup = TreePopup::new(sample_nodes())
.width(PopupSize::Fixed(100))
.height(PopupSize::Fixed(50));
let state = TreeState::default();
assert_eq!(
popup.resolve_rect(Rect::new(0, 0, 60, 20), &state),
Rect::new(0, 0, 60, 20)
);
}
#[test]
fn resolve_rect_auto_uses_auto_height() {
let popup = TreePopup::new(sample_nodes());
let state = TreeState::default();
let auto_h = popup.auto_height(&state, Rect::new(0, 0, 100, 50));
assert_eq!(auto_h, 5);
let rect = popup.resolve_rect(Rect::new(0, 0, 100, 50), &state);
assert_eq!(rect.height, 5);
}
#[test]
fn resolve_rect_auto_centers_correctly() {
let popup = TreePopup::new(sample_nodes());
let state = TreeState::default();
let rect = popup.resolve_rect(Rect::new(0, 0, 100, 50), &state);
assert_eq!(rect.x, 10);
assert_eq!(rect.y, 22); }
#[test]
fn snapshot_default() {
let popup = TreePopup::new(sample_nodes());
let mut state = TreeState::default();
render("tree_popup_default", popup, &mut state);
}
#[test]
fn snapshot_with_title() {
let popup = TreePopup::new(sample_nodes()).title("Project");
let mut state = TreeState::default();
render("tree_popup_with_title", popup, &mut state);
}
#[test]
fn snapshot_with_border_color() {
let popup = TreePopup::new(sample_nodes())
.title("Cyan border")
.border_color(Color::Cyan);
let mut state = TreeState::default();
render("tree_popup_border_color", popup, &mut state);
}
#[test]
fn snapshot_with_width() {
let popup = TreePopup::new(sample_nodes())
.width(PopupSize::Fixed(40));
let mut state = TreeState::default();
render("tree_popup_with_width", popup, &mut state);
}
#[test]
fn snapshot_expanded() {
let popup = TreePopup::new(sample_nodes()).title("Expanded");
let mut state = TreeState { expanded: HashSet::from([1]), ..TreeState::default() };
render("tree_popup_expanded", popup, &mut state);
}
#[test]
fn snapshot_with_origin() {
let popup = TreePopup::new(sample_nodes())
.origin(5, 5);
let mut state = TreeState::default();
render("tree_popup_with_origin", popup, &mut state);
}
#[test]
fn regression_tree_uses_full_inner() {
let mut state = TreeState { expanded: HashSet::from([1]), ..TreeState::default() };
let backend = TestBackend::new(60, 20);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
f.render_stateful_widget(
TreePopup::new(sample_nodes()).title("Expanded"),
f.area(),
&mut state,
)
})
.unwrap();
let buf = terminal.backend().buffer();
let state = TreeState::default();
let popup_rect = TreePopup::new(sample_nodes())
.height(PopupSize::Fixed(6))
.title("Expanded")
.resolve_rect(Rect::new(0, 0, 60, 20), &state);
let inner = Rect::new(
popup_rect.x + 1,
popup_rect.y + 1,
popup_rect.width.saturating_sub(2),
popup_rect.height.saturating_sub(2),
);
let last_y = inner.y + inner.height - 1;
let has_content = (inner.x + 1..inner.x + inner.width - 1)
.any(|x| buf.cell((x, last_y)).is_some_and(|c| c.symbol().trim() != ""));
assert!(
has_content,
"last inner row (y={}) should contain tree content, not be blank",
last_y,
);
}
#[test]
fn snapshot_with_badges() {
let badges = BadgeStack::new()
.push(Badge::new(" main", Color::Green).anchor(BadgeAnchor::TopLeft));
let popup = TreePopup::new(sample_nodes())
.title("Files")
.badges(badges);
let mut state = TreeState::default();
render("tree_with_badges", popup, &mut state);
}