use std::io::Write;
use std::process::Command;
use tempfile::NamedTempFile;
fn run_awk_rs(args: &[&str], input: Option<&str>) -> Result<String, String> {
let mut cmd = Command::new("cargo");
cmd.args(["run", "--quiet", "--"]);
cmd.args(args);
if input.is_some() {
cmd.stdin(std::process::Stdio::piped());
}
cmd.stdout(std::process::Stdio::piped());
cmd.stderr(std::process::Stdio::piped());
let mut child = cmd.spawn().map_err(|e| e.to_string())?;
if let Some((input_str, mut stdin)) = input.zip(child.stdin.take()) {
stdin
.write_all(input_str.as_bytes())
.map_err(|e| e.to_string())?;
}
let output = child.wait_with_output().map_err(|e| e.to_string())?;
if output.status.success() {
String::from_utf8(output.stdout).map_err(|e| e.to_string())
} else {
Err(String::from_utf8_lossy(&output.stderr).to_string())
}
}
#[test]
fn test_cli_help() {
let output = run_awk_rs(&["--help"], None).unwrap();
assert!(output.contains("Usage:"));
assert!(output.contains("awk-rs"));
}
#[test]
fn test_cli_version() {
let output = run_awk_rs(&["--version"], None).unwrap();
assert!(output.contains("awk-rs"));
}
#[test]
fn test_cli_simple_program() {
let output = run_awk_rs(&["BEGIN { print \"hello\" }"], None).unwrap();
assert_eq!(output, "hello\n");
}
#[test]
fn test_cli_with_input() {
let output = run_awk_rs(&["{ print $1 }"], Some("a b c")).unwrap();
assert_eq!(output, "a\n");
}
#[test]
fn test_cli_field_separator() {
let output = run_awk_rs(&["-F:", "{ print $1 }"], Some("a:b:c")).unwrap();
assert_eq!(output, "a\n");
}
#[test]
fn test_cli_field_separator_attached() {
let output = run_awk_rs(&["-F,", "{ print $2 }"], Some("a,b,c")).unwrap();
assert_eq!(output, "b\n");
}
#[test]
fn test_cli_variable() {
let output = run_awk_rs(&["-v", "x=5", "BEGIN { print x }"], None).unwrap();
assert_eq!(output, "5\n");
}
#[test]
fn test_cli_program_file() {
let mut file = NamedTempFile::new().unwrap();
writeln!(file, r#"BEGIN {{ print "from file" }}"#).unwrap();
let path = file.path().to_str().unwrap();
let output = run_awk_rs(&["-f", path], None).unwrap();
assert_eq!(output, "from file\n");
}
#[test]
fn test_cli_posix_mode() {
let output = run_awk_rs(&["--posix", "BEGIN { print \"posix\" }"], None).unwrap();
assert_eq!(output, "posix\n");
}
#[test]
fn test_cli_traditional_mode() {
let output = run_awk_rs(&["--traditional", "BEGIN { print \"trad\" }"], None).unwrap();
assert_eq!(output, "trad\n");
}
#[test]
fn test_cli_separator_end_of_options() {
let output = run_awk_rs(&["BEGIN { print \"test\" }", "--"], None).unwrap();
assert_eq!(output, "test\n");
}
#[test]
fn test_cli_stdin_dash() {
let output = run_awk_rs(&["{ print }", "-"], Some("hello")).unwrap();
assert_eq!(output, "hello\n");
}
#[test]
fn test_cli_multiple_inputs() {
let mut file1 = NamedTempFile::new().unwrap();
writeln!(file1, "a").unwrap();
let mut file2 = NamedTempFile::new().unwrap();
writeln!(file2, "b").unwrap();
let path1 = file1.path().to_str().unwrap();
let path2 = file2.path().to_str().unwrap();
let output = run_awk_rs(&["{ print }", path1, path2], None).unwrap();
assert!(output.contains("a") && output.contains("b"));
}
#[test]
fn test_cli_begin_end_run_once_across_files() {
let mut file1 = NamedTempFile::new().unwrap();
writeln!(file1, "a").unwrap();
writeln!(file1, "b").unwrap();
let mut file2 = NamedTempFile::new().unwrap();
writeln!(file2, "c").unwrap();
let path1 = file1.path().to_str().unwrap();
let path2 = file2.path().to_str().unwrap();
let output = run_awk_rs(&[r#"BEGIN{print "hi"} END{print NR}"#, path1, path2], None).unwrap();
assert_eq!(output, "hi\n3\n");
}
#[test]
fn test_cli_filename_and_fnr_across_files() {
let mut file1 = NamedTempFile::new().unwrap();
writeln!(file1, "a").unwrap();
writeln!(file1, "b").unwrap();
let mut file2 = NamedTempFile::new().unwrap();
writeln!(file2, "c").unwrap();
let path1 = file1.path().to_str().unwrap();
let path2 = file2.path().to_str().unwrap();
let output = run_awk_rs(&["{ print FILENAME, NR, FNR }", path1, path2], None).unwrap();
assert_eq!(
output,
format!("{p1} 1 1\n{p1} 2 2\n{p2} 3 1\n", p1 = path1, p2 = path2)
);
}
#[test]
fn test_cli_bare_getline_reads_main_input() {
let output = run_awk_rs(&["{ getline; print }"], Some("one\ntwo\nthree\nfour\n")).unwrap();
assert_eq!(output, "two\nfour\n");
}
#[test]
fn test_cli_bare_getline_at_eof_returns_zero() {
let output = run_awk_rs(&["{ r = getline; print r, $0 }"], Some("a\nb\nc\n")).unwrap();
assert_eq!(output, "1 b\n0 c\n");
}
#[test]
fn test_cli_getline_var_sets_var_and_nr() {
let output = run_awk_rs(&["{ getline v; print $0, v, NR, NF }"], Some("a b\nc d\n")).unwrap();
assert_eq!(output, "a b c d 2 2\n");
}
#[test]
fn test_cli_variable_escape_sequences() {
let output = run_awk_rs(&["-v", r"x=a\tb", "BEGIN { print x }"], None).unwrap();
assert_eq!(output, "a\tb\n");
}
#[test]
fn test_cli_variable_escape_newline_and_octal() {
let output = run_awk_rs(&["-v", r"x=a\n\101", "BEGIN { print x }"], None).unwrap();
assert_eq!(output, "a\nA\n");
}
#[test]
fn test_cli_error_no_program() {
let result = run_awk_rs(&[], None);
assert!(result.is_err());
}
#[test]
fn test_cli_error_unknown_option() {
let result = run_awk_rs(&["--unknown"], None);
assert!(result.is_err());
}
#[test]
fn test_cli_error_missing_f_arg() {
let result = run_awk_rs(&["-f"], None);
assert!(result.is_err());
}
#[test]
fn test_cli_error_missing_v_arg() {
let result = run_awk_rs(&["-v"], None);
assert!(result.is_err());
}
#[test]
fn test_cli_error_invalid_v_arg() {
let result = run_awk_rs(&["-v", "invalid"], None);
assert!(result.is_err());
}
#[test]
fn test_cli_error_missing_field_sep_arg() {
let result = run_awk_rs(&["-F"], None);
assert!(result.is_err());
}
#[test]
#[cfg(unix)]
fn test_cli_system_flushes_output_first() {
let output = run_awk_rs(
&[r#"BEGIN { print "a"; system("echo b"); print "c" }"#],
Some(""),
)
.unwrap();
assert_eq!(output, "a\nb\nc\n");
}
#[test]
#[cfg(unix)]
fn test_cli_system_flushes_redirected_files() {
let file = NamedTempFile::new().unwrap();
let path = file.path().to_string_lossy().replace('\\', "/");
let program = format!(r#"BEGIN {{ print "written" > "{path}"; system("cat {path}") }}"#);
let output = run_awk_rs(&[&program], Some("")).unwrap();
assert_eq!(output, "written\n");
}
#[test]
fn test_cli_variable_escape_hex() {
let output = run_awk_rs(&["-v", r"x=\x41\x42c", "BEGIN { print x }"], None).unwrap();
assert_eq!(output, "ABc\n");
}