use crate::common::harness::EditorTestHarness;
use crossterm::event::{KeyCode, KeyModifiers};
use portable_pty::{native_pty_system, PtySize};
#[test]
fn test_split_horizontal() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness.type_text("Buffer 1").unwrap();
harness.assert_buffer_content("Buffer 1");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split horiz").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Split pane horiz");
harness.assert_buffer_content("Buffer 1");
}
#[test]
fn test_split_vertical() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness.type_text("Buffer 1").unwrap();
harness.assert_buffer_content("Buffer 1");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Split pane vertically");
harness.assert_buffer_content("Buffer 1");
}
#[test]
fn test_split_navigation() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness.type_text("First buffer").unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_buffer_content("First buffer");
harness.send_key(KeyCode::End, KeyModifiers::NONE).unwrap();
harness.type_text(" - extended").unwrap();
harness.assert_buffer_content("First buffer - extended");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("next split").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Switched to next");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("prev split").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Switched to prev");
}
#[test]
fn test_close_split() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("close split").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Closed split");
}
#[test]
fn test_cannot_close_last_split() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("close split").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Cannot close split");
}
#[test]
#[ignore]
fn test_split_size_adjustment() {
let mut harness = EditorTestHarness::new(80, 24).unwrap();
harness
.send_key(KeyCode::Char('v'), KeyModifiers::ALT)
.unwrap();
harness
.send_key(KeyCode::Char('='), KeyModifiers::ALT)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Adjusted split size by 5%");
harness
.send_key(KeyCode::Char('-'), KeyModifiers::ALT)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Adjusted split size by -5%");
}
#[test]
fn test_nested_splits() {
let mut harness = EditorTestHarness::new(120, 40).unwrap();
harness.type_text("Buffer 1").unwrap();
harness
.send_key(KeyCode::Char('v'), KeyModifiers::ALT)
.unwrap();
harness.type_text("Buffer 2").unwrap();
harness
.send_key(KeyCode::Char('h'), KeyModifiers::ALT)
.unwrap();
harness.type_text("Buffer 3").unwrap();
harness.render().unwrap();
}
#[test]
fn test_split_with_file_operations() {
let mut harness = EditorTestHarness::with_temp_project(80, 24).unwrap();
let project_dir = harness.project_dir().unwrap();
let file1 = project_dir.join("file1.txt");
let file2 = project_dir.join("file2.txt");
std::fs::write(&file1, "File 1 content").unwrap();
std::fs::write(&file2, "File 2 content").unwrap();
harness.open_file(&file1).unwrap();
harness.assert_buffer_content("File 1 content");
harness
.send_key(KeyCode::Char('v'), KeyModifiers::ALT)
.unwrap();
harness.open_file(&file2).unwrap();
harness.assert_buffer_content("File 2 content");
harness.render().unwrap();
harness.assert_screen_contains("file1.txt");
harness.assert_screen_contains("file2.txt");
}
#[test]
fn test_toggle_maximize_split() {
let mut harness = EditorTestHarness::new(120, 40).unwrap();
harness.type_text("Buffer 1").unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Split pane vertically");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("togmax").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Maximized split");
}
#[test]
fn test_toggle_unmaximize_split() {
let mut harness = EditorTestHarness::with_temp_project(120, 40).unwrap();
let project_dir = harness.project_dir().unwrap();
let file1 = project_dir.join("file1.txt");
let file2 = project_dir.join("file2.txt");
std::fs::write(&file1, "File 1 content").unwrap();
std::fs::write(&file2, "File 2 content").unwrap();
harness.open_file(&file1).unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.open_file(&file2).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("togmax").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("togmax").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Restored all splits");
harness.assert_screen_contains("file1.txt");
harness.assert_screen_contains("file2.txt");
}
#[test]
fn test_cannot_toggle_maximize_single_split() {
let mut harness = EditorTestHarness::new(120, 40).unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("togmax").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
harness.assert_screen_contains("Cannot maximize");
}
#[test]
fn test_close_last_buffer_in_split_closes_split() {
let mut harness = EditorTestHarness::with_temp_project(120, 40).unwrap();
let project_dir = harness.project_dir().unwrap();
let file1 = project_dir.join("file1.txt");
std::fs::write(&file1, "File 1 content").unwrap();
harness.open_file(&file1).unwrap();
harness.assert_buffer_content("File 1 content");
assert_eq!(harness.editor().get_split_count(), 1);
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains(">command"))
.unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains("Split pane vertically"))
.unwrap();
assert_eq!(harness.editor().get_split_count(), 2);
let tabs = harness
.editor()
.get_split_tabs(harness.editor().get_active_split());
assert_eq!(tabs.len(), 1, "New split should have exactly 1 tab");
harness
.send_key(KeyCode::Char('w'), KeyModifiers::ALT)
.unwrap();
harness.render().unwrap();
assert_eq!(
harness.editor().get_split_count(),
1,
"Expected split to be closed when closing last buffer"
);
harness.assert_screen_contains("file1.txt");
}
#[test]
fn test_close_unique_buffer_in_split_closes_split() {
let mut harness = EditorTestHarness::with_temp_project(120, 40).unwrap();
let project_dir = harness.project_dir().unwrap();
let file1 = project_dir.join("file1.txt");
let file2 = project_dir.join("file2.txt");
std::fs::write(&file1, "File 1 content").unwrap();
std::fs::write(&file2, "File 2 content").unwrap();
harness.open_file(&file1).unwrap();
harness.assert_buffer_content("File 1 content");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains(">command"))
.unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains("Split pane vertically"))
.unwrap();
assert_eq!(harness.editor().get_split_count(), 2);
harness.open_file(&file2).unwrap();
harness
.wait_until(|h| h.screen_to_string().contains("file2.txt"))
.unwrap();
harness
.send_key(KeyCode::PageUp, KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('w'), KeyModifiers::ALT)
.unwrap();
harness.render().unwrap();
let active_split = harness.editor().get_active_split();
let tabs = harness.editor().get_split_tabs(active_split);
assert_eq!(
tabs.len(),
1,
"Split should have exactly 1 tab (file2 only)"
);
assert_eq!(harness.editor().get_split_count(), 2);
harness
.send_key(KeyCode::Char('w'), KeyModifiers::ALT)
.unwrap();
harness.render().unwrap();
assert_eq!(
harness.editor().get_split_count(),
1,
"Expected split to be closed when closing last unique buffer"
);
harness.assert_screen_contains("file1.txt");
}
#[test]
fn test_close_terminal_in_split_closes_split() {
if native_pty_system()
.openpty(PtySize {
rows: 1,
cols: 1,
pixel_width: 0,
pixel_height: 0,
})
.is_err()
{
eprintln!("Skipping terminal test: PTY not available in this environment");
return;
}
let mut harness = EditorTestHarness::with_temp_project(120, 40).unwrap();
let project_dir = harness.project_dir().unwrap();
let file1 = project_dir.join("file1.txt");
std::fs::write(&file1, "File 1 content").unwrap();
harness.open_file(&file1).unwrap();
harness.assert_buffer_content("File 1 content");
assert_eq!(harness.editor().get_split_count(), 1);
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains(">command"))
.unwrap();
harness.type_text("split vert").unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness
.wait_until(|h| h.screen_to_string().contains("Split pane vertically"))
.unwrap();
assert_eq!(harness.editor().get_split_count(), 2);
harness
.editor_mut()
.set_terminal_jump_to_end_on_output(false);
harness.editor_mut().open_terminal();
harness.render().unwrap();
harness.assert_screen_contains("Terminal");
assert!(
harness.editor().is_terminal_mode(),
"Should be in terminal mode after opening terminal"
);
let active_split = harness.editor().get_active_split();
let tabs = harness.editor().get_split_tabs(active_split);
let file1_buffer = tabs
.iter()
.find(|&&b| !harness.editor().is_terminal_buffer(b))
.copied()
.expect("Should have file1 buffer in tabs");
harness
.editor_mut()
.close_tab_in_split(file1_buffer, active_split);
harness.render().unwrap();
assert_eq!(harness.editor().get_split_count(), 2);
harness.editor_mut().close_tab();
harness.render().unwrap();
assert_eq!(
harness.editor().get_split_count(),
1,
"Expected split to be closed when closing terminal (the last buffer in split)"
);
harness.assert_screen_contains("file1.txt");
harness.assert_screen_not_contains("Terminal");
}