use std::io::Write;
use std::process::Command;
use tempfile::NamedTempFile;
fn create_temp_script(content: &str) -> NamedTempFile {
let mut temp_file = NamedTempFile::new().expect("Failed to create temp file");
temp_file
.write_all(content.as_bytes())
.expect("Failed to write to temp file");
temp_file
}
fn run_echo_comment_with_flags(script_path: &str, shell_flags: &str) -> (i32, String, String) {
let output = Command::new("target/debug/echo-comment")
.arg(format!("--shell-flags={}", shell_flags))
.arg(script_path)
.output()
.expect("Failed to execute binary");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
(exit_code, stdout, stderr)
}
fn run_echo_comment_with_flags_and_color(
script_path: &str,
shell_flags: &str,
color: &str,
) -> (i32, String, String) {
let output = Command::new("target/debug/echo-comment")
.arg(format!("--shell-flags={}", shell_flags))
.arg("--color")
.arg(color)
.arg(script_path)
.output()
.expect("Failed to execute binary");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
(exit_code, stdout, stderr)
}
fn run_echo_comment_normal(script_path: &str) -> (i32, String, String) {
let output = Command::new("target/debug/echo-comment")
.arg(script_path)
.output()
.expect("Failed to execute binary");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
(exit_code, stdout, stderr)
}
#[test]
fn test_shell_flags_pipefail_behavior() {
let script_content = r#"#!/usr/bin/env -S echo-comment
# Test comment: this grep call will fail and we won't get the Python
echo "hello" | grep "world"
# hiss
python -c "print('Goodbye')"
"#;
let temp_script = create_temp_script(script_content);
let script_path = temp_script.path().to_str().unwrap();
let (exit_code_normal, stdout_normal, stderr_normal) = run_echo_comment_normal(script_path);
let (exit_code_pipefail, stdout_pipefail, stderr_pipefail) =
run_echo_comment_with_flags(script_path, "-euo pipefail");
assert_eq!(
exit_code_normal, 0,
"Normal mode should complete successfully. stderr: {}",
stderr_normal
);
assert!(
stdout_normal
.contains("Test comment: this grep call will fail and we won't get the Python"),
"Should echo the first comment in normal mode"
);
assert!(
stdout_normal.contains("hiss"),
"Should echo the second comment in normal mode"
);
assert!(
stdout_normal.contains("Goodbye"),
"Should execute Python command in normal mode despite grep failure"
);
assert_ne!(
exit_code_pipefail, 0,
"Pipefail mode should exit with error code after grep failure. stderr: {}",
stderr_pipefail
);
assert!(
stdout_pipefail
.contains("Test comment: this grep call will fail and we won't get the Python"),
"Should echo the first comment in pipefail mode"
);
assert!(
!stdout_pipefail.contains("hiss"),
"Should NOT echo the second comment in pipefail mode (execution stopped)"
);
assert!(
!stdout_pipefail.contains("Goodbye"),
"Should NOT execute Python command in pipefail mode (execution stopped)"
);
}
#[test]
fn test_shell_flags_with_color_option() {
let script_content = r#"#!/usr/bin/env echo-comment
# Test comment: this grep call will fail and we won't get the Python
echo "hello" | grep "world"
# hiss
python -c "print('Goodbye')"
"#;
let temp_script = create_temp_script(script_content);
let script_path = temp_script.path().to_str().unwrap();
let (exit_code, stdout, stderr) =
run_echo_comment_with_flags_and_color(script_path, "-euo pipefail", "green");
assert_ne!(
exit_code, 0,
"Should exit with error code due to pipefail. stderr: {}",
stderr
);
assert!(
stdout.contains("Test comment: this grep call will fail and we won't get the Python"),
"Should echo the first comment"
);
assert!(
stdout.contains("\x1b[0;32m"),
"Should contain green ANSI color code in output"
);
assert!(
stdout.contains("\x1b[0m"),
"Should contain ANSI reset code in output"
);
assert!(
!stdout.contains("hiss"),
"Should NOT echo the second comment (execution stopped due to pipefail)"
);
assert!(
!stdout.contains("Goodbye"),
"Should NOT execute Python command (execution stopped due to pipefail)"
);
}
#[test]
fn test_color_option_without_shell_flags() {
let script_content = r#"#!/usr/bin/env echo-comment
# This comment should be green
echo "Regular command"
# Another green comment
"#;
let temp_script = create_temp_script(script_content);
let script_path = temp_script.path().to_str().unwrap();
let output = Command::new("target/debug/echo-comment")
.arg("--color")
.arg("green")
.arg(script_path)
.output()
.expect("Failed to execute binary");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
assert_eq!(exit_code, 0, "Should exit successfully. stderr: {}", stderr);
assert!(
stdout.contains("This comment should be green"),
"Should echo the first comment"
);
assert!(
stdout.contains("Another green comment"),
"Should echo the second comment"
);
assert!(
stdout.contains("Regular command"),
"Should execute regular command"
);
assert!(
stdout.contains("\x1b[0;32m"),
"Should contain green ANSI color code in output"
);
assert!(
stdout.contains("\x1b[0m"),
"Should contain ANSI reset code in output"
);
}
#[test]
fn test_multiple_color_options() {
let script_content = r#"#!/usr/bin/env echo-comment
# Red comment test
echo "Command output"
# Another red comment
"#;
let temp_script = create_temp_script(script_content);
let script_path = temp_script.path().to_str().unwrap();
let output = Command::new("target/debug/echo-comment")
.arg("--color")
.arg("red")
.arg(script_path)
.output()
.expect("Failed to execute binary");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
assert_eq!(exit_code, 0, "Should exit successfully. stderr: {}", stderr);
assert!(
stdout.contains("\x1b[0;31m"),
"Should contain red ANSI color code in output"
);
assert!(
stdout.contains("Red comment test"),
"Should echo the comments"
);
assert!(
stdout.contains("Another red comment"),
"Should echo all comments"
);
}
#[test]
fn test_shell_flags_errexit_behavior() {
let script_content = r#"#!/usr/bin/env echo-comment
# Starting test
false
# This should not be reached with -e flag
echo "This should not execute"
"#;
let temp_script = create_temp_script(script_content);
let script_path = temp_script.path().to_str().unwrap();
let (exit_code_normal, stdout_normal, _) = run_echo_comment_normal(script_path);
let (exit_code_errexit, stdout_errexit, stderr_errexit) =
run_echo_comment_with_flags(script_path, "-e");
assert_eq!(
exit_code_normal, 0,
"Normal mode should complete successfully"
);
assert!(
stdout_normal.contains("Starting test"),
"Should echo first comment in normal mode"
);
assert!(
stdout_normal.contains("This should not be reached with -e flag"),
"Should echo second comment in normal mode"
);
assert_ne!(
exit_code_errexit, 0,
"Errexit mode should exit with error code. stderr: {}",
stderr_errexit
);
assert!(
stdout_errexit.contains("Starting test"),
"Should echo first comment in errexit mode"
);
assert!(
!stdout_errexit.contains("This should not be reached with -e flag"),
"Should NOT echo second comment in errexit mode (execution stopped)"
);
}