use super::output_capture::CapturedOutput;
use sqlmodel_console::renderables::QueryResults;
use sqlmodel_console::{OutputMode, SqlModelConsole};
#[test]
fn e2e_simple_query_results() {
let columns = vec!["id".to_string(), "name".to_string(), "email".to_string()];
let rows = vec![
vec![
"1".to_string(),
"Alice".to_string(),
"alice@example.com".to_string(),
],
vec![
"2".to_string(),
"Bob".to_string(),
"bob@example.com".to_string(),
],
vec![
"3".to_string(),
"Carol".to_string(),
"carol@example.com".to_string(),
],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("id");
output.assert_stdout_contains("name");
output.assert_stdout_contains("email");
output.assert_stdout_contains("Alice");
output.assert_stdout_contains("Bob");
output.assert_stdout_contains("Carol");
output.assert_stdout_contains("alice@example.com");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_query_results_row_count() {
let columns = vec!["id".to_string()];
let rows = vec![
vec!["1".to_string()],
vec!["2".to_string()],
vec!["3".to_string()],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("3");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_empty_query_results() {
let columns = vec!["id".to_string(), "name".to_string()];
let rows: Vec<Vec<String>> = vec![];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain.clone(), String::new());
output.assert_stdout_contains("id");
output.assert_stdout_contains("name");
output.assert_plain_mode_clean();
let has_empty_indicator =
plain.contains("0 rows") || plain.contains("Empty") || plain.lines().count() <= 3;
assert!(has_empty_indicator);
}
#[test]
fn e2e_single_column_results() {
let columns = vec!["count".to_string()];
let rows = vec![vec!["42".to_string()]];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("count");
output.assert_stdout_contains("42");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_many_columns() {
let columns: Vec<String> = (0..10).map(|i| format!("col_{i}")).collect();
let rows = vec![(0..10).map(|i| format!("val_{i}")).collect()];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("col_0");
output.assert_stdout_contains("col_9");
output.assert_stdout_contains("val_0");
output.assert_stdout_contains("val_9");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_large_dataset() {
let columns = vec!["id".to_string(), "value".to_string()];
let rows: Vec<Vec<String>> = (0..100)
.map(|i| vec![i.to_string(), format!("value_{i}")])
.collect();
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain.clone(), String::new());
output.assert_stdout_contains("id");
output.assert_stdout_contains("value");
output.assert_plain_mode_clean();
let line_count = plain.lines().count();
assert!(line_count >= 10, "Should render multiple rows");
}
#[test]
fn e2e_mixed_data_types() {
let columns = vec![
"integer".to_string(),
"float".to_string(),
"text".to_string(),
"boolean".to_string(),
"null".to_string(),
];
let rows = vec![
vec![
"42".to_string(),
"3.14159".to_string(),
"Hello, World!".to_string(),
"true".to_string(),
"NULL".to_string(),
],
vec![
"-1".to_string(),
"2.718".to_string(),
"Test".to_string(),
"false".to_string(),
"NULL".to_string(),
],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("42");
output.assert_stdout_contains("3.14159");
output.assert_stdout_contains("Hello, World!");
output.assert_stdout_contains("true");
output.assert_stdout_contains("NULL");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_unicode_content() {
let columns = vec!["name".to_string(), "description".to_string()];
let rows = vec![
vec!["日本語".to_string(), "Japanese text".to_string()],
vec!["café".to_string(), "French café".to_string()],
vec!["Müller".to_string(), "German name".to_string()],
vec!["🎉".to_string(), "Emoji support".to_string()],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("日本語");
output.assert_stdout_contains("café");
output.assert_stdout_contains("Müller");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_long_values() {
let columns = vec!["id".to_string(), "content".to_string()];
let long_content = "A".repeat(200);
let rows = vec![vec!["1".to_string(), long_content.clone()]];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain.clone(), String::new());
output.assert_stdout_contains("id");
output.assert_stdout_contains("content");
output.assert_plain_mode_clean();
assert!(plain.contains("AAA"));
}
#[test]
fn e2e_empty_string_values() {
let columns = vec!["id".to_string(), "optional_field".to_string()];
let rows = vec![
vec!["1".to_string(), String::new()],
vec!["2".to_string(), "has value".to_string()],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("id");
output.assert_stdout_contains("has value");
output.assert_plain_mode_clean();
}
#[test]
fn e2e_query_results_plain_console() {
let console = SqlModelConsole::with_mode(OutputMode::Plain);
let columns = vec!["status".to_string()];
let rows = vec![vec!["ok".to_string()]];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
assert!(console.is_plain());
output.assert_plain_mode_clean();
}
#[test]
fn e2e_query_results_parseable() {
let columns = vec!["a".to_string(), "b".to_string()];
let rows = vec![vec!["1".to_string(), "2".to_string()]];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
assert!(!plain.is_empty());
for line in plain.lines() {
assert!(line.len() < 10000);
}
}
#[test]
fn e2e_query_results_json() {
let columns = vec!["id".to_string(), "name".to_string()];
let rows = vec![vec!["1".to_string(), "Test".to_string()]];
let results = QueryResults::from_data(columns, rows);
let json_value = results.to_json();
let json_str = serde_json::to_string(&json_value).unwrap();
assert!(json_str.contains("id"));
assert!(json_str.contains("name"));
assert!(json_str.contains("Test"));
}
#[test]
fn e2e_pipe_delimited_format() {
let columns = vec!["id".to_string(), "name".to_string()];
let rows = vec![
vec!["1".to_string(), "Alice".to_string()],
vec!["2".to_string(), "Bob".to_string()],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
assert!(plain.contains('|') || plain.contains('\t') || plain.contains(' '));
}
#[test]
fn e2e_table_alignment() {
let columns = vec!["short".to_string(), "much_longer_column".to_string()];
let rows = vec![
vec!["a".to_string(), "b".to_string()],
vec!["longer".to_string(), "x".to_string()],
];
let results = QueryResults::from_data(columns, rows);
let plain = results.render_plain();
let output = CapturedOutput::from_strings(plain, String::new());
output.assert_stdout_contains("short");
output.assert_stdout_contains("much_longer_column");
output.assert_plain_mode_clean();
}