use super::*;
use ratatui::Terminal;
use ratatui::backend::TestBackend;
use sabiql_app::model::app_state::AppState;
use sabiql_app::model::shared::help::HelpOrigin;
use sabiql_app::model::shared::settings::KeymapPreset;
use sabiql_app::policy::write::sql_risk::AcknowledgeReason;
use sabiql_domain::query_history::{QueryHistoryEntry, QueryResultStatus};
use sabiql_domain::{
ConnectionId, DatabaseDiagnostic, DiagnosticField, DiagnosticLevel, QueryResult,
SqliteDiagnosticsSnapshot,
};
const POSTGRES_SEQ_SCAN_PLAN: &str =
"Seq Scan on users (cost=0.00..1000.00 rows=2550 width=36)\n Filter: (id > 10)";
const POSTGRES_INDEX_SCAN_PLAN: &str = "Index Scan using idx_users_id on users (cost=0.28..8.30 rows=1 width=36)\n Index Cond: (id > 10)";
const POSTGRES_PLAN_QUERY: &str = "SELECT * FROM users WHERE id > 10";
fn baseline_sqlite_diagnostics_snapshot() -> SqliteDiagnosticsSnapshot {
SqliteDiagnosticsSnapshot {
db_file: DiagnosticField::ok("/tmp/app.db"),
sqlite_version: DiagnosticField::ok("3.45.0"),
feature_summary: DiagnosticField::ok(
"FTS5: available\nFTS4: not available\nRTree: available\nJSON: available",
),
foreign_keys: DiagnosticField::ok("on"),
journal_mode: DiagnosticField::ok("wal"),
query_only: DiagnosticField::ok("off"),
busy_timeout: DiagnosticField::ok("5000"),
database_list: DiagnosticField::ok("0: main @ /tmp/app.db"),
quick_check: DiagnosticField::ok("ok"),
}
}
#[test]
fn sql_modal_with_completion() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT * FROM us".to_string());
state.sql_modal.enter_editing();
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_completion_popup_with_scroll() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT ".to_string());
state.sql_modal.enter_editing();
let candidates = vec![
CompletionCandidate {
text: "users".into(),
kind: CompletionKind::Table,
score: 100,
},
CompletionCandidate {
text: "posts".into(),
kind: CompletionKind::Table,
score: 90,
},
CompletionCandidate {
text: "comments".into(),
kind: CompletionKind::Table,
score: 80,
},
CompletionCandidate {
text: "id".into(),
kind: CompletionKind::Column,
score: 70,
},
CompletionCandidate {
text: "name".into(),
kind: CompletionKind::Column,
score: 60,
},
CompletionCandidate {
text: "email".into(),
kind: CompletionKind::Column,
score: 50,
},
CompletionCandidate {
text: "created_at".into(),
kind: CompletionKind::Column,
score: 40,
},
CompletionCandidate {
text: "updated_at".into(),
kind: CompletionKind::Column,
score: 30,
},
CompletionCandidate {
text: "COUNT".into(),
kind: CompletionKind::Keyword,
score: 20,
},
CompletionCandidate {
text: "DISTINCT".into(),
kind: CompletionKind::Keyword,
score: 10,
},
];
state
.sql_modal
.apply_completion_update(&candidates, 7, true);
for _ in 0..5 {
state.sql_modal.completion_next();
}
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_unknown_risk_acknowledge() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("DO $$ BEGIN DELETE FROM users; END $$".to_string());
state
.sql_modal
.begin_confirming_risk(AcknowledgeReason::UnknownRisk, "DO".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_high_risk_without_target_acknowledge() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("DROP TABLE a, b".to_string());
state
.sql_modal
.begin_confirming_risk(AcknowledgeReason::TargetNameUnavailable, "DROP".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_non_atomic_transaction_acknowledge() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("PRAGMA foreign_keys = OFF; CREATE TABLE users(id INTEGER)".to_string());
state.sql_modal.begin_confirming_risk(
AcknowledgeReason::NonAtomicTransaction,
"SQLite transaction".to_string(),
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_analyze_unknown_risk_acknowledge() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.begin_confirming_analyze_risk(
"MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN DELETE".to_string(),
AcknowledgeReason::UnknownRisk,
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_analyze_read_only_acknowledge() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.begin_confirming_analyze_risk(
"SELECT * FROM users".to_string(),
AcknowledgeReason::AnalyzeExecution,
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_ide_editing() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT 1".to_string());
state.sql_modal.enter_editing();
state.settings.load_keymap_preset(KeymapPreset::Ide);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_normal_cursor_at_tail() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT 1".to_string());
state.sql_modal.enter_normal();
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_success_select() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT * FROM users".to_string());
state.sql_modal.finish_adhoc_success(AdhocSuccessSnapshot {
command_tag: None,
row_count: 2,
execution_time_ms: 15,
mysql_diagnostics: Vec::new(),
});
state
.query
.set_current_result(Arc::new(QueryResult::success(
"SELECT * FROM users".to_string(),
vec!["id".to_string(), "name".to_string()],
vec![
vec!["1".to_string(), "Alice".to_string()],
vec!["2".to_string(), "Bob".to_string()],
],
15,
QuerySource::Adhoc,
)));
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_success_with_mysql_diagnostics() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("INSERT IGNORE INTO users (id) VALUES (1)".to_string());
state.sql_modal.finish_adhoc_success(AdhocSuccessSnapshot {
command_tag: Some(CommandTag::Insert(1)),
row_count: 1,
execution_time_ms: 15,
mysql_diagnostics: vec![
DatabaseDiagnostic {
level: DiagnosticLevel::Warning,
code: 1062,
message: "Duplicate entry '1' for key 'users.PRIMARY'".to_string(),
},
DatabaseDiagnostic {
level: DiagnosticLevel::Note,
code: 1050,
message: "Table 'users' already exists".to_string(),
},
],
});
state.query.set_current_result(Arc::new(
QueryResult::success(
"INSERT IGNORE INTO users (id) VALUES (1)".to_string(),
vec![],
vec![],
15,
QuerySource::Adhoc,
)
.with_command_tag(CommandTag::Insert(1))
.with_mysql_diagnostics(vec![DatabaseDiagnostic {
level: DiagnosticLevel::Warning,
code: 1062,
message: "Duplicate entry '1' for key 'users.PRIMARY'".to_string(),
}]),
));
let output = trim_line_endings(&render_to_string(&mut terminal, &mut state));
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_success_dml_with_command_tag() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("DELETE FROM users WHERE id = 1".to_string());
state.sql_modal.finish_adhoc_success(AdhocSuccessSnapshot {
command_tag: Some(CommandTag::Delete(3)),
row_count: 3,
execution_time_ms: 12,
mysql_diagnostics: Vec::new(),
});
state.query.set_current_result(Arc::new(
QueryResult::success(
"DELETE FROM users WHERE id = 1".to_string(),
vec![],
vec![],
12,
QuerySource::Adhoc,
)
.with_row_count(3)
.with_command_tag(CommandTag::Delete(3)),
));
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_success_ddl_create_table() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("CREATE TABLE backup AS SELECT * FROM users".to_string());
state.sql_modal.finish_adhoc_success(AdhocSuccessSnapshot {
command_tag: Some(CommandTag::Create("TABLE".to_string())),
row_count: 0,
execution_time_ms: 45,
mysql_diagnostics: Vec::new(),
});
state.query.set_current_result(Arc::new(
QueryResult::success(
"CREATE TABLE backup AS SELECT * FROM users".to_string(),
vec![],
vec![],
45,
QuerySource::Adhoc,
)
.with_command_tag(CommandTag::Create("TABLE".to_string())),
));
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_error_with_message() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("SELECT * FORM users".to_string());
state.sql_modal.finish_adhoc_error(
"ERROR: syntax error at or near \"FORM\"\nLINE 1: SELECT * FORM users\n ^"
.to_string(),
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_confirming_high_matched() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("DROP TABLE users".to_string());
let mut input = TextInputState::default();
input.set_content("users".to_string());
state.sql_modal.begin_confirming_high(
AdhocRiskDecision {
risk_level: RiskLevel::High,
label: "DROP",
},
"users".to_string(),
);
*state.sql_modal.confirming_high_input_mut().unwrap() = input;
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_confirming_high_unmatched() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state
.sql_modal
.editor_mut_for_input()
.set_content("DROP TABLE users".to_string());
let mut input = TextInputState::default();
input.set_content("use".to_string());
state.sql_modal.begin_confirming_high(
AdhocRiskDecision {
risk_level: RiskLevel::High,
label: "DROP",
},
"users".to_string(),
);
*state.sql_modal.confirming_high_input_mut().unwrap() = input;
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn help_overlay() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::Help);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn help_overlay_filtered_current_result() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.ui.set_focused_pane(FocusedPane::Result);
state.result_interaction.activate_cell(0, 0);
let origin = HelpOrigin::from_state(&state);
state.ui.help_mut().open(origin);
for ch in "copy".chars() {
state.ui.help_mut().insert_filter_char(ch);
}
state.ui.help_mut().enter_filter_editing();
state.modal.set_mode(InputMode::Help);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn help_overlay_long_key_rows() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::Help);
state.ui.help_mut().set_scroll_offset(58);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn help_overlay_narrow_horizontal_scroll() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal_sized(50, 24);
state.modal.set_mode(InputMode::Help);
state.ui.set_terminal_width(50);
state.ui.set_terminal_height(24);
state.ui.help_mut().set_scroll_offset(58);
state.ui.help_mut().set_horizontal_offset(18);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn command_palette_overlay() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::CommandPalette);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn settings_overlay() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.settings.open(state.ui.theme_id());
state.modal.set_mode(InputMode::Settings);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn settings_overlay_keymap() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.settings.open(state.ui.theme_id());
state.settings.switch_next_section();
state.modal.set_mode(InputMode::Settings);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn settings_overlay_er_diagram() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.settings.open(state.ui.theme_id());
state.settings.switch_next_section();
state.settings.switch_next_section();
state.modal.set_mode(InputMode::Settings);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn settings_overlay_er_diagram_custom_browser() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state
.settings
.load_er_browser(Some("Brave Browser".to_string()));
state.settings.open(state.ui.theme_id());
state.settings.switch_next_section();
state.settings.switch_next_section();
state.modal.set_mode(InputMode::Settings);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn table_picker_overlay() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::TablePicker);
state.ui.table_picker_mut().insert_filter_str("user");
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn mysql_table_picker_shows_table_names_without_database() {
let mut state = create_test_state();
state.session.activate_connection_with_target(
&ConnectionId::from_string("mysql-test"),
"mysql",
DatabaseType::MySQL,
"mysql://user@localhost:3306/app?ssl-mode=PREFERRED",
Some("app"),
);
state
.session
.mark_connected(Arc::new(fixtures::sample_metadata()));
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::TablePicker);
state.ui.table_picker_mut().insert_filter_str("user");
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn command_line_input() {
let mut state = postgres_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::CommandLine);
state.command_line_input.set_content("sql".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn query_history_picker_with_entries() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::QueryHistoryPicker);
state.query_history_picker.replace_entries(&[
QueryHistoryEntry::new_with_database(
"SELECT * FROM users WHERE id = 1".to_string(),
"2026-03-13T10:00:00Z".to_string(),
ConnectionId::from_string("test-conn"),
None,
QueryResultStatus::Success,
None,
),
QueryHistoryEntry::new_with_database(
"INSERT INTO orders (user_id, total) VALUES (1, 100)".to_string(),
"2026-03-13T11:00:00Z".to_string(),
ConnectionId::from_string("test-conn"),
None,
QueryResultStatus::Success,
Some(1),
),
QueryHistoryEntry::new_with_database(
"SELECT count(*) FROM users".to_string(),
"2026-03-13T12:00:00Z".to_string(),
ConnectionId::from_string("test-conn"),
None,
QueryResultStatus::Failed,
None,
),
]);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn query_history_picker_empty() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::QueryHistoryPicker);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn query_history_picker_filter_mode() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::QueryHistoryPicker);
state.query_history_picker.replace_entries(&[
QueryHistoryEntry::new_with_database(
"SELECT * FROM users".to_string(),
"2026-03-13T10:00:00Z".to_string(),
ConnectionId::from_string("test-conn"),
None,
QueryResultStatus::Success,
None,
),
QueryHistoryEntry::new_with_database(
"SELECT * FROM orders".to_string(),
"2026-03-13T11:00:00Z".to_string(),
ConnectionId::from_string("test-conn"),
None,
QueryResultStatus::Success,
None,
),
]);
state.query_history_picker.insert_filter_str("user");
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_plan_tab_placeholder() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.set_active_tab(SqlModalTab::Plan);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_plan_tab_with_plan_text() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.set_active_tab(SqlModalTab::Plan);
state.explain.set_plan(
"Seq Scan on users (cost=0.00..35.50 rows=2550 width=36)\n Filter: (id > 10)".to_string(),
DatabaseType::PostgreSQL,
false,
42,
POSTGRES_PLAN_QUERY,
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_plan_tab_with_error() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.set_active_tab(SqlModalTab::Plan);
state
.explain
.set_error("ERROR: relation \"nonexistent\" does not exist".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_compare_tab_empty() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.set_active_tab(SqlModalTab::Compare);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_compare_tab_right_only() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.explain.set_plan(
"Seq Scan on users (cost=0.00..10.20 rows=10 width=3273)\n Filter: email_verified"
.to_string(),
DatabaseType::PostgreSQL,
false,
40,
"SELECT * FROM users WHERE email_verified",
);
state.sql_modal.set_active_tab(SqlModalTab::Compare);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_compare_tab_with_verdict() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.explain.set_plan(
POSTGRES_SEQ_SCAN_PLAN.to_string(),
DatabaseType::PostgreSQL,
false,
100,
POSTGRES_PLAN_QUERY,
);
state.explain.set_plan(
POSTGRES_INDEX_SCAN_PLAN.to_string(),
DatabaseType::PostgreSQL,
false,
5,
POSTGRES_PLAN_QUERY,
);
state.sql_modal.set_active_tab(SqlModalTab::Compare);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_compare_tab_unavailable() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.explain.set_plan(
"CREATE TABLE foo (id int)".to_string(),
DatabaseType::PostgreSQL,
false,
0,
"CREATE TABLE foo",
);
state.explain.set_plan(
"ALTER TABLE foo ADD COLUMN bar text".to_string(),
DatabaseType::PostgreSQL,
false,
0,
"ALTER TABLE foo",
);
state.sql_modal.set_active_tab(SqlModalTab::Compare);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_compare_tab_narrow_stacked() {
let mut state = create_test_state();
let backend = TestBackend::new(50, 24);
let mut terminal = Terminal::new(backend).unwrap();
state.modal.set_mode(InputMode::SqlModal);
state.explain.set_plan(
POSTGRES_SEQ_SCAN_PLAN.to_string(),
DatabaseType::PostgreSQL,
false,
100,
POSTGRES_PLAN_QUERY,
);
state.explain.set_plan(
POSTGRES_INDEX_SCAN_PLAN.to_string(),
DatabaseType::PostgreSQL,
false,
5,
POSTGRES_PLAN_QUERY,
);
state.sql_modal.set_active_tab(SqlModalTab::Compare);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sql_modal_normal_initial() {
let mut state = create_test_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
fn sqlite_connected_state() -> AppState {
let mut state = create_test_state();
state.session.activate_connection_with_dsn(
&ConnectionId::new(),
"local",
DatabaseType::SQLite,
"sqlite:///tmp/app.db",
);
state
.session
.mark_connected(Arc::new(fixtures::sample_metadata()));
state
}
#[test]
fn sqlite_sql_modal_omits_compare_tab() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_sql_modal_plan_tab_labels_query_plan() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
state.modal.set_mode(InputMode::SqlModal);
state.sql_modal.set_active_tab(SqlModalTab::Plan);
state.explain.set_plan(
"SEARCH users USING INDEX idx_users_name\n - SCAN orders".to_string(),
DatabaseType::SQLite,
false,
42,
"DELETE FROM users WHERE name = 'alice'",
);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_loading() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
state.sqlite_diagnostics.begin_core_fetch();
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_loaded() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
let run_id = state.sqlite_diagnostics.begin_core_fetch();
state
.sqlite_diagnostics
.set_core_loaded(run_id, baseline_sqlite_diagnostics_snapshot());
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_partial_failure() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
let run_id = state.sqlite_diagnostics.begin_core_fetch();
let mut snapshot = baseline_sqlite_diagnostics_snapshot();
snapshot.feature_summary = DiagnosticField::Unavailable;
snapshot.foreign_keys = DiagnosticField::err("timeout");
snapshot.journal_mode = DiagnosticField::ok("delete");
snapshot.query_only = DiagnosticField::ok("on");
snapshot.quick_check = DiagnosticField::ok("row 1 missing from index idx_users");
state.sqlite_diagnostics.set_core_loaded(run_id, snapshot);
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_quick_check_pending() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
let run_id = state.sqlite_diagnostics.begin_core_fetch();
state
.sqlite_diagnostics
.set_core_loaded(run_id, baseline_sqlite_diagnostics_snapshot());
state.sqlite_diagnostics.begin_quick_check();
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_quick_check_not_run() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal();
let run_id = state.sqlite_diagnostics.begin_core_fetch();
let mut snapshot = baseline_sqlite_diagnostics_snapshot();
snapshot.quick_check = DiagnosticField::Pending;
state.sqlite_diagnostics.set_core_loaded(run_id, snapshot);
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn sqlite_diagnostics_overlay_wrapped_scroll() {
let mut state = sqlite_connected_state();
let mut terminal = create_test_terminal_sized(50, 24);
let run_id = state.sqlite_diagnostics.begin_core_fetch();
let mut snapshot = baseline_sqlite_diagnostics_snapshot();
snapshot.db_file = DiagnosticField::ok(
"/tmp/very/long/database/path/that/will/wrap/in/a/narrow/viewport/app.db",
);
state.sqlite_diagnostics.set_core_loaded(run_id, snapshot);
state.sqlite_diagnostics.set_scroll_offset(8);
state.modal.set_mode(InputMode::SqliteDiagnostics);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}