use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use crate::api::{BindingAction, KeyBinding};
use crate::keys::{classify_key, KeyDecision};
use crate::run::is_actionable_key_event;
use crate::state::TuiAction;
#[test]
fn expected_key_accepts_with_key_name() {
let decision = classify_key(
KeyEvent::new(KeyCode::Char('y'), KeyModifiers::CONTROL),
10,
&["ctrl-y".to_string()],
&[],
);
assert_eq!(decision, KeyDecision::Accept(Some("ctrl-y".to_string())));
}
#[test]
fn enter_accepts_without_expected_key_name() {
let decision = classify_key(
KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE),
10,
&[],
&[],
);
assert_eq!(decision, KeyDecision::Accept(None));
}
#[test]
fn key_release_events_are_ignored() {
assert!(is_actionable_key_event(&KeyEvent::new(
KeyCode::Enter,
KeyModifiers::NONE,
)));
assert!(!is_actionable_key_event(&KeyEvent::new_with_kind(
KeyCode::Enter,
KeyModifiers::NONE,
KeyEventKind::Release,
)));
}
#[test]
fn bind_key_can_abort() {
let decision = classify_key(
KeyEvent::new(KeyCode::Char('x'), KeyModifiers::CONTROL),
10,
&[],
&[KeyBinding {
key: "ctrl-x".to_string(),
action: BindingAction::Abort,
}],
);
assert_eq!(decision, KeyDecision::Abort);
}
#[test]
fn shifted_navigation_keys_scroll_preview() {
let decision = classify_key(
KeyEvent::new(KeyCode::Down, KeyModifiers::SHIFT),
10,
&[],
&[],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewDown));
let decision = classify_key(
KeyEvent::new(KeyCode::PageUp, KeyModifiers::SHIFT),
10,
&[],
&[],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewPageUp(10)));
}
#[test]
fn bind_key_can_scroll_preview() {
let decision = classify_key(
KeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
10,
&[],
&[KeyBinding {
key: "ctrl-j".to_string(),
action: BindingAction::PreviewDown,
}],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewDown));
}
#[test]
fn bind_key_can_scroll_preview_to_edges() {
let decision = classify_key(
KeyEvent::new(KeyCode::End, KeyModifiers::NONE),
10,
&[],
&[KeyBinding {
key: "end".to_string(),
action: BindingAction::PreviewBottom,
}],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewBottom));
}
#[test]
fn bind_key_can_drive_basic_navigation_actions() {
let decision = classify_key(
KeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
10,
&[],
&[KeyBinding {
key: "ctrl-j".to_string(),
action: BindingAction::MoveSelectionDown,
}],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::MoveSelectionDown));
let decision = classify_key(
KeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
10,
&[],
&[KeyBinding {
key: "ctrl-a".to_string(),
action: BindingAction::MoveCursorStart,
}],
);
assert_eq!(decision, KeyDecision::Action(TuiAction::MoveCursorStart));
}
#[test]
fn readline_keys_map_to_editing_actions() {
let cases = [
(
KeyEvent::new(KeyCode::Char('b'), KeyModifiers::CONTROL),
TuiAction::MoveCursorLeft,
),
(
KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL),
TuiAction::MoveCursorRight,
),
(
KeyEvent::new(KeyCode::Char('k'), KeyModifiers::CONTROL),
TuiAction::DeleteToEnd,
),
(
KeyEvent::new(KeyCode::Char('w'), KeyModifiers::CONTROL),
TuiAction::DeleteWord,
),
(
KeyEvent::new(KeyCode::Left, KeyModifiers::ALT),
TuiAction::MoveCursorWordLeft,
),
(
KeyEvent::new(KeyCode::Right, KeyModifiers::ALT),
TuiAction::MoveCursorWordRight,
),
(
KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL),
TuiAction::Backspace,
),
(
KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL),
TuiAction::DeleteOrExit,
),
];
for (key, action) in cases {
assert_eq!(classify_key(key, 10, &[], &[]), KeyDecision::Action(action));
}
}