use super::*;
use crate::history::HistoryState;
#[test]
fn test_ctrl_c_sets_quit_flag() {
let mut app = app_with_query(".");
app.handle_key_event(key_with_mods(KeyCode::Char('c'), KeyModifiers::CONTROL));
assert!(app.should_quit);
}
#[test]
fn test_q_sets_quit_flag_in_normal_mode() {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Normal;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(app.should_quit);
}
#[test]
fn test_q_does_not_quit_in_insert_mode() {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(!app.should_quit);
assert_eq!(app.query(), ".q");
}
#[test]
fn test_enter_sets_results_output_mode() {
let mut app = app_with_query(".");
app.handle_key_event(key(KeyCode::Enter));
assert_eq!(app.output_mode, Some(OutputMode::Results));
assert!(app.should_quit);
}
#[test]
fn test_enter_saves_successful_query_to_history() {
let mut app = app_with_query(".name");
let initial_count = app.history.total_count();
assert!(app.query.as_ref().unwrap().result.is_ok());
app.handle_key_event(key(KeyCode::Enter));
assert_eq!(app.history.total_count(), initial_count + 1);
assert!(app.should_quit);
}
#[test]
fn test_enter_does_not_save_failed_query_to_history() {
let mut app = test_app(r#"{"name": "test"}"#);
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('|')));
flush_debounced_query(&mut app);
let initial_count = app.history.total_count();
assert!(app.query.as_ref().unwrap().result.is_err());
app.handle_key_event(key(KeyCode::Enter));
assert_eq!(app.history.total_count(), initial_count);
assert!(app.should_quit);
}
#[test]
fn test_enter_does_not_save_empty_query_to_history() {
let mut app = app_with_query("");
let initial_count = app.history.total_count();
app.handle_key_event(key(KeyCode::Enter));
assert_eq!(app.history.total_count(), initial_count);
assert!(app.should_quit);
}
#[test]
fn test_ctrl_q_outputs_query_and_saves_successful_query() {
let mut app = app_with_query(".name");
let initial_count = app.history.total_count();
app.handle_key_event(key_with_mods(KeyCode::Char('q'), KeyModifiers::CONTROL));
assert_eq!(app.history.total_count(), initial_count + 1);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_ctrl_q_does_not_save_failed_query() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.history = HistoryState::empty();
app.handle_key_event(key(KeyCode::Char('|')));
flush_debounced_query(&mut app);
let initial_count = app.history.total_count();
assert!(app.query.as_ref().unwrap().result.is_err());
app.handle_key_event(key_with_mods(KeyCode::Char('q'), KeyModifiers::CONTROL));
assert_eq!(app.history.total_count(), initial_count);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_shift_enter_outputs_query_and_saves_successful_query() {
let mut app = app_with_query(".name");
let initial_count = app.history.total_count();
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::SHIFT));
assert_eq!(app.history.total_count(), initial_count + 1);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_shift_enter_does_not_save_failed_query() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.history = HistoryState::empty();
app.handle_key_event(key(KeyCode::Char('|')));
flush_debounced_query(&mut app);
let initial_count = app.history.total_count();
assert!(app.query.as_ref().unwrap().result.is_err());
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::SHIFT));
assert_eq!(app.history.total_count(), initial_count);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_alt_enter_outputs_query_and_saves_successful_query() {
let mut app = app_with_query(".name");
let initial_count = app.history.total_count();
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::ALT));
assert_eq!(app.history.total_count(), initial_count + 1);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_alt_enter_does_not_save_failed_query() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.history = HistoryState::empty();
app.handle_key_event(key(KeyCode::Char('|')));
flush_debounced_query(&mut app);
let initial_count = app.history.total_count();
assert!(app.query.as_ref().unwrap().result.is_err());
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::ALT));
assert_eq!(app.history.total_count(), initial_count);
assert_eq!(app.output_mode, Some(OutputMode::Query));
assert!(app.should_quit);
}
#[test]
fn test_shift_tab_switches_focus_to_results() {
let mut app = app_with_query(".");
app.focus = Focus::InputField;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::ResultsPane);
}
#[test]
fn test_shift_tab_switches_focus_to_input() {
let mut app = app_with_query(".");
app.focus = Focus::ResultsPane;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::InputField);
}
#[test]
fn test_global_keys_work_regardless_of_focus() {
let mut app = app_with_query(".");
app.focus = Focus::ResultsPane;
app.handle_key_event(key_with_mods(KeyCode::Char('c'), KeyModifiers::CONTROL));
assert!(app.should_quit);
}
#[test]
fn test_insert_mode_text_input_updates_query() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('.')));
assert_eq!(app.query(), ".");
}
#[test]
fn test_query_execution_resets_scroll() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.results_scroll.offset = 50;
app.handle_key_event(key(KeyCode::Char('.')));
assert_eq!(app.results_scroll.offset, 0);
}
#[test]
fn test_history_with_emoji() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".emoji_field 🚀");
app.handle_key_event(key_with_mods(KeyCode::Char('p'), KeyModifiers::CONTROL));
assert_eq!(app.query(), ".emoji_field 🚀");
}
#[test]
fn test_history_with_multibyte_chars() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".café | .naïve");
app.handle_key_event(key_with_mods(KeyCode::Char('p'), KeyModifiers::CONTROL));
assert_eq!(app.query(), ".café | .naïve");
}
#[test]
fn test_history_search_with_unicode() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".café");
app.history.add_entry_in_memory(".coffee");
app.handle_key_event(key_with_mods(KeyCode::Char('r'), KeyModifiers::CONTROL));
app.handle_key_event(key(KeyCode::Char('c')));
app.handle_key_event(key(KeyCode::Char('a')));
app.handle_key_event(key(KeyCode::Char('f')));
assert_eq!(app.history.filtered_count(), 1);
}
#[test]
fn test_cycling_stops_at_oldest() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".first");
app.handle_key_event(key_with_mods(KeyCode::Char('p'), KeyModifiers::CONTROL));
assert_eq!(app.query(), ".first");
app.handle_key_event(key_with_mods(KeyCode::Char('p'), KeyModifiers::CONTROL));
app.handle_key_event(key_with_mods(KeyCode::Char('p'), KeyModifiers::CONTROL));
assert_eq!(app.query(), ".first");
}
#[test]
fn test_history_popup_with_single_entry() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".single");
app.handle_key_event(key_with_mods(KeyCode::Char('r'), KeyModifiers::CONTROL));
assert!(app.history.is_visible());
app.handle_key_event(key(KeyCode::Up));
assert_eq!(app.history.selected_index(), 0);
app.handle_key_event(key(KeyCode::Down));
assert_eq!(app.history.selected_index(), 0);
}
#[test]
fn test_filter_with_no_matches() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".foo");
app.history.add_entry_in_memory(".bar");
app.handle_key_event(key_with_mods(KeyCode::Char('r'), KeyModifiers::CONTROL));
app.handle_key_event(key(KeyCode::Char('x')));
app.handle_key_event(key(KeyCode::Char('y')));
app.handle_key_event(key(KeyCode::Char('z')));
assert_eq!(app.history.filtered_count(), 0);
}
#[test]
fn test_backspace_on_empty_search() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".test");
app.handle_key_event(key_with_mods(KeyCode::Char('r'), KeyModifiers::CONTROL));
assert_eq!(app.history.search_query(), "");
app.handle_key_event(key(KeyCode::Backspace));
assert_eq!(app.history.search_query(), "");
}
#[test]
fn test_q_quits_in_results_pane_insert_mode() {
let mut app = app_with_query("");
app.focus = Focus::ResultsPane;
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(app.should_quit);
}
#[test]
fn test_q_does_not_quit_in_input_field_insert_mode() {
let mut app = app_with_query("");
app.focus = Focus::InputField;
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(!app.should_quit);
assert!(app.query().contains('q'));
}
#[test]
fn test_q_quits_in_input_field_normal_mode() {
let mut app = app_with_query("");
app.focus = Focus::InputField;
app.input.editor_mode = EditorMode::Normal;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(app.should_quit);
}
#[test]
fn test_q_quits_in_results_pane_normal_mode() {
let mut app = app_with_query("");
app.focus = Focus::ResultsPane;
app.input.editor_mode = EditorMode::Normal;
app.handle_key_event(key(KeyCode::Char('q')));
assert!(app.should_quit);
}
#[test]
fn test_focus_switch_preserves_editor_mode() {
let mut app = app_with_query("");
app.focus = Focus::InputField;
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::ResultsPane);
assert_eq!(app.input.editor_mode, EditorMode::Insert);
app.handle_key_event(key(KeyCode::Char('q')));
assert!(app.should_quit);
}
#[test]
fn test_backtab_hides_ai_popup_when_switching_to_results() {
let mut app = app_with_query(".");
app.focus = Focus::InputField;
app.ai.visible = true;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::ResultsPane);
assert!(!app.ai.visible);
assert!(app.saved_ai_visibility_for_results);
}
#[test]
fn test_backtab_hides_tooltip_when_switching_to_results() {
let mut app = app_with_query(".");
app.focus = Focus::InputField;
app.tooltip.enabled = true;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::ResultsPane);
assert!(!app.tooltip.enabled);
assert!(app.saved_tooltip_visibility_for_results);
}
#[test]
fn test_backtab_restores_ai_popup_when_switching_to_input() {
let mut app = app_with_query(".");
app.focus = Focus::ResultsPane;
app.saved_ai_visibility_for_results = true;
app.ai.visible = false;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::InputField);
assert!(app.ai.visible);
}
#[test]
fn test_backtab_restores_tooltip_when_switching_to_input() {
let mut app = app_with_query(".");
app.focus = Focus::ResultsPane;
app.saved_tooltip_visibility_for_results = true;
app.tooltip.enabled = false;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::InputField);
assert!(app.tooltip.enabled);
}
#[test]
fn test_backtab_round_trip_preserves_popup_state() {
let mut app = app_with_query(".");
app.focus = Focus::InputField;
app.ai.visible = true;
app.tooltip.enabled = true;
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::ResultsPane);
assert!(!app.ai.visible);
assert!(!app.tooltip.enabled);
app.handle_key_event(key(KeyCode::BackTab));
assert_eq!(app.focus, Focus::InputField);
assert!(app.ai.visible);
assert!(app.tooltip.enabled);
}
#[test]
fn test_tooltip_initializes_enabled() {
let app = test_app(TEST_JSON);
assert!(app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_toggles_tooltip_from_enabled() {
let mut app = app_with_query(".");
assert!(app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(!app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_toggles_tooltip_from_disabled() {
let mut app = app_with_query(".");
app.tooltip.toggle(); assert!(!app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_works_in_insert_mode() {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
assert!(app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(!app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_works_in_normal_mode() {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Normal;
app.focus = Focus::InputField;
assert!(app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(!app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_works_when_results_pane_focused() {
let mut app = app_with_query(".");
app.focus = Focus::ResultsPane;
assert!(app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(!app.tooltip.enabled);
}
#[test]
fn test_ctrl_t_preserves_current_function() {
let mut app = app_with_query("select(.x)");
app.tooltip.set_current_function(Some("select".to_string()));
assert!(app.tooltip.enabled);
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert!(!app.tooltip.enabled);
assert_eq!(app.tooltip.current_function, Some("select".to_string()));
}
#[test]
fn test_ctrl_t_round_trip() {
let mut app = app_with_query(".");
let initial_enabled = app.tooltip.enabled;
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
app.handle_key_event(key_with_mods(KeyCode::Char('t'), KeyModifiers::CONTROL));
assert_eq!(app.tooltip.enabled, initial_enabled);
}
#[test]
fn test_tab_does_not_accept_autocomplete_in_results_pane() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::ResultsPane;
let suggestions = vec![crate::autocomplete::Suggestion::new(
".name",
crate::autocomplete::SuggestionType::Field,
)];
app.autocomplete.update_suggestions(suggestions);
assert!(app.autocomplete.is_visible());
app.handle_key_event(key(KeyCode::Tab));
assert_eq!(app.query(), ".na"); assert!(app.autocomplete.is_visible()); }
#[test]
fn test_vim_navigation_blocked_when_help_visible() {
let mut app = app_with_query(".test");
app.input.editor_mode = EditorMode::Normal;
app.focus = Focus::InputField;
app.help.visible = true;
app.handle_key_event(key(KeyCode::Char('h'))); app.handle_key_event(key(KeyCode::Char('l'))); app.handle_key_event(key(KeyCode::Char('w'))); app.handle_key_event(key(KeyCode::Char('x')));
assert_eq!(app.query(), ".test");
assert!(app.help.visible);
}
#[test]
fn test_history_popup_enter_not_intercepted_by_global() {
let mut app = app_with_query("");
app.input.editor_mode = EditorMode::Insert;
app.history.add_entry_in_memory(".selected");
app.handle_key_event(key_with_mods(KeyCode::Char('r'), KeyModifiers::CONTROL));
assert!(app.history.is_visible());
app.handle_key_event(key(KeyCode::Enter));
assert!(!app.history.is_visible());
assert_eq!(app.query(), ".selected");
assert!(app.output_mode.is_none()); assert!(!app.should_quit); }
#[test]
fn test_ctrl_q_executes_pending_query_before_exit() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('.')));
app.handle_key_event(key(KeyCode::Char('n')));
app.handle_key_event(key(KeyCode::Char('a')));
app.handle_key_event(key(KeyCode::Char('m')));
app.handle_key_event(key(KeyCode::Char('e')));
assert!(app.debouncer.has_pending());
app.handle_key_event(key_with_mods(KeyCode::Char('q'), KeyModifiers::CONTROL));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Query));
}
#[test]
fn test_shift_enter_executes_pending_query_before_exit() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('.')));
app.handle_key_event(key(KeyCode::Char('t')));
app.handle_key_event(key(KeyCode::Char('e')));
app.handle_key_event(key(KeyCode::Char('s')));
app.handle_key_event(key(KeyCode::Char('t')));
assert!(app.debouncer.has_pending());
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::SHIFT));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Query));
}
#[test]
fn test_alt_enter_executes_pending_query_before_exit() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('.')));
app.handle_key_event(key(KeyCode::Char('i')));
app.handle_key_event(key(KeyCode::Char('d')));
assert!(app.debouncer.has_pending());
app.handle_key_event(key_with_mods(KeyCode::Enter, KeyModifiers::ALT));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Query));
}
#[test]
fn test_enter_executes_pending_query_before_exit() {
let mut app = test_app(TEST_JSON);
app.input.editor_mode = EditorMode::Insert;
app.handle_key_event(key(KeyCode::Char('[')));
app.handle_key_event(key(KeyCode::Char('0')));
app.handle_key_event(key(KeyCode::Char(']')));
assert!(app.debouncer.has_pending());
app.handle_key_event(key(KeyCode::Enter));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Results));
}
#[test]
fn test_ctrl_f_opens_search() {
let mut app = app_with_query(".test");
assert!(!app.search.is_visible());
app.handle_key_event(key_with_mods(KeyCode::Char('f'), KeyModifiers::CONTROL));
assert!(app.search.is_visible());
}
#[test]
fn test_ctrl_f_works_in_insert_mode() {
let mut app = app_with_query(".test");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
app.handle_key_event(key_with_mods(KeyCode::Char('f'), KeyModifiers::CONTROL));
assert!(app.search.is_visible());
}
#[test]
fn test_ctrl_f_works_in_results_pane() {
let mut app = app_with_query(".test");
app.focus = Focus::ResultsPane;
app.handle_key_event(key_with_mods(KeyCode::Char('f'), KeyModifiers::CONTROL));
assert!(app.search.is_visible());
}