use ratatui::layout::Rect;
use ratatui_toolkit::resizable_split::{ResizableSplit, SplitDirection};
#[test]
fn test_new_creates_vertical_split_by_default() {
let split = ResizableSplit::new(70);
assert_eq!(split.direction, SplitDirection::Vertical);
assert_eq!(split.split_percent, 70);
assert_eq!(split.min_percent, 10);
assert_eq!(split.max_percent, 90);
assert!(!split.is_dragging);
assert!(!split.is_hovering);
assert_eq!(split.divider_pos, 0);
}
#[test]
fn test_new_with_direction_vertical() {
let split = ResizableSplit::new_with_direction(60, SplitDirection::Vertical);
assert_eq!(split.direction, SplitDirection::Vertical);
assert_eq!(split.split_percent, 60);
}
#[test]
fn test_new_with_direction_horizontal() {
let split = ResizableSplit::new_with_direction(40, SplitDirection::Horizontal);
assert_eq!(split.direction, SplitDirection::Horizontal);
assert_eq!(split.split_percent, 40);
}
#[test]
fn test_default_creates_70_percent_vertical_split() {
let split = ResizableSplit::default();
assert_eq!(split.direction, SplitDirection::Vertical);
assert_eq!(split.split_percent, 70);
}
#[test]
fn test_new_clamps_percentage_to_min_5() {
let split = ResizableSplit::new(0);
assert_eq!(split.split_percent, 5);
let split = ResizableSplit::new(3);
assert_eq!(split.split_percent, 5);
}
#[test]
fn test_new_clamps_percentage_to_max_95() {
let split = ResizableSplit::new(100);
assert_eq!(split.split_percent, 95);
let split = ResizableSplit::new(150);
assert_eq!(split.split_percent, 95);
let split = ResizableSplit::new(u16::MAX);
assert_eq!(split.split_percent, 95);
}
#[test]
fn test_new_accepts_valid_percentages() {
let split = ResizableSplit::new(5);
assert_eq!(split.split_percent, 5);
let split = ResizableSplit::new(50);
assert_eq!(split.split_percent, 50);
let split = ResizableSplit::new(95);
assert_eq!(split.split_percent, 95);
}
#[test]
fn test_new_with_direction_clamps_percentage() {
let split = ResizableSplit::new_with_direction(0, SplitDirection::Vertical);
assert_eq!(split.split_percent, 5);
let split = ResizableSplit::new_with_direction(200, SplitDirection::Horizontal);
assert_eq!(split.split_percent, 95);
}
#[test]
fn test_update_divider_position_vertical_50_percent() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 50);
}
#[test]
fn test_update_divider_position_vertical_70_percent() {
let mut split = ResizableSplit::new(70);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 70);
}
#[test]
fn test_update_divider_position_vertical_with_offset() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(10, 5, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 60);
}
#[test]
fn test_update_divider_position_vertical_odd_width() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 99, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 49);
}
#[test]
fn test_update_divider_position_vertical_small_area() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 10, 5);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 5);
}
#[test]
fn test_update_divider_position_vertical_extreme_percentages() {
let mut split = ResizableSplit::new(5);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 5);
let mut split = ResizableSplit::new(95);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 95);
}
#[test]
fn test_update_divider_position_horizontal_50_percent() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 10);
}
#[test]
fn test_update_divider_position_horizontal_70_percent() {
let mut split = ResizableSplit::new_with_direction(70, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 14);
}
#[test]
fn test_update_divider_position_horizontal_with_offset() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(10, 5, 100, 20);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 15);
}
#[test]
fn test_update_divider_position_horizontal_odd_height() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 21);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 10);
}
#[test]
fn test_update_divider_position_horizontal_small_area() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 10, 8);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 4);
}
#[test]
fn test_update_divider_position_horizontal_extreme_percentages() {
let mut split = ResizableSplit::new_with_direction(5, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 100);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 5);
let mut split = ResizableSplit::new_with_direction(95, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 100);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 95);
}
#[test]
fn test_is_on_divider_vertical_exact_position() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 10, area));
}
#[test]
fn test_is_on_divider_vertical_one_before() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(49, 10, area));
}
#[test]
fn test_is_on_divider_vertical_one_after() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(51, 10, area));
}
#[test]
fn test_is_on_divider_vertical_two_before() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(!split.is_on_divider(48, 10, area));
}
#[test]
fn test_is_on_divider_vertical_two_after() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(!split.is_on_divider(52, 10, area));
}
#[test]
fn test_is_on_divider_vertical_at_left_edge() {
let mut split = ResizableSplit::new(5);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(5, 10, area));
assert!(split.is_on_divider(4, 10, area));
assert!(split.is_on_divider(6, 10, area));
}
#[test]
fn test_is_on_divider_vertical_at_right_edge() {
let mut split = ResizableSplit::new(95);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(95, 10, area));
assert!(split.is_on_divider(94, 10, area));
assert!(split.is_on_divider(96, 10, area));
}
#[test]
fn test_is_on_divider_vertical_with_area_offset() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(10, 5, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(60, 10, area));
assert!(split.is_on_divider(59, 10, area));
assert!(split.is_on_divider(61, 10, area));
assert!(!split.is_on_divider(58, 10, area));
assert!(!split.is_on_divider(62, 10, area));
}
#[test]
fn test_is_on_divider_vertical_row_doesnt_matter() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 0, area));
assert!(split.is_on_divider(50, 10, area));
assert!(split.is_on_divider(50, 19, area));
}
#[test]
fn test_is_on_divider_horizontal_exact_position() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 10, area));
}
#[test]
fn test_is_on_divider_horizontal_one_before() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 9, area));
}
#[test]
fn test_is_on_divider_horizontal_one_after() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 11, area));
}
#[test]
fn test_is_on_divider_horizontal_two_before() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(!split.is_on_divider(50, 8, area));
}
#[test]
fn test_is_on_divider_horizontal_two_after() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(!split.is_on_divider(50, 12, area));
}
#[test]
fn test_is_on_divider_horizontal_at_top_edge() {
let mut split = ResizableSplit::new_with_direction(5, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 100);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 5, area));
assert!(split.is_on_divider(50, 4, area));
assert!(split.is_on_divider(50, 6, area));
}
#[test]
fn test_is_on_divider_horizontal_at_bottom_edge() {
let mut split = ResizableSplit::new_with_direction(95, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 100);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 95, area));
assert!(split.is_on_divider(50, 94, area));
assert!(split.is_on_divider(50, 96, area));
}
#[test]
fn test_is_on_divider_horizontal_with_area_offset() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(10, 5, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(50, 15, area));
assert!(split.is_on_divider(50, 14, area));
assert!(split.is_on_divider(50, 16, area));
assert!(!split.is_on_divider(50, 13, area));
assert!(!split.is_on_divider(50, 17, area));
}
#[test]
fn test_is_on_divider_horizontal_column_doesnt_matter() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(0, 10, area));
assert!(split.is_on_divider(50, 10, area));
assert!(split.is_on_divider(99, 10, area));
}
#[test]
fn test_start_drag_sets_is_dragging() {
let mut split = ResizableSplit::new(50);
assert!(!split.is_dragging);
split.start_drag();
assert!(split.is_dragging);
}
#[test]
fn test_stop_drag_clears_is_dragging() {
let mut split = ResizableSplit::new(50);
split.start_drag();
assert!(split.is_dragging);
split.stop_drag();
assert!(!split.is_dragging);
}
#[test]
fn test_multiple_start_drag_calls() {
let mut split = ResizableSplit::new(50);
split.start_drag();
assert!(split.is_dragging);
split.start_drag();
assert!(split.is_dragging);
}
#[test]
fn test_multiple_stop_drag_calls() {
let mut split = ResizableSplit::new(50);
split.stop_drag();
assert!(!split.is_dragging);
split.stop_drag();
assert!(!split.is_dragging);
}
#[test]
fn test_drag_lifecycle() {
let mut split = ResizableSplit::new(50);
assert!(!split.is_dragging);
split.start_drag();
assert!(split.is_dragging);
split.stop_drag();
assert!(!split.is_dragging);
split.start_drag();
assert!(split.is_dragging);
split.stop_drag();
assert!(!split.is_dragging);
}
#[test]
fn test_update_from_mouse_vertical_does_not_update_when_not_dragging() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.update_from_mouse(75, 10, area);
assert_eq!(split.split_percent, 50); }
#[test]
fn test_update_from_mouse_vertical_updates_when_dragging() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(75, 10, area);
assert_eq!(split.split_percent, 75);
}
#[test]
fn test_update_from_mouse_vertical_calculates_percentage_correctly() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(25, 10, area);
assert_eq!(split.split_percent, 25);
split.update_from_mouse(75, 10, area);
assert_eq!(split.split_percent, 75);
split.update_from_mouse(50, 10, area);
assert_eq!(split.split_percent, 50);
}
#[test]
fn test_update_from_mouse_vertical_with_area_offset() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(10, 5, 100, 20);
split.start_drag();
split.update_from_mouse(60, 10, area);
assert_eq!(split.split_percent, 50);
split.update_from_mouse(85, 10, area);
assert_eq!(split.split_percent, 75);
}
#[test]
fn test_update_from_mouse_vertical_clamps_to_min_percent() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(5, 10, area);
assert_eq!(split.split_percent, 10);
split.update_from_mouse(0, 10, area);
assert_eq!(split.split_percent, 10);
}
#[test]
fn test_update_from_mouse_vertical_clamps_to_max_percent() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(95, 10, area);
assert_eq!(split.split_percent, 90);
split.update_from_mouse(99, 10, area);
assert_eq!(split.split_percent, 90);
}
#[test]
fn test_update_from_mouse_vertical_mouse_before_area() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(10, 5, 100, 20);
split.start_drag();
split.update_from_mouse(5, 10, area);
assert_eq!(split.split_percent, 10); }
#[test]
fn test_update_from_mouse_vertical_mouse_after_area() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(150, 10, area);
assert_eq!(split.split_percent, 90); }
#[test]
fn test_update_from_mouse_vertical_zero_width_area() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 0, 20);
split.start_drag();
split.update_from_mouse(10, 10, area);
assert_eq!(split.split_percent, 50); }
#[test]
fn test_update_from_mouse_horizontal_does_not_update_when_not_dragging() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.update_from_mouse(50, 15, area);
assert_eq!(split.split_percent, 50); }
#[test]
fn test_update_from_mouse_horizontal_updates_when_dragging() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(50, 15, area);
assert_eq!(split.split_percent, 75);
}
#[test]
fn test_update_from_mouse_horizontal_calculates_percentage_correctly() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(50, 5, area);
assert_eq!(split.split_percent, 25);
split.update_from_mouse(50, 10, area);
assert_eq!(split.split_percent, 50);
split.update_from_mouse(50, 15, area);
assert_eq!(split.split_percent, 75); }
#[test]
fn test_update_from_mouse_horizontal_with_area_offset() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(10, 5, 100, 20);
split.start_drag();
split.update_from_mouse(50, 15, area);
assert_eq!(split.split_percent, 50);
split.update_from_mouse(50, 20, area);
assert_eq!(split.split_percent, 75);
}
#[test]
fn test_update_from_mouse_horizontal_clamps_to_min_percent() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(50, 1, area);
assert_eq!(split.split_percent, 10);
split.update_from_mouse(50, 0, area);
assert_eq!(split.split_percent, 10);
}
#[test]
fn test_update_from_mouse_horizontal_clamps_to_max_percent() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(50, 19, area);
assert_eq!(split.split_percent, 90);
split.update_from_mouse(50, 20, area);
assert_eq!(split.split_percent, 90);
}
#[test]
fn test_update_from_mouse_horizontal_mouse_before_area() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(10, 5, 100, 20);
split.start_drag();
split.update_from_mouse(50, 2, area);
assert_eq!(split.split_percent, 10); }
#[test]
fn test_update_from_mouse_horizontal_mouse_after_area() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(50, 50, area);
assert_eq!(split.split_percent, 90); }
#[test]
fn test_update_from_mouse_horizontal_zero_height_area() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 0);
split.start_drag();
split.update_from_mouse(50, 10, area);
assert_eq!(split.split_percent, 50); }
#[test]
fn test_boundary_minimum_area_size_vertical() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 1, 1);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 0);
}
#[test]
fn test_boundary_minimum_area_size_horizontal() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 1, 1);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 0);
}
#[test]
fn test_boundary_max_area_offset_vertical() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(u16::MAX - 100, 0, 100, 20);
split.update_divider_position(area);
let expected = (u16::MAX - 100) + 50;
assert_eq!(split.divider_pos, expected);
}
#[test]
fn test_boundary_max_area_offset_horizontal() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, u16::MAX - 100, 100, 100);
split.update_divider_position(area);
let expected = (u16::MAX - 100) + 50;
assert_eq!(split.divider_pos, expected);
}
#[test]
fn test_boundary_divider_at_position_zero() {
let mut split = ResizableSplit::new(5);
let area = Rect::new(0, 0, 100, 20);
split.update_divider_position(area);
assert!(split.is_on_divider(4, 10, area));
assert!(split.is_on_divider(5, 10, area));
assert!(split.is_on_divider(6, 10, area));
}
#[test]
fn test_boundary_extreme_split_positions() {
let mut split = ResizableSplit::new(5);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(10, 10, area);
assert_eq!(split.split_percent, 10);
let mut split = ResizableSplit::new(95);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(90, 10, area);
assert_eq!(split.split_percent, 90); }
#[test]
fn test_right_percent_calculates_correctly() {
let split = ResizableSplit::new(70);
assert_eq!(split.right_percent(), 30);
let split = ResizableSplit::new(50);
assert_eq!(split.right_percent(), 50);
let split = ResizableSplit::new(25);
assert_eq!(split.right_percent(), 75);
}
#[test]
fn test_bottom_percent_is_alias_for_right_percent() {
let split = ResizableSplit::new_with_direction(70, SplitDirection::Horizontal);
assert_eq!(split.bottom_percent(), 30);
assert_eq!(split.bottom_percent(), split.right_percent());
}
#[test]
fn test_integration_complete_drag_cycle_vertical() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
assert_eq!(split.split_percent, 50);
assert!(!split.is_dragging);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 50);
assert!(split.is_on_divider(50, 10, area));
split.start_drag();
assert!(split.is_dragging);
split.update_from_mouse(70, 10, area);
assert_eq!(split.split_percent, 70);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 70);
split.stop_drag();
assert!(!split.is_dragging);
split.update_from_mouse(80, 10, area);
assert_eq!(split.split_percent, 70); }
#[test]
fn test_integration_complete_drag_cycle_horizontal() {
let mut split = ResizableSplit::new_with_direction(50, SplitDirection::Horizontal);
let area = Rect::new(0, 0, 100, 40);
assert_eq!(split.split_percent, 50);
assert!(!split.is_dragging);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 20);
assert!(split.is_on_divider(50, 20, area));
split.start_drag();
assert!(split.is_dragging);
split.update_from_mouse(50, 30, area);
assert_eq!(split.split_percent, 75);
split.update_divider_position(area);
assert_eq!(split.divider_pos, 30);
split.stop_drag();
assert!(!split.is_dragging);
}
#[test]
fn test_integration_dragging_respects_bounds() {
let mut split = ResizableSplit::new(50);
let area = Rect::new(0, 0, 100, 20);
split.start_drag();
split.update_from_mouse(95, 10, area);
assert_eq!(split.split_percent, 90);
split.update_from_mouse(5, 10, area);
assert_eq!(split.split_percent, 10);
split.update_from_mouse(60, 10, area);
assert_eq!(split.split_percent, 60);
}
#[test]
fn test_integration_divider_hit_area_at_boundaries() {
let mut split = ResizableSplit::new(5);
let area = Rect::new(0, 0, 20, 10);
split.update_divider_position(area);
assert!(split.is_on_divider(0, 5, area));
assert!(split.is_on_divider(1, 5, area));
assert!(split.is_on_divider(2, 5, area));
assert!(!split.is_on_divider(3, 5, area));
}