use super::*;
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
fn key(code: KeyCode) -> KeyEvent {
KeyEvent {
code,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press,
state: KeyEventState::NONE,
}
}
fn ctrl(code: KeyCode) -> KeyEvent {
KeyEvent {
modifiers: KeyModifiers::CONTROL,
..key(code)
}
}
fn motion_preview() -> Preview {
let mut lines: Vec<String> = (1..=20).map(|i| format!("line {i}")).collect();
lines[4] = String::new();
lines[11] = String::new();
lines[6] = "fn main() {".into();
lines[14] = "}".into();
let body = lines.join("\n");
let mut p = Preview::new();
p.set_bytes("a.rs", body.as_bytes());
p.viewport = 10;
p
}
fn motions(p: &mut Preview, keys: &str) {
for c in keys.chars() {
assert!(p.motion_key(key(KeyCode::Char(c))), "motion {c}");
}
}
#[test]
fn counts_gg_g_and_pages() {
let mut p = motion_preview();
motions(&mut p, "3j");
assert_eq!(p.line(), Some(4));
motions(&mut p, "gg");
assert_eq!(p.line(), Some(1));
motions(&mut p, "5G");
assert_eq!(p.line(), Some(5));
motions(&mut p, "G");
assert_eq!(p.line(), Some(20));
assert!(p.motion_key(ctrl(KeyCode::Char('u'))));
assert_eq!(p.line(), Some(15));
assert!(p.motion_key(ctrl(KeyCode::Char('d'))));
assert_eq!(p.line(), Some(20));
assert!(p.motion_key(ctrl(KeyCode::Char('b'))));
assert_eq!(p.line(), Some(10));
for c in "7".chars() {
p.motion_key(key(KeyCode::Char(c)));
}
assert!(!p.motion_key(key(KeyCode::Char('x'))));
motions(&mut p, "j");
assert_eq!(p.line(), Some(11));
motions(&mut p, "g");
motions(&mut p, "j");
assert_eq!(p.line(), Some(12));
assert_eq!(p.motion_pending, None);
}
#[test]
fn paragraphs_brackets_and_view_positioning() {
let mut p = motion_preview();
motions(&mut p, "8G"); motions(&mut p, "{");
assert_eq!(p.line(), Some(5)); motions(&mut p, "}");
assert_eq!(p.line(), Some(12)); motions(&mut p, "7G");
motions(&mut p, "%");
assert_eq!(p.line(), Some(15));
motions(&mut p, "%");
assert_eq!(p.line(), Some(7));
motions(&mut p, "15G");
motions(&mut p, "zz");
assert_eq!(p.scroll, 9); motions(&mut p, "zt");
assert_eq!(p.scroll, 14);
motions(&mut p, "zb");
assert_eq!(p.scroll, 5); }
#[test]
fn motions_noop_on_cursorless_content() {
let mut p = Preview::new();
assert!(!p.motion_key(key(KeyCode::Char('j'))));
assert!(!p.motion_key(key(KeyCode::Char('G'))));
}
#[test]
fn visual_selects_and_copy_targets_it() {
let mut p = motion_preview();
p.move_cursor(1);
let (text, n) = p.copy_target().unwrap();
assert_eq!((text.as_str(), n), ("line 2\n", 1));
assert_eq!(p.visual_range(), None);
p.toggle_visual();
assert_eq!(p.visual_range(), Some((2, 2)));
p.move_cursor(2);
assert_eq!(p.visual_range(), Some((2, 4)));
let (text, n) = p.copy_target().unwrap();
assert_eq!(n, 3);
assert!(text.starts_with("line 2") && text.ends_with("line 4\n"));
motions(&mut p, "gg");
assert_eq!(p.visual_range(), Some((1, 2)));
assert!(p.clear_visual());
assert_eq!(p.visual_range(), None);
assert!(!p.clear_visual());
}
#[test]
fn cursor_walks_and_clamps() {
let mut p = Preview::new();
p.set_bytes("a.rs", b"one\ntwo\nthree");
assert_eq!(p.line(), Some(1));
p.move_cursor(1);
p.move_cursor(1);
assert_eq!(p.line(), Some(3));
p.move_cursor(1); assert_eq!(p.line(), Some(3));
p.move_cursor(-10); assert_eq!(p.line(), Some(1));
}
#[test]
fn cursorless_content_has_no_line() {
let mut p = Preview::new();
p.set_dir("src", vec![]);
assert_eq!(p.line(), None);
p.move_cursor(1);
assert_eq!(p.line(), None);
p.set_bytes("blob", b"\0\0binary\0");
assert_eq!(p.line(), None);
assert_eq!(p.readout(), None);
}
#[test]
fn cursor_resets_on_new_content() {
let mut p = Preview::new();
p.set_bytes("a.rs", b"one\ntwo\nthree");
p.move_cursor(2);
assert_eq!(p.line(), Some(3));
p.set_highlighted("b.rs", "rust", vec![Line::from("x")]);
assert_eq!(p.line(), Some(1));
assert_eq!(p.readout().as_deref(), Some("1/1"));
}
#[test]
fn scroll_follows_cursor_into_viewport() {
let mut p = Preview::new();
p.set_bytes(
"a.rs",
(1..=50)
.map(|i| format!("line{i}"))
.collect::<Vec<_>>()
.join("\n")
.as_bytes(),
);
for _ in 0..49 {
p.move_cursor(1);
}
p.clamp_scroll(10);
assert_eq!(p.scroll, 40); p.move_cursor(-49);
p.clamp_scroll(10);
assert_eq!(p.scroll, 0);
}