#[cfg(test)]
mod tests {
use super::super::properties::*;
use crate::ir::{Command, EffectSet, ShellIR, ShellValue};
#[test]
fn test_verify_no_command_injection_safe() {
let ir = ShellIR::Exec {
cmd: Command::new("echo").arg(ShellValue::String("safe".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_no_command_injection(&ir).is_ok());
}
#[test]
fn test_verify_no_command_injection_unsafe() {
let ir = ShellIR::Exec {
cmd: Command::new("eval").arg(ShellValue::Variable("user_input".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_no_command_injection(&ir).is_err());
}
#[test]
fn test_verify_no_command_injection_nested() {
let ir = ShellIR::Sequence(vec![
ShellIR::Let {
name: "x".to_string(),
value: ShellValue::String("safe".to_string()),
effects: EffectSet::pure(),
},
ShellIR::Exec {
cmd: Command::new("echo").arg(ShellValue::Variable("x".to_string())),
effects: EffectSet::pure(),
},
]);
assert!(verify_no_command_injection(&ir).is_ok());
}
#[test]
fn test_verify_deterministic_safe() {
let ir = ShellIR::Exec {
cmd: Command::new("echo").arg(ShellValue::String("hello".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_deterministic(&ir).is_ok());
}
#[test]
fn test_verify_deterministic_unsafe() {
let ir = ShellIR::Exec {
cmd: Command::new("date"),
effects: EffectSet::pure(),
};
assert!(verify_deterministic(&ir).is_err());
}
#[test]
fn test_verify_deterministic_random() {
let ir = ShellIR::Let {
name: "x".to_string(),
value: ShellValue::CommandSubst(Command::new("uuidgen")),
effects: EffectSet::pure(),
};
assert!(verify_deterministic(&ir).is_err());
}
#[test]
fn test_verify_idempotency_mkdir() {
let ir = ShellIR::Exec {
cmd: Command::new("mkdir").arg(ShellValue::String("testdir".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_idempotency(&ir).is_ok());
}
#[test]
fn test_verify_idempotency_mkdir_p() {
let ir = ShellIR::Exec {
cmd: Command::new("mkdir")
.arg(ShellValue::String("-p".to_string()))
.arg(ShellValue::String("testdir".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_idempotency(&ir).is_ok());
}
#[test]
fn test_verify_idempotency_safe_command() {
let ir = ShellIR::Exec {
cmd: Command::new("echo").arg(ShellValue::String("hello".to_string())),
effects: EffectSet::pure(),
};
assert!(verify_idempotency(&ir).is_ok());
}
#[test]
fn test_verify_resource_safety_safe() {
let ir = ShellIR::Sequence(vec![
ShellIR::Let {
name: "x".to_string(),
value: ShellValue::String("hello".to_string()),
effects: EffectSet::pure(),
},
ShellIR::Exec {
cmd: Command::new("echo").arg(ShellValue::Variable("x".to_string())),
effects: EffectSet::pure(),
},
]);
assert!(verify_resource_safety(&ir).is_ok());
}
#[test]
fn test_verify_resource_safety_with_effects() {
let mut effects = EffectSet::pure();
effects.add(crate::ir::Effect::FileWrite);
let ir = ShellIR::Exec {
cmd: Command::new("touch").arg(ShellValue::String("file.txt".to_string())),
effects,
};
assert!(verify_resource_safety(&ir).is_ok());
}
#[test]
fn test_verify_resource_safety_excessive() {
let ir = ShellIR::Exec {
cmd: Command::new("dd")
.arg(ShellValue::String("if=/dev/zero".to_string()))
.arg(ShellValue::String("of=/dev/null".to_string()))
.arg(ShellValue::String("bs=1G".to_string()))
.arg(ShellValue::String("count=1000".to_string())),
effects: EffectSet::pure(),
};
let _result = verify_resource_safety(&ir);
}
}