fn test_complex_boolean_conditions_idempotent() {
let source = r#"
fn main() {
let a = true;
let b = false;
let c = true;
if a && b {
write_file("result.txt", "a and b");
} else if a || c {
write_file("result.txt", "a or c");
} else {
write_file("result.txt", "neither");
}
}
fn write_file(path: &str, content: &str) {
let noop = true;
}
"#;
let config = Config::default();
let shell = transpile(source, &config).unwrap();
let temp_dir1 = TempDir::new().unwrap();
let state1 = execute_and_capture_state(&shell, &temp_dir1);
let temp_dir2 = TempDir::new().unwrap();
let state2 = execute_and_capture_state(&shell, &temp_dir2);
assert_eq!(state1, state2, "Complex boolean conditions not idempotent");
}
#[test]
fn test_simple_script_deterministic() {
let source = r#"
fn main() {
write_file("test.txt", "hello world");
}
fn write_file(path: &str, content: &str) {
let noop = true;
}
"#;
let config = Config::default();
let shell = transpile(source, &config).unwrap();
let states: Vec<ScriptState> = (0..10)
.map(|_| {
let temp = TempDir::new().unwrap();
execute_and_capture_state(&shell, &temp)
})
.collect();
for (i, state) in states.iter().enumerate().skip(1) {
assert_eq!(&states[0], state, "Non-deterministic on run {}", i);
}
}
#[test]
fn test_condition_evaluation_no_side_effects() {
let source = r#"
fn main() {
let counter = 0;
// Condition should not modify state
if counter == 0 {
write_file("zero.txt", "counter is zero");
}
// Counter should still be 0
if counter == 0 {
write_file("still_zero.txt", "counter still zero");
}
}
fn write_file(path: &str, content: &str) {
let noop = true;
}
"#;
let config = Config::default();
let shell = transpile(source, &config).unwrap();
let temp_dir1 = TempDir::new().unwrap();
let state1 = execute_and_capture_state(&shell, &temp_dir1);
let temp_dir2 = TempDir::new().unwrap();
let state2 = execute_and_capture_state(&shell, &temp_dir2);
assert_eq!(state1.files.len(), state2.files.len());
assert_eq!(state1, state2, "Condition evaluation has side effects");
}
#[test]
fn test_empty_branches_idempotent() {
let source = r#"
fn main() {
let condition = true;
if condition {
// Empty true branch
} else {
write_file("else.txt", "else branch");
}
write_file("after.txt", "after if");
}
fn write_file(path: &str, content: &str) {
let noop = true;
}
"#;
let config = Config::default();
let shell = transpile(source, &config).unwrap();
let temp_dir1 = TempDir::new().unwrap();
let state1 = execute_and_capture_state(&shell, &temp_dir1);
let temp_dir2 = TempDir::new().unwrap();
let state2 = execute_and_capture_state(&shell, &temp_dir2);
assert_eq!(state1, state2, "Empty branches not idempotent");
}