use super::*;
#[test]
fn test_tab_accepts_field_suggestion_replaces_from_dot() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
use crate::query::ResultType;
assert_eq!(
app.query.as_ref().unwrap().base_query_for_suggestions,
Some(".".to_string()),
"base_query should remain '.' since .na returns null"
);
assert_eq!(
app.query.as_ref().unwrap().base_type_for_suggestions,
Some(ResultType::Object),
"base_type should be Object (root object)"
);
let suggestions = vec![crate::autocomplete::Suggestion::new(
"name",
crate::autocomplete::SuggestionType::Field,
)];
app.autocomplete.update_suggestions(suggestions);
app.handle_key_event(key(KeyCode::Tab));
assert_eq!(app.query(), ".name");
assert!(!app.autocomplete.is_visible());
}
#[test]
fn test_tab_accepts_array_suggestion_appends() {
let mut app = app_with_query(".services");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
use crate::query::ResultType;
assert_eq!(
app.query.as_ref().unwrap().base_query_for_suggestions,
Some(".services".to_string()),
"base_query should be '.services'"
);
assert_eq!(
app.query.as_ref().unwrap().base_type_for_suggestions,
Some(ResultType::ArrayOfObjects),
"base_type should be ArrayOfObjects"
);
assert_eq!(app.input.textarea.cursor().1, 9);
let suggestions = vec![crate::autocomplete::Suggestion::new(
"[].name",
crate::autocomplete::SuggestionType::Field,
)];
app.autocomplete.update_suggestions(suggestions);
app.handle_key_event(key(KeyCode::Tab));
assert_eq!(app.query(), ".services[].name");
assert!(!app.autocomplete.is_visible());
}
#[test]
fn test_tab_accepts_array_suggestion_replaces_short_partial() {
let mut app = app_with_query(".services");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
use crate::query::ResultType;
assert_eq!(
app.query.as_ref().unwrap().base_query_for_suggestions,
Some(".services".to_string())
);
assert_eq!(
app.query.as_ref().unwrap().base_type_for_suggestions,
Some(ResultType::ArrayOfObjects)
);
app.input.textarea.insert_str(".s");
let suggestions = vec![crate::autocomplete::Suggestion::new(
"[].serviceArn",
crate::autocomplete::SuggestionType::Field,
)];
app.autocomplete.update_suggestions(suggestions);
app.handle_key_event(key(KeyCode::Tab));
assert_eq!(app.query(), ".services[].serviceArn");
assert!(!app.autocomplete.is_visible());
}
#[test]
fn test_tab_accepts_nested_array_suggestion() {
let mut app = app_with_query(".items[].tags");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
use crate::query::ResultType;
assert_eq!(
app.query.as_ref().unwrap().base_query_for_suggestions,
Some(".items[].tags".to_string()),
"base_query should be '.items[].tags'"
);
assert_eq!(
app.query.as_ref().unwrap().base_type_for_suggestions,
Some(ResultType::ArrayOfObjects),
"base_type should be ArrayOfObjects"
);
app.input.textarea.insert_char('.');
let suggestions = vec![crate::autocomplete::Suggestion::new(
"[].name",
crate::autocomplete::SuggestionType::Field,
)];
app.autocomplete.update_suggestions(suggestions);
app.handle_key_event(key(KeyCode::Tab));
assert_eq!(app.query(), ".items[].tags[].name");
assert!(!app.autocomplete.is_visible());
}
#[test]
fn test_enter_accepts_suggestion_when_autocomplete_visible() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
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::Enter));
assert!(!app.should_quit);
assert!(app.output_mode.is_none());
assert_eq!(app.query(), ".name");
}
#[test]
fn test_enter_closes_autocomplete_popup_after_selection() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
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::Enter));
assert!(!app.autocomplete.is_visible());
}
#[test]
fn test_enter_exits_application_when_autocomplete_not_visible() {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
assert!(!app.autocomplete.is_visible());
app.handle_key_event(key(KeyCode::Enter));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Results));
}
#[test]
fn test_enter_with_shift_modifier_bypasses_autocomplete_check() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
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_with_mods(KeyCode::Enter, KeyModifiers::SHIFT));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Query));
}
#[test]
fn test_enter_with_alt_modifier_bypasses_autocomplete_check() {
let mut app = app_with_query(".na");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
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_with_mods(KeyCode::Enter, KeyModifiers::ALT));
assert!(app.should_quit);
assert_eq!(app.output_mode, Some(OutputMode::Query));
}
#[test]
fn test_enter_tab_equivalence_for_autocomplete() {
let suggestions = [
("name", crate::autocomplete::SuggestionType::Field),
("age", crate::autocomplete::SuggestionType::Field),
("length", crate::autocomplete::SuggestionType::Function),
("keys", crate::autocomplete::SuggestionType::Function),
];
for (text, stype) in suggestions {
let mut app_enter = app_with_query(".");
app_enter.input.editor_mode = EditorMode::Insert;
app_enter.focus = Focus::InputField;
let mut app_tab = app_with_query(".");
app_tab.input.editor_mode = EditorMode::Insert;
app_tab.focus = Focus::InputField;
let suggestion = crate::autocomplete::Suggestion::new(text, stype.clone());
app_enter
.autocomplete
.update_suggestions(vec![suggestion.clone()]);
app_tab.autocomplete.update_suggestions(vec![suggestion]);
assert!(app_enter.autocomplete.is_visible());
assert!(app_tab.autocomplete.is_visible());
app_enter.handle_key_event(key(KeyCode::Enter));
app_tab.handle_key_event(key(KeyCode::Tab));
assert_eq!(
app_enter.query(),
app_tab.query(),
"Enter and Tab should produce identical query strings for '{}'",
text
);
assert!(!app_enter.autocomplete.is_visible());
assert!(!app_tab.autocomplete.is_visible());
}
}
#[test]
fn test_enter_accepts_autocomplete_and_closes_popup() {
let suggestions = ["name", "age", "city", "services", "items"];
for text in suggestions {
let mut app = app_with_query(".");
app.input.editor_mode = EditorMode::Insert;
app.focus = Focus::InputField;
let suggestion =
crate::autocomplete::Suggestion::new(text, crate::autocomplete::SuggestionType::Field);
app.autocomplete.update_suggestions(vec![suggestion]);
assert!(app.autocomplete.is_visible());
app.handle_key_event(key(KeyCode::Enter));
assert!(
!app.autocomplete.is_visible(),
"Autocomplete should be hidden after Enter"
);
assert!(
app.query().contains(text),
"Query '{}' should contain suggestion text '{}'",
app.query(),
text
);
assert!(
!app.should_quit,
"Should not quit when accepting autocomplete"
);
}
}
#[test]
fn test_enter_exits_when_autocomplete_not_visible() {
let focus_states = [Focus::InputField, Focus::ResultsPane];
let editor_modes = [EditorMode::Insert, EditorMode::Normal];
for focus in focus_states {
for mode in editor_modes {
let mut app = app_with_query(".");
app.focus = focus;
app.input.editor_mode = mode;
app.autocomplete.hide();
assert!(!app.autocomplete.is_visible());
app.handle_key_event(key(KeyCode::Enter));
assert!(
app.should_quit,
"Should quit when Enter pressed without autocomplete (focus: {:?}, mode: {:?})",
focus, mode
);
assert_eq!(
app.output_mode,
Some(OutputMode::Results),
"Output mode should be Results"
);
}
}
}