#![allow(clippy::unwrap_used)] #![allow(clippy::expect_used)]
use bashrs::{transpile, Config};
#[test]
fn test_last_statement_detection_in_function() {
let source = r#"
fn add(a: i32, b: i32) -> i32 {
let result = a + b;
result
}
fn main() {
let sum = add(5, 3);
echo(sum);
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("echo \"$result\""),
"Last statement in function with return type should be echoed"
);
}
#[test]
fn test_echo_guard_in_function() {
let source = r#"
fn get_value() -> i32 {
42
}
fn no_return() {
let x = 10;
}
fn main() {
let val = get_value();
no_return();
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("echo \"42\"") || script.contains("echo 42"),
"Function with return type should echo return value"
);
let no_return_section = script
.split("no_return() {")
.nth(1)
.unwrap()
.split('}')
.next()
.unwrap();
assert!(
!no_return_section.contains("echo \"$x\""),
"Function without return type should not echo variables"
);
}
#[test]
fn test_range_expression_conversion() {
let source = r#"
fn main() {
for i in 0..3 {
echo(i);
}
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("seq") || script.contains("for i in"),
"Range expression should be converted to seq or shell range"
);
}
#[test]
fn test_equality_operator_conversion() {
let source = r#"
fn main() {
let x = 5;
if x == 5 {
echo("equal");
}
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("-eq") || script.contains("="),
"Equality operator should generate comparison test"
);
}
#[test]
fn test_subtraction_operator_conversion() {
let source = r#"
fn main() {
let a = 10;
let b = 3;
let result = a - b;
echo(result);
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("$((") && (script.contains("-") || script.contains("sub")),
"Subtraction should generate arithmetic expansion"
);
}
#[test]
fn test_download_command_effects() {
let source = r#"
fn main() {
echo("test");
}
fn echo(s: &str) {}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok());
let script = result.unwrap();
assert!(
script.contains("#!/bin/sh"),
"Script should have valid POSIX header"
);
assert!(
script.contains("main()"),
"Script should contain main function"
);
}
#[test]
fn test_arithmetic_operator_distinctness() {
let add_source = r#"
fn main() {
let result = 10 + 5;
echo(result);
}
"#;
let sub_source = r#"
fn main() {
let result = 10 - 5;
echo(result);
}
"#;
let div_source = r#"
fn main() {
let result = 10 / 5;
echo(result);
}
"#;
let add_script = transpile(add_source, &Config::default()).unwrap();
let sub_script = transpile(sub_source, &Config::default()).unwrap();
let div_script = transpile(div_source, &Config::default()).unwrap();
assert_ne!(
add_script, sub_script,
"Addition and subtraction should generate different code"
);
assert_ne!(
add_script, div_script,
"Addition and division should generate different code"
);
assert_ne!(
sub_script, div_script,
"Subtraction and division should generate different code"
);
assert!(
add_script.contains("+") || add_script.contains("add") || add_script.contains("result=15"),
"Addition operator should appear OR constant-fold to 15"
);
assert!(
sub_script.contains("-") || sub_script.contains("sub") || sub_script.contains("result=5"),
"Subtraction operator should appear OR constant-fold to 5"
);
assert!(
div_script.contains("/") || div_script.contains("div") || div_script.contains("result=2"),
"Division operator should appear OR constant-fold to 2"
);
}
#[test]
fn test_range_inclusive_vs_exclusive() {
let exclusive_source = r#"
fn main() {
for i in 0..3 {
echo(i);
}
}
"#;
let inclusive_source = r#"
fn main() {
for i in 0..=3 {
echo(i);
}
}
"#;
let exclusive_script = transpile(exclusive_source, &Config::default()).unwrap();
let inclusive_script = transpile(inclusive_source, &Config::default()).unwrap();
assert_ne!(
exclusive_script, inclusive_script,
"Inclusive and exclusive ranges should generate different code"
);
assert!(
exclusive_script.contains("seq 0 2") || exclusive_script.contains("0 1 2"),
"Exclusive range 0..3 should generate seq 0 2"
);
assert!(
inclusive_script.contains("seq 0 3") || inclusive_script.contains("0 1 2 3"),
"Inclusive range 0..=3 should generate seq 0 3"
);
}