use crate::{transpile, Config};
use std::fs;
use std::process::Command;
use tempfile::TempDir;
fn shellcheck_validate(shell_script: &str) -> Result<(), String> {
let temp_dir = TempDir::new().unwrap();
let script_path = temp_dir.path().join("test.sh");
fs::write(&script_path, shell_script).unwrap();
let output = Command::new("shellcheck")
.arg("-s")
.arg("sh") .arg("--severity=error") .arg(&script_path)
.output()
.expect("Failed to run shellcheck - is it installed?");
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
Err(format!(
"ShellCheck failed:\nSTDOUT:\n{}\nSTDERR:\n{}\n\nScript:\n{}",
stdout, stderr, shell_script
))
}
}
fn transpile_and_validate(source: &str) -> Result<String, String> {
let config = Config::default();
let shell_script =
transpile(source, &config).map_err(|e| format!("Transpilation failed: {}", e))?;
shellcheck_validate(&shell_script)?;
Ok(shell_script)
}
#[test]
fn test_shellcheck_empty_main() {
let source = r#"
fn main() {}
"#;
transpile_and_validate(source).expect("Empty main should pass shellcheck");
}
#[test]
fn test_shellcheck_simple_variable() {
let source = r#"
fn main() {
let x = "hello";
}
"#;
transpile_and_validate(source).expect("Simple variable should pass shellcheck");
}
#[test]
fn test_shellcheck_echo_command() {
let source = r#"
fn main() {
echo("Hello, World!");
}
"#;
transpile_and_validate(source).expect("Echo command should pass shellcheck");
}
#[test]
fn test_shellcheck_if_statement() {
let source = r#"
fn main() {
let condition = true;
if condition {
echo("true branch");
} else {
echo("false branch");
}
}
"#;
transpile_and_validate(source).expect("If statement should pass shellcheck");
}
#[test]
fn test_shellcheck_nested_if() {
let source = r#"
fn main() {
let a = true;
let b = false;
if a {
if b {
echo("both true");
} else {
echo("a true, b false");
}
} else {
echo("a false");
}
}
"#;
transpile_and_validate(source).expect("Nested if should pass shellcheck");
}
#[test]
fn test_shellcheck_multiple_variables() {
let source = r#"
fn main() {
let name = "Rash";
let version = "0.3.3";
let greeting = "Hello";
echo(name);
echo(version);
echo(greeting);
}
"#;
transpile_and_validate(source).expect("Multiple variables should pass shellcheck");
}
#[test]
fn test_shellcheck_user_function() {
let source = r#"
fn main() {
greet("World");
}
fn greet(name: &str) {
echo(name);
}
"#;
transpile_and_validate(source).expect("User function should pass shellcheck");
}
#[test]
fn test_shellcheck_multiple_functions() {
let source = r#"
fn main() {
setup();
process();
cleanup();
}
fn setup() {
echo("Setting up...");
}
fn process() {
echo("Processing...");
}
fn cleanup() {
echo("Cleaning up...");
}
"#;
transpile_and_validate(source).expect("Multiple functions should pass shellcheck");
}
#[test]
fn test_shellcheck_function_with_params() {
let source = r#"
fn main() {
install("package", "/usr/local");
}
fn install(name: &str, path: &str) {
echo(name);
echo(path);
}
"#;
transpile_and_validate(source).expect("Function with params should pass shellcheck");
}
#[test]
fn test_shellcheck_unicode_emoji() {
let source = r#"
fn main() {
let msg = "Hello 👋 World 🦀";
echo(msg);
}
"#;
transpile_and_validate(source).expect("Unicode emoji should pass shellcheck");
}
#[test]
fn test_shellcheck_unicode_cjk() {
let source = r#"
fn main() {
let msg = "你好世界";
echo(msg);
}
"#;
transpile_and_validate(source).expect("Unicode CJK should pass shellcheck");
}
#[test]
fn test_shellcheck_unicode_arabic() {
let source = r#"
fn main() {
let msg = "مرحبا";
echo(msg);
}
"#;
transpile_and_validate(source).expect("Unicode Arabic should pass shellcheck");
}
#[test]
fn test_shellcheck_special_chars_in_strings() {
let source = r#"
fn main() {
let msg1 = "String with spaces";
let msg2 = "String with 'quotes'";
let msg3 = "String with $dollar";
let msg4 = "String with |pipe|";
echo(msg1);
echo(msg2);
echo(msg3);
echo(msg4);
}
"#;
transpile_and_validate(source).expect("Special characters should pass shellcheck");
}
#[test]
fn test_shellcheck_newlines_tabs() {
let source = r#"
fn main() {
let msg = "Line1\nLine2\tTabbed";
echo(msg);
}
"#;
transpile_and_validate(source).expect("Newlines and tabs should pass shellcheck");
}
#[test]
fn test_shellcheck_empty_if_branch() {
let source = r#"
fn main() {
let condition = true;
if condition {
// Empty
} else {
echo("else branch");
}
}
"#;
transpile_and_validate(source).expect("Empty if branch should pass shellcheck");
}
#[test]
fn test_shellcheck_empty_else_branch() {
let source = r#"
fn main() {
let condition = false;
if condition {
echo("if branch");
} else {
// Empty
}
}
"#;
transpile_and_validate(source).expect("Empty else branch should pass shellcheck");
}
#[test]
fn test_shellcheck_both_branches_empty() {
let source = r#"
fn main() {
let condition = true;
if condition {
// Empty
} else {
// Empty
}
}
"#;
transpile_and_validate(source).expect("Both empty branches should pass shellcheck");
}
#[test]
fn test_shellcheck_variable_shadowing() {
let source = r#"
fn main() {
let x = "outer";
echo(x);
if true {
let x = "inner";
echo(x);
}
echo(x);
}
"#;
transpile_and_validate(source).expect("Variable shadowing should pass shellcheck");
}
#[test]
include!("shellcheck_validation_tests_main.rs");