use super::*;
#[test]
fn copy_paths_and_names_from_a_panel() {
let dir = std::env::temp_dir().join(format!("fm84-copy-names-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("a.txt"), "").unwrap();
std::fs::write(dir.join("b.txt"), "").unwrap();
let mut app_state = AppState::new();
app_state.options = crate::options::Options::default();
app_state.is_left_active = true;
app_state.open_dir(true, dir.clone(), Some("b.txt".as_ref()));
let chord = |app_state: &mut AppState, modifiers| handle_key(app_state, KeyEvent::new(KeyCode::Char('c'), modifiers));
chord(&mut app_state, KeyModifiers::CONTROL);
assert_eq!(app_state.clipboard, dir.join("b.txt").to_string_lossy());
assert!(app_state.find_note.as_deref().unwrap().starts_with("Copied path: "));
chord(&mut app_state, KeyModifiers::ALT);
assert_eq!(app_state.clipboard, "b.txt");
app_state.selected_left.insert("a.txt".into());
app_state.selected_left.insert("b.txt".into());
chord(&mut app_state, KeyModifiers::ALT);
assert_eq!(app_state.clipboard, "a.txt\nb.txt");
assert_eq!(app_state.find_note.as_deref(), Some("Copied 2 names"));
press(&mut app_state, KeyCode::Down);
assert!(app_state.find_note.is_none());
app_state.selected_left.clear();
app_state.state_left.select(Some(0));
chord(&mut app_state, KeyModifiers::CONTROL);
assert_eq!(app_state.clipboard, dir.to_string_lossy());
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn swap_the_panels_and_send_the_other_one_here() {
let dir = std::env::temp_dir().join(format!("fm84-swap-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
for name in ["one", "two", "three"] {
std::fs::create_dir_all(dir.join(name)).unwrap();
}
std::fs::write(dir.join("one").join("a.txt"), "").unwrap();
std::fs::write(dir.join("one").join("b.txt"), "").unwrap();
let mut app_state = AppState::new();
app_state.is_left_active = true;
app_state.open_dir(true, dir.join("one"), Some("b.txt".as_ref()));
app_state.selected_left.insert("a.txt".into());
app_state.open_dir(false, dir.join("two"), None);
app_state.is_left_active = false;
app_state.new_tab();
app_state.open_dir(false, dir.join("three"), None);
app_state.is_left_active = true;
let chord = |app_state: &mut AppState, c, modifiers| handle_key(app_state, KeyEvent::new(KeyCode::Char(c), modifiers));
let cursor = |app_state: &AppState, is_left: bool| {
let (children, state) = if is_left { (&app_state.children_left, &app_state.state_left) } else { (&app_state.children_right, &app_state.state_right) };
children[state.selected().unwrap()].name_full.clone()
};
chord(&mut app_state, 'u', KeyModifiers::CONTROL);
assert_eq!((app_state.dir_left.clone(), app_state.dir_right.clone()), (dir.join("three"), dir.join("one")));
assert_eq!((app_state.tabs_left.list.len(), app_state.tabs_left.active, app_state.tabs_right.list.len()), (2, 1, 1));
assert!(!app_state.is_left_active);
assert_eq!(cursor(&app_state, false), "b.txt");
assert!(app_state.selected_right.contains(std::ffi::OsStr::new("a.txt")) && app_state.selected_left.is_empty());
app_state.select_tab(true, 0);
assert_eq!(app_state.dir_left, dir.join("two"));
chord(&mut app_state, 'i', KeyModifiers::ALT);
assert_eq!(app_state.dir_left, dir.join("one"));
assert_eq!(cursor(&app_state, true), "b.txt");
assert!(!app_state.is_left_active);
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn sort_from_the_keys_and_the_headings() {
use crate::options::{Options, SortKey};
use crossterm::event::{MouseButton, MouseEvent, MouseEventKind};
let dir = std::env::temp_dir().join(format!("fm84-sort-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("a.txt"), "a long one").unwrap();
std::fs::write(dir.join("b.rs"), "short").unwrap();
std::fs::write(dir.join("c.md"), "mid size").unwrap();
let mut app_state = AppState::new();
app_state.options = Options::default();
app_state.is_left_active = true;
app_state.open_dir(true, dir.clone(), Some("b.rs".as_ref()));
let names = |app_state: &AppState| app_state.children_left.iter().skip(1).map(|item| item.name_full.clone()).collect::<Vec<_>>();
let control = |app_state: &mut AppState, n| handle_key(app_state, KeyEvent::new(KeyCode::F(n), KeyModifiers::CONTROL));
control(&mut app_state, 3);
assert_eq!(names(&app_state), ["a.txt", "b.rs", "c.md"]);
control(&mut app_state, 3);
assert!(app_state.options.sort_descending);
assert_eq!(names(&app_state), ["c.md", "b.rs", "a.txt"]);
control(&mut app_state, 4);
assert_eq!((app_state.options.sort_key, app_state.options.sort_descending), (SortKey::Extension, false));
assert_eq!(names(&app_state), ["c.md", "b.rs", "a.txt"]);
let cursor = app_state.state_left.selected().unwrap();
assert_eq!(app_state.children_left[cursor].name_full, "b.rs");
let mut terminal = ratatui::Terminal::new(ratatui::backend::TestBackend::new(120, 30)).unwrap();
crate::ui::render_ui(&mut terminal, &mut app_state);
let (cell, _) = *app_state.sort_headers.iter().find(|(_, key)| *key == SortKey::Size).unwrap();
let click = MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),
column: cell.x,
row: cell.y,
modifiers: KeyModifiers::NONE,
};
crate::input::handle_mouse(&mut app_state, click);
assert_eq!(app_state.options.sort_key, SortKey::Size);
assert_eq!(names(&app_state), ["b.rs", "c.md", "a.txt"]);
crate::ui::render_ui(&mut terminal, &mut app_state);
let heading: String = (cell.x..cell.x + cell.width).map(|x| terminal.backend().buffer()[(x, cell.y)].symbol().to_string()).collect();
assert_eq!(heading.trim_end(), "Size ↑");
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn go_to_a_path_and_back_and_forward() {
let dir = std::env::temp_dir().join(format!("fm84-go-to-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(dir.join("sub/deeper")).unwrap();
std::fs::write(dir.join("a.txt"), "text").unwrap();
let mut app_state = AppState::new();
app_state.is_left_active = true;
app_state.open_dir(true, dir.clone(), Some("sub".as_ref()));
let alt = |app_state: &mut AppState, code: KeyCode| handle_key(app_state, KeyEvent::new(code, KeyModifiers::ALT));
let ctrl_l = |app_state: &mut AppState| handle_key(app_state, KeyEvent::new(KeyCode::Char('l'), KeyModifiers::CONTROL));
let cursor = |app_state: &AppState| {
let index = app_state.state_left.selected().unwrap();
app_state.children_left[index].name.clone()
};
let type_in = |app_state: &mut AppState, text: &str| {
let Some(Dialog::Prompt(PromptKind::GoTo, input)) = &mut app_state.dialog else { panic!("no prompt") };
input.set(text.to_string());
};
ctrl_l(&mut app_state);
let Some(Dialog::Prompt(PromptKind::GoTo, input)) = &app_state.dialog else { panic!("no prompt") };
assert_eq!(input.text, format!("{}{}", dir.display(), std::path::MAIN_SEPARATOR));
press(&mut app_state, KeyCode::Char('s'));
press(&mut app_state, KeyCode::Tab);
press(&mut app_state, KeyCode::Char('d'));
press(&mut app_state, KeyCode::Tab);
press(&mut app_state, KeyCode::Enter);
assert_eq!(app_state.dir_left, dir.join("sub/deeper"));
ctrl_l(&mut app_state);
type_in(&mut app_state, "../../a.txt");
press(&mut app_state, KeyCode::Enter);
assert_eq!((app_state.dir_left.clone(), cursor(&app_state)), (dir.clone(), "a".to_string()));
ctrl_l(&mut app_state);
type_in(&mut app_state, "nowhere");
press(&mut app_state, KeyCode::Enter);
assert!(app_state.error.take().unwrap().contains("nowhere"));
assert_eq!(app_state.dir_left, dir);
alt(&mut app_state, KeyCode::Left);
assert_eq!(app_state.dir_left, dir.join("sub/deeper"));
alt(&mut app_state, KeyCode::Left);
assert_eq!((app_state.dir_left.clone(), cursor(&app_state)), (dir.clone(), "sub".to_string()));
alt(&mut app_state, KeyCode::Right);
assert_eq!(app_state.dir_left, dir.join("sub/deeper"));
press(&mut app_state, KeyCode::Backspace);
assert_eq!(app_state.dir_left, dir.join("sub"));
alt(&mut app_state, KeyCode::Right);
assert_eq!(app_state.dir_left, dir.join("sub"));
alt(&mut app_state, KeyCode::Left);
assert_eq!(app_state.dir_left, dir.join("sub/deeper"));
std::fs::remove_dir(dir.join("sub/deeper")).unwrap();
alt(&mut app_state, KeyCode::Right);
assert_eq!(app_state.dir_left, dir.join("sub"));
alt(&mut app_state, KeyCode::Left);
assert_eq!(app_state.dir_left, dir, "the gone one was passed over");
alt(&mut app_state, KeyCode::Right);
assert_eq!(app_state.dir_left, dir.join("sub"));
std::fs::remove_dir_all(&dir).unwrap();
}