#![allow(clippy::unwrap_used)] #![allow(clippy::expect_used)]
use bashrs::{transpile, Config};
#[test]
fn test_edge_case_08_function_return_values() {
let source = r#"
fn main() {
let x = add(1, 2);
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(
result.contains("echo $((a + b))") || result.contains("echo \"$((a + b))\""),
"Function with return type should echo result"
);
assert!(
result.contains("x=\"$(add 1 2)\"") || result.contains("x=$(add 1 2)"),
"Function call result should be captured with $(...)"
);
assert!(!result.contains("x=unknown"), "Should not assign unknown");
}
#[test]
fn test_edge_case_09_arithmetic_expressions() {
let source = r#"
fn main() {
let x = 1 + 2;
let y = 10 - 3;
let z = 4 * 5;
let w = 20 / 4;
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(
result.contains("$((1 + 2))") || result.contains("x=3") || result.contains("x='3'"),
"Should use arithmetic expansion OR constant-fold: addition. Got: {}",
result
);
assert!(
result.contains("$((10 - 3))") || result.contains("y=7") || result.contains("y='7'"),
"Should use arithmetic expansion OR constant-fold: subtraction. Got: {}",
result
);
assert!(
result.contains("$((4 * 5))") || result.contains("z=20") || result.contains("z='20'"),
"Should use arithmetic expansion OR constant-fold: multiplication. Got: {}",
result
);
assert!(
result.contains("$((20 / 4))") || result.contains("w=5") || result.contains("w='5'"),
"Should use arithmetic expansion OR constant-fold: division. Got: {}",
result
);
assert!(
!result.contains("\"${x}${y}\""),
"Should not use string concatenation for arithmetic"
);
}
#[test]
fn test_edge_case_03_negative_integers() {
let source = r#"
fn main() {
let x = -1;
let y = -42;
let z = 0;
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(
!result.contains("unknown"),
"Negative integers should not transpile to 'unknown'"
);
assert!(
result.contains("x=-1") || result.contains("x='-1'"),
"Should assign x=-1. Got: {}",
result
);
assert!(
result.contains("y=-42") || result.contains("y='-42'"),
"Should assign y=-42. Got: {}",
result
);
assert!(
result.contains("z=0") || result.contains("z='0'"),
"Should assign z=0. Got: {}",
result
);
}
#[test]
fn test_edge_case_02_println_macro() {
let source = r#"
fn main() {
println!("Hello, World!");
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok(), "println! should be supported");
let script = result.unwrap();
assert!(
script.contains("printf") || script.contains("echo"),
"println! should generate output command"
);
assert!(
script.contains("Hello, World!"),
"Should preserve the string"
);
}
#[test]
fn test_edge_case_01_empty_function_bodies() {
let source = r#"
fn main() {
echo("test");
}
fn echo(msg: &str) {
// Empty function - should generate : no-op
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(
!result.contains("echo() {"),
"Empty builtin function should NOT generate function definition (uses builtin directly)"
);
assert!(
result.contains("echo ") || result.contains("echo test"),
"Should call the builtin echo command"
);
}
#[test]
fn test_edge_case_04_comparison_operators() {
let source = r#"
fn main() {
let x = 1;
if x > 0 {
let y = 2;
}
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(
!result.contains("test -n \"${x}0\""),
"Comparison should not use string concatenation test"
);
assert!(
result.contains("-gt")
|| result.contains("test") && result.contains("$x") && result.contains("0"),
"Should use POSIX integer comparison (-gt, -lt, -eq, etc.)"
);
}
#[test]
fn test_edge_case_06_for_loops() {
let source = r#"
fn main() {
for i in 0..3 {
let x = i;
}
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(result.contains("for i in"), "Should have for loop");
assert!(
result.contains("seq") || result.contains("$(seq"),
"Should use seq for range iteration"
);
assert!(
result.contains("0") && result.contains("2"),
"Range 0..3 should be 0 to 2 inclusive"
);
assert!(
!result.to_lowercase().contains("unsupported"),
"For loops should be supported"
);
}
#[test]
fn test_edge_case_07_match_expressions() {
let source = r#"
fn main() {
let x = 2;
match x {
1 => {
let y = 10;
}
2 => {
let y = 20;
}
_ => {
let y = 0;
}
}
}
"#;
let config = Config::default();
let result = transpile(source, &config).unwrap();
assert!(result.contains("case "), "Should have case statement");
assert!(result.contains("esac"), "Should close with esac");
assert!(result.contains("1)"), "Should match literal 1");
assert!(result.contains("2)"), "Should match literal 2");
assert!(result.contains("*)"), "Should have wildcard pattern");
assert!(
result.matches(";;").count() >= 3,
"Each case should end with ;;"
);
assert!(
!result.to_lowercase().contains("unsupported"),
"Match expressions should be supported"
);
}
#[test]
fn test_edge_case_10_empty_main() {
let source = r#"
fn main() {
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok(), "Empty main() should transpile successfully");
let script = result.unwrap();
assert!(
script.starts_with("#!/") || script.contains("main()"),
"Should be a valid shell script"
);
let main_section = script.split("# Main script begins").last().unwrap_or("");
assert!(
!main_section.to_lowercase().contains("error:"),
"Main script should not contain error messages"
);
}
#[test]
fn test_edge_case_11_integer_overflow() {
let source = r#"
fn main() {
let x = 2147483647; // i32::MAX
let y = -2147483648; // i32::MIN
}
"#;
let config = Config::default();
let result = transpile(source, &config);
assert!(result.is_ok(), "Boundary integers should transpile");
let script = result.unwrap();
assert!(script.contains("2147483647"), "Should handle i32::MAX");
assert!(
script.contains("-2147483648") || script.contains("2147483648"),
"Should handle i32::MIN"
);
assert!(
!script.contains("unknown"),
"Should not transpile to unknown for boundary values"
);
}