#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use std::fs;
use std::process::Command;
use tempfile::TempDir;
#[test]
fn test_e2e_build_pipeline() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let greeting = "Hello from E2E test!";
let version = "1.0.0";
echo(greeting);
echo(version);
}
fn echo(msg: &str) {}
"#;
let input_file = temp_dir.path().join("app.rs");
let output_file = temp_dir.path().join("app.sh");
fs::write(&input_file, source).expect("Failed to write source");
let build_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "build"])
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.output()
.expect("Failed to run bashrs build");
assert!(
build_output.status.success(),
"Build failed:\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&build_output.stdout),
String::from_utf8_lossy(&build_output.stderr)
);
assert!(output_file.exists(), "Output file not created");
let script_content = fs::read_to_string(&output_file).expect("Failed to read output file");
assert!(script_content.contains("#!/bin/sh"), "Missing shebang");
assert!(
script_content.contains("Generated by"),
"Missing generation comment"
);
let run_output = Command::new("sh")
.arg(&output_file)
.output()
.expect("Failed to execute generated script");
assert!(
run_output.status.success(),
"Script execution failed:\nstderr: {}",
String::from_utf8_lossy(&run_output.stderr)
);
let stdout = String::from_utf8_lossy(&run_output.stdout);
assert!(
stdout.contains("Hello from E2E test!"),
"Output missing greeting"
);
assert!(stdout.contains("1.0.0"), "Output missing version");
}
#[test]
fn test_e2e_check_command() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let valid_source = r#"
fn main() {
let x = 42;
let y = "test";
}
"#;
let input_file = temp_dir.path().join("valid.rs");
fs::write(&input_file, valid_source).expect("Failed to write source");
let check_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "check"])
.arg(input_file.to_str().unwrap())
.output()
.expect("Failed to run bashrs check");
assert!(
check_output.status.success(),
"Check failed for valid code:\nstderr: {}",
String::from_utf8_lossy(&check_output.stderr)
);
}
#[test]
fn test_e2e_check_command_invalid_syntax() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let invalid_source = "fn main( { }";
let input_file = temp_dir.path().join("invalid.rs");
fs::write(&input_file, invalid_source).expect("Failed to write source");
let check_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "check"])
.arg(input_file.to_str().unwrap())
.output()
.expect("Failed to run bashrs check");
assert!(
!check_output.status.success(),
"Check should fail for invalid syntax"
);
}
#[test]
fn test_e2e_multi_shell_execution() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let test_var = "POSIX compatible";
echo(test_var);
}
fn echo(msg: &str) {}
"#;
let input_file = temp_dir.path().join("posix_test.rs");
let output_file = temp_dir.path().join("posix_test.sh");
fs::write(&input_file, source).expect("Failed to write source");
let build_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "build"])
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.output()
.expect("Failed to run bashrs build");
assert!(build_output.status.success(), "Build failed");
let shells = vec!["sh", "dash", "bash"];
for shell in shells {
let which_output = Command::new("which")
.arg(shell)
.output()
.expect("Failed to run which");
if !which_output.status.success() {
eprintln!("Skipping {} (not installed)", shell);
continue;
}
let run_output = Command::new(shell)
.arg(&output_file)
.output()
.unwrap_or_else(|_| panic!("Failed to run with {}", shell));
assert!(
run_output.status.success(),
"Script failed with {}:\nstderr: {}",
shell,
String::from_utf8_lossy(&run_output.stderr)
);
let stdout = String::from_utf8_lossy(&run_output.stdout);
assert!(
stdout.contains("POSIX compatible"),
"{} output missing expected text",
shell
);
}
}
#[test]
fn test_e2e_compile_self_extracting() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let message = "Self-extracting binary!";
echo(message);
}
fn echo(msg: &str) {}
"#;
let input_file = temp_dir.path().join("binary.rs");
let output_file = temp_dir.path().join("binary.sh");
fs::write(&input_file, source).expect("Failed to write source");
let compile_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "compile"])
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.arg("--self-extracting")
.output()
.expect("Failed to run bashrs compile");
if !compile_output.status.success() {
eprintln!(
"Compile stderr: {}",
String::from_utf8_lossy(&compile_output.stderr)
);
eprintln!("Note: Binary compilation may not be fully implemented in v1.0");
return;
}
assert!(output_file.exists(), "Self-extracting script not created");
let metadata = fs::metadata(&output_file).expect("Failed to get metadata");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let permissions = metadata.permissions();
assert!(permissions.mode() & 0o111 != 0, "Script not executable");
}
}
#[test]
fn test_e2e_verification_levels() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let x = 1 + 2;
}
"#;
let input_file = temp_dir.path().join("verify_test.rs");
fs::write(&input_file, source).expect("Failed to write source");
let levels = vec!["none", "basic", "strict", "paranoid"];
for level in levels {
let output_file = temp_dir.path().join(format!("verify_{}.sh", level));
let build_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--"])
.arg("--verify")
.arg(level)
.arg("build")
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.output()
.unwrap_or_else(|_| panic!("Failed to build with verify={}", level));
if !build_output.status.success() {
eprintln!("Build with verify={} failed (may be expected)", level);
continue;
}
assert!(
output_file.exists(),
"Output not created for verify={}",
level
);
}
}
#[test]
fn test_e2e_target_dialects() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let msg = "Dialect test";
echo(msg);
}
fn echo(msg: &str) {}
"#;
let input_file = temp_dir.path().join("dialect_test.rs");
fs::write(&input_file, source).expect("Failed to write source");
let dialects = vec!["posix", "bash", "dash", "ash"];
for dialect in dialects {
let output_file = temp_dir.path().join(format!("target_{}.sh", dialect));
let build_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--"])
.arg("--target")
.arg(dialect)
.arg("build")
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.output()
.unwrap_or_else(|_| panic!("Failed to build with target={}", dialect));
assert!(
build_output.status.success(),
"Build failed for target={}:\nstderr: {}",
dialect,
String::from_utf8_lossy(&build_output.stderr)
);
assert!(
output_file.exists(),
"Output not created for target={}",
dialect
);
let content = fs::read_to_string(&output_file).expect("Failed to read output");
assert!(
content.starts_with("#!/bin/sh"),
"Invalid shebang for {}",
dialect
);
}
}
#[test]
fn test_e2e_complex_example() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let source = r#"
fn main() {
let project_name = "test-project";
let version = "1.0.0";
echo("=== Installation ===");
echo(&format!("Project: {}", project_name));
echo(&format!("Version: {}", version));
if check_prerequisites() {
echo("✓ Prerequisites OK");
} else {
echo("✗ Prerequisites failed");
}
echo("Installation complete");
}
fn check_prerequisites() -> bool {
true
}
fn echo(msg: &str) {}
fn format(template: &str, args: &str) -> String {
String::new()
}
"#;
let input_file = temp_dir.path().join("complex.rs");
let output_file = temp_dir.path().join("complex.sh");
fs::write(&input_file, source).expect("Failed to write source");
let build_output = Command::new("cargo")
.args(["run", "--bin", "bashrs", "--", "build"])
.arg(input_file.to_str().unwrap())
.arg("-o")
.arg(output_file.to_str().unwrap())
.output()
.expect("Failed to run bashrs build");
if !build_output.status.success() {
eprintln!("Complex example failed (may contain unsupported features)");
return;
}
let run_output = Command::new("sh")
.arg(&output_file)
.output()
.expect("Failed to execute script");
if run_output.status.success() {
let stdout = String::from_utf8_lossy(&run_output.stdout);
assert!(stdout.contains("Installation"), "Output missing content");
}
}