#[cfg(test)]
mod stdin_conversion_tests {
use std::process::{Command, Stdio};
use std::io::{Write, BufRead, BufReader};
use std::time::Duration;
fn run_toonconv_stdin(input: &str, args: &[&str]) -> Result<(String, String), String> {
let mut cmd = Command::new("cargo");
cmd.args(&["run", "--bin", "toonconv", "--"])
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = cmd.spawn()
.map_err(|e| format!("Failed to start process: {}", e))?;
if let Some(mut stdin) = child.stdin.take() {
stdin.write_all(input.as_bytes())
.map_err(|e| format!("Failed to write to stdin: {}", e))?;
}
let stdout = child.stdout.take()
.map(|mut stdout| {
let mut reader = BufReader::new(stdout);
let mut output = String::new();
reader.read_to_string(&mut output).unwrap();
output
}).unwrap_or_default();
let stderr = child.stderr.take()
.map(|mut stderr| {
let mut reader = BufReader::new(stderr);
let mut error = String::new();
reader.read_to_string(&mut error).unwrap();
error
}).unwrap_or_default();
let status = child.wait_with_output()
.map_err(|e| format!("Failed to wait for process: {}", e))?;
Ok((stdout, stderr))
}
#[test]
fn test_basic_stdin_conversion() {
let input = r#"{"name": "Alice", "age": 30, "active": true}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
assert!(stdout.contains("age:"));
assert!(stdout.contains("30"));
assert!(stdout.contains("active:"));
assert!(stdout.contains("true"));
assert!(!stdout.contains("{"));
assert!(!stdout.contains("}"));
assert!(!stdout.contains("\""));
}
#[test]
fn test_stdin_invalid_json() {
let input = r#"{"name": "test", "value": }"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(!stderr.is_empty(), "Should have error message");
assert!(stdout.is_empty() || stdout.trim().is_empty(), "Should have no TOON output");
assert!(stderr.contains("JSON parse error") || stderr.contains("parse error"),
"Should mention JSON parse error: {}", stderr);
}
#[test]
fn test_stdin_empty_input() {
let input = "";
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(!stderr.is_empty(), "Should have error message for empty input");
assert!(stdout.is_empty() || stdout.trim().is_empty(), "Should have no TOON output");
assert!(stderr.contains("Empty") || stderr.contains("empty"),
"Should mention empty input: {}", stderr);
}
#[test]
fn test_stdin_whitespace_input() {
let input = " \n\t ";
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(!stderr.is_empty(), "Should have error message for whitespace input");
assert!(stdout.is_empty() || stdout.trim().is_empty(), "Should have no TOON output");
}
#[test]
fn test_stdin_with_stats() {
let input = r#"{"name": "Alice", "age": 30}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--stats"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have output");
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
assert!(stdout.contains("Input size") || stdout.contains("output") || stdout.contains("statistics"),
"Should show statistics: {}", stdout);
}
#[test]
fn test_stdin_with_quiet() {
let input = r#"{"name": "Alice", "age": 30}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--quiet"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
let lines: Vec<&str> = stdout.lines().collect();
assert_eq!(lines.len(), 1, "Should have only TOON output line in quiet mode");
}
#[test]
fn test_stdin_with_custom_delimiter() {
let input = r#"[{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--delimiter", "tab"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains('\t'), "Should contain tab character");
assert!(stdout.contains("[2,]{id,name}:"));
assert!(stdout.contains("1\tAlice"));
assert!(stdout.contains("2\tBob"));
}
#[test]
fn test_stdin_with_custom_indent() {
let input = r#"{"user": {"name": "Alice", "settings": {"theme": "dark"}}}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--indent", "4"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("user:"));
assert!(stdout.contains("settings:"));
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
let lines: Vec<&str> = stdout.lines().collect();
assert!(lines.len() >= 3, "Should have multiple lines for nested structure");
}
#[test]
fn test_stdin_with_memory_limit() {
let input = r#"{"data": "test"}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--memory-limit", "1MB"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("data:"));
assert!(stdout.contains("test"));
}
#[test]
fn test_stdin_array_conversion() {
let input = r#"[1, 2, 3, 4, 5]"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.starts_with("[5]:"));
assert!(stdout.contains("1,2,3,4,5"));
}
#[test]
fn test_stdin_user_array_conversion() {
let input = r#"[{"name": "Alice", "role": "admin"}, {"name": "Bob", "role": "user"}]"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("[2,]{name,role}:"));
assert!(stdout.contains("Alice,admin"));
assert!(stdout.contains("Bob,user"));
}
#[test]
fn test_stdin_performance_small() {
use std::time::Instant;
let input = r#"{"name": "Alice", "age": 30, "active": true}"#;
let start = Instant::now();
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
let elapsed = start.elapsed();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(elapsed.as_millis() < 100, "Small input should convert in under 100ms, took {:?}", elapsed);
}
#[test]
fn test_stdin_with_verbose() {
let input = r#"{"name": "Alice", "age": 30}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin", "--verbose"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
assert!(stdout.contains("age:"));
assert!(stdout.contains("30"));
}
#[test]
fn test_stdin_help_message() {
let (stdout, stderr) = run_toonconv_stdin("", &["--stdin", "--help"]).unwrap();
assert!(!stdout.is_empty(), "Should show help message");
assert!(stdout.contains("toonconv") || stdout.contains("Convert JSON") || stdout.contains("usage"),
"Should contain help information: {}", stdout);
}
#[test]
fn test_stdin_multiline_json() {
let input = r#"{
"user": {
"name": "Alice",
"profile": {
"age": 30,
"location": "New York"
}
}
}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("user:"));
assert!(stdout.contains("name:"));
assert!(stdout.contains("Alice"));
assert!(stdout.contains("profile:"));
assert!(stdout.contains("age:"));
assert!(stdout.contains("30"));
assert!(stdout.contains("location:"));
assert!(stdout.contains("New York"));
}
#[test]
fn test_stdin_mixed_data_types() {
let input = r#"{
"string": "hello",
"number": 42,
"float": 3.14,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {"key": "value"}
}"#;
let (stdout, stderr) = run_toonconv_stdin(input, &["--stdin"]).unwrap();
assert!(stderr.is_empty(), "Should not have errors: {}", stderr);
assert!(!stdout.is_empty(), "Should have TOON output");
assert!(stdout.contains("string:"));
assert!(stdout.contains("hello"));
assert!(stdout.contains("number:"));
assert!(stdout.contains("42"));
assert!(stdout.contains("float:"));
assert!(stdout.contains("3.14"));
assert!(stdout.contains("boolean:"));
assert!(stdout.contains("true"));
assert!(stdout.contains("null:"));
assert!(stdout.contains("null"));
assert!(stdout.contains("array:"));
assert!(stdout.contains("[3]:"));
assert!(stdout.contains("1,2,3"));
assert!(stdout.contains("object:"));
assert!(stdout.contains("key:"));
assert!(stdout.contains("value"));
}
}