use std::fs;
use std::io::Write;
use tempfile::{NamedTempFile, TempDir};
#[test]
fn test_cli_encrypt_with_text_arg() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "encrypt", "--text", "Hello", "--shift", "3"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Khoor"),
"Expected 'Khoor' in output, got: {}",
stdout
);
}
#[test]
fn test_cli_encrypt_stdin_matches_text_arg_for_surrounding_spaces() {
use std::io::Write;
use std::process::{Command, Stdio};
let text_arg_output = Command::new("cargo")
.args([
"run",
"--",
"encrypt",
"--text",
" Hello ",
"--shift",
"3",
])
.output()
.expect("Failed to execute CLI with --text");
assert!(text_arg_output.status.success());
let text_arg_line = String::from_utf8_lossy(&text_arg_output.stdout)
.lines()
.last()
.unwrap_or("")
.to_string();
let mut stdin_child = Command::new("cargo")
.args(["run", "--", "encrypt", "--shift", "3"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("Failed to spawn CLI for stdin");
stdin_child
.stdin
.as_mut()
.unwrap()
.write_all(b" Hello \n")
.unwrap();
let stdin_output = stdin_child.wait_with_output().unwrap();
assert!(stdin_output.status.success());
let stdin_stdout = String::from_utf8_lossy(&stdin_output.stdout);
let stdin_line = stdin_stdout
.strip_prefix("Enter text: ")
.unwrap_or(&stdin_stdout)
.trim_end_matches(['\n', '\r'])
.to_string();
assert_eq!(
text_arg_line, stdin_line,
"--text line: {:?}, stdin ciphertext: {:?}, full stdin stdout: {:?}",
text_arg_line, stdin_line, stdin_stdout
);
assert_eq!(stdin_line, " Khoor ");
}
#[test]
fn test_cli_decrypt_with_text_arg() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "decrypt", "--text", "Khoor", "--shift", "3"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Hello"),
"Expected 'Hello' in output, got: {}",
stdout
);
}
#[test]
fn test_cli_encrypt_from_file() {
let mut temp_file = NamedTempFile::new().unwrap();
write!(temp_file, "Hello World").unwrap();
let file_path = temp_file.path().to_string_lossy().to_string();
let output = std::process::Command::new("cargo")
.args(["run", "--", "encrypt", "--file", &file_path, "--shift", "3"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Khoor Zruog"),
"Expected 'Khoor Zruog' in output, got: {}",
stdout
);
}
#[test]
fn test_cli_encrypt_output_to_file() {
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.path().join("output.txt");
let output_path_str = output_path.to_string_lossy().to_string();
let result = std::process::Command::new("cargo")
.args([
"run",
"--",
"encrypt",
"--text",
"Hello",
"--shift",
"3",
"--output",
&output_path_str,
])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&result.stdout);
let content = fs::read_to_string(&output_path).unwrap();
assert_eq!(content, "Khoor");
assert!(
stdout.contains(&output_path_str),
"Output message should contain file path '{}', got: {}",
output_path_str,
stdout
);
}
#[test]
fn test_cli_nonexistent_file_error_contains_path() {
let nonexistent_path = "/tmp/nonexistent_caesar_test_file_12345.txt";
let output = std::process::Command::new("cargo")
.args([
"run",
"--",
"encrypt",
"--file",
nonexistent_path,
"--shift",
"3",
])
.output()
.expect("Failed to execute CLI");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains(nonexistent_path),
"Error message should contain file path '{}', got: {}",
nonexistent_path,
stderr
);
}
#[test]
fn test_cli_both_text_and_file_error() {
let mut temp_file = NamedTempFile::new().unwrap();
write!(temp_file, "content").unwrap();
let file_path = temp_file.path().to_string_lossy().to_string();
let output = std::process::Command::new("cargo")
.args([
"run", "--", "encrypt", "--text", "Hello", "--file", &file_path, "--shift", "3",
])
.output()
.expect("Failed to execute CLI");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!output.status.success(),
"Command should fail on clap validation"
);
assert!(
stderr.contains("cannot be used with") || stderr.contains("conflicts with"),
"Error should mention clap conflict, got: {}",
stderr
);
}
#[test]
fn test_cli_brute_force_both_text_and_file_error() {
let mut temp_file = NamedTempFile::new().unwrap();
write!(temp_file, "content").unwrap();
let file_path = temp_file.path().to_string_lossy().to_string();
let output = std::process::Command::new("cargo")
.args([
"run",
"--",
"brute-force",
"--text",
"Khoor",
"--file",
&file_path,
])
.output()
.expect("Failed to execute CLI");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!output.status.success(),
"Command should fail on clap validation"
);
assert!(
stderr.contains("cannot be used with") || stderr.contains("conflicts with"),
"Error should mention clap conflict, got: {}",
stderr
);
}
#[test]
fn test_cli_encrypt_empty_file() {
let temp_file = NamedTempFile::new().unwrap();
let file_path = temp_file.path().to_string_lossy().to_string();
let output = std::process::Command::new("cargo")
.args(["run", "--", "encrypt", "--file", &file_path, "--shift", "3"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.trim().is_empty(),
"Expected empty output for empty file, got: '{}'",
stdout.trim()
);
}
#[test]
fn test_cli_brute_force_output() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "brute-force", "--text", "Khoor"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Brute Force Decryption"),
"Should contain brute force header, got: {}",
stdout
);
assert!(
stdout.contains("Shift 3: Hello"),
"Shift 3 should decrypt to 'Hello', got: {}",
stdout
);
}
#[test]
fn test_cli_version_matches_cargo_toml() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "--version"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
let expected_version = env!("CARGO_PKG_VERSION");
assert!(
stdout.contains(expected_version),
"CLI version should be {} from Cargo.toml, got: {}",
expected_version,
stdout
);
}
#[test]
fn test_cli_encrypt_unicode_text() {
let output = std::process::Command::new("cargo")
.args([
"run",
"--",
"encrypt",
"--text",
"Hello世界",
"--shift",
"3",
])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Khoor世界"),
"Expected 'Khoor世界' in output, got: {}",
stdout
);
}
#[test]
fn test_cli_safe_mode_invalid_shift_error() {
let output = std::process::Command::new("cargo")
.args([
"run", "--", "encrypt", "--text", "Hello", "--shift", "30", "--safe",
])
.output()
.expect("Failed to execute CLI");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Invalid shift value") || stderr.contains("out of range"),
"Should show shift validation error, got: {}",
stderr
);
}
#[test]
fn test_cli_safe_mode_empty_text_from_file() {
let temp_file = NamedTempFile::new().unwrap();
let file_path = temp_file.path().to_string_lossy().to_string();
let output = std::process::Command::new("cargo")
.args([
"run", "--", "encrypt", "--file", &file_path, "--shift", "3", "--safe",
])
.output()
.expect("Failed to execute CLI");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("empty"),
"Should show empty text error, got: {}",
stderr
);
}
#[test]
fn test_cli_brute_force_includes_shift_zero() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "brute-force", "--text", "Khoor"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Shift 0:"),
"Brute force output should include shift 0, got: {}",
stdout
);
}
#[test]
fn test_cli_brute_force_shift_zero_is_original() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "brute-force", "--text", "Khoor"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Shift 0: Khoor"),
"Shift 0 should show original text 'Khoor', got: {}",
stdout
);
}
#[test]
fn test_cli_encrypt_help_shows_correct_shift_description() {
let output = std::process::Command::new("cargo")
.args(["run", "--", "encrypt", "--help"])
.output()
.expect("Failed to execute CLI");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("safe mode: -25 to 25"),
"Help text should mention safe mode range, got: {}",
stdout
);
assert!(
!stdout.contains("Shift value (1-25)"),
"Help text should NOT contain outdated '1-25' range, got: {}",
stdout
);
}