#![allow(deprecated)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
#![allow(non_snake_case)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::io::Write;
use tempfile::{NamedTempFile, TempDir};
#[allow(deprecated)]
fn bashrs_cmd() -> Command {
assert_cmd::cargo_bin_cmd!("bashrs")
}
fn create_temp_makefile(content: &str) -> NamedTempFile {
let mut file = NamedTempFile::new().expect("Failed to create temp file");
file.write_all(content.as_bytes())
.expect("Failed to write to temp file");
file
}
#[test]
fn test_MAKE_WITH_TESTS_001_generates_test_file() {
let makefile = r#"# Simple Makefile
.PHONY: all
all:
echo "Building"
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
assert!(
test_file.exists(),
"Test file should be generated at {}",
test_file.display()
);
let test_content = fs::read_to_string(&test_file).expect("Failed to read test file");
assert!(
test_content.starts_with("#!/bin/sh"),
"Test file should have POSIX shebang"
);
}
#[test]
fn test_MAKE_WITH_TESTS_001_test_file_naming_convention() {
let makefile = "all:\n\techo test";
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("MyMakefile");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
let test_file = output_dir.path().join("MyMakefile.test.sh");
assert!(
test_file.exists(),
"Test file should follow <makefile>.test.sh naming"
);
}
#[test]
fn test_MAKE_WITH_TESTS_002_generates_determinism_test() {
let makefile = r#".PHONY: build
build:
echo "Deterministic build"
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
let test_content = fs::read_to_string(&test_file).expect("Failed to read test file");
assert!(
test_content.contains("test_determinism") || test_content.contains("determinism"),
"Test file should contain determinism test"
);
assert!(
test_content.contains("make") && test_content.matches("make").count() >= 2,
"Determinism test should run make multiple times"
);
}
#[test]
fn test_MAKE_WITH_TESTS_003_generates_idempotency_test() {
let makefile = r#".PHONY: install
install:
mkdir -p /tmp/test_dir
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
let test_content = fs::read_to_string(&test_file).expect("Failed to read test file");
assert!(
test_content.contains("test_idempotency") || test_content.contains("idempotent"),
"Test file should contain idempotency test"
);
assert!(
test_content.matches("make").count() >= 2,
"Idempotency test should run make multiple times"
);
}
#[test]
fn test_MAKE_WITH_TESTS_004_generates_posix_compliance_test() {
let makefile = r#".PHONY: test
test:
echo "test"
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
let test_content = fs::read_to_string(&test_file).expect("Failed to read test file");
assert!(
test_content.contains("make") && test_content.contains("POSIX"),
"Test file should contain POSIX compliance test"
);
}
#[test]
fn test_MAKE_WITH_TESTS_005_property_tests_flag() {
let makefile = r#".PHONY: build
build:
@echo "Build"
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("--property-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
let test_content = fs::read_to_string(&test_file).expect("Failed to read test file");
assert!(
test_content.contains("for")
|| test_content.contains("while")
|| test_content.contains("seq"),
"Property tests should iterate over multiple test cases"
);
assert!(
test_content.contains("100") || test_content.contains("50"),
"Property tests should run many cases"
);
}
#[test]
fn test_MAKE_WITH_TESTS_006_generated_tests_are_executable() {
let makefile = r#".PHONY: all
all:
@echo "Hello"
"#;
let input_file = create_temp_makefile(makefile);
let output_dir = TempDir::new().expect("Failed to create temp dir");
let output_file = output_dir.path().join("Makefile");
let test_file = output_dir.path().join("Makefile.test.sh");
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.arg("-o")
.arg(&output_file)
.assert()
.success();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&test_file).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&test_file, perms).unwrap();
}
let output = std::process::Command::new("sh")
.arg("-n") .arg(&test_file)
.output()
.expect("Failed to check test file syntax");
assert!(
output.status.success(),
"Generated test file should have valid sh syntax"
);
}
#[test]
fn test_MAKE_WITH_TESTS_error_missing_output() {
let makefile = "all:\n\techo test";
let input_file = create_temp_makefile(makefile);
bashrs_cmd()
.arg("make")
.arg("purify")
.arg(input_file.path())
.arg("--with-tests")
.assert()
.failure()
.stderr(predicate::str::contains("output").or(predicate::str::contains("-o")));
}
#[test]
fn test_MAKE_WITH_TESTS_help_flag() {
bashrs_cmd()
.arg("make")
.arg("purify")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("--with-tests"))
.stdout(predicate::str::contains("Generate test suite"));
}