255 lines
6.1 KiB
Rust
255 lines
6.1 KiB
Rust
use rush::interpreter::executor::Executor;
|
|
use rush::parser::Parser;
|
|
use rush::runtime::environment::Environment;
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_variable_assignment() {
|
|
// Test variable assignment functionality
|
|
let parser = Parser::new();
|
|
let result = parser.parse("name = \"test\"");
|
|
assert!(result.is_ok());
|
|
|
|
let program = result.unwrap();
|
|
let mut env = Environment::new();
|
|
let mut executor = Executor::new(&mut env);
|
|
|
|
for stmt in program.statements {
|
|
executor.execute_node(stmt);
|
|
}
|
|
|
|
assert_eq!(env.get_variable("name"), Some(&"test".to_string()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_simple_command() {
|
|
// Test basic command execution doesn't panic
|
|
let parser = Parser::new();
|
|
let result = parser.parse("echo \"test\"");
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_script_parsing() {
|
|
// Test the parsing of a complete .rsh script
|
|
let script = r#"
|
|
name = "Louis"
|
|
echo "Hello" $name
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
let program = result.unwrap();
|
|
assert!(program.statements.len() >= 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_undefined_variable_detection() {
|
|
// Test that using an undefined variable is caught
|
|
let script = r#"
|
|
echo "Hello" $undefined_var
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_err());
|
|
let err_msg = format!("{:?}", result.unwrap_err());
|
|
assert!(err_msg.contains("undefined_var"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_out_of_order_variable_detection() {
|
|
// Test that using a variable before it's defined is caught
|
|
let script = r#"
|
|
echo "Hello" $name
|
|
name = "Louis"
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_err());
|
|
let err_msg = format!("{:?}", result.unwrap_err());
|
|
assert!(err_msg.contains("name"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_variable_order() {
|
|
// Test that defining before using works correctly
|
|
let script = r#"
|
|
name = "Louis"
|
|
echo "Hello" $name
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_for_loop_variable_scope() {
|
|
// Test that for loop variables are properly scoped
|
|
let script = r#"
|
|
for i in 1 2 3 {
|
|
echo "Number:" $i
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_for_loop_variable_isolation() {
|
|
// Test that for loop variables don't leak to outer scope
|
|
let script = r#"
|
|
for i in 1 2 3 {
|
|
echo "Inside:" $i
|
|
}
|
|
echo "Outside:" $i
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_err());
|
|
let err_msg = format!("{:?}", result.unwrap_err());
|
|
assert!(err_msg.contains("i"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_parallel_block_variable_access() {
|
|
// Test that parallel blocks can access outer scope variables
|
|
let script = r#"
|
|
name = "Test"
|
|
|
|
parallel {
|
|
run { echo "Task 1:" $name }
|
|
run { echo "Task 2:" $name }
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_parallel_block_undefined_variable() {
|
|
// Test that parallel blocks catch undefined variables
|
|
let script = r#"
|
|
parallel {
|
|
run { echo "Task:" $undefined }
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_workers_block_variable_access() {
|
|
// Test that workers blocks can access outer scope variables
|
|
let script = r#"
|
|
msg = "Worker"
|
|
|
|
workers 2 {
|
|
echo $msg "Task 1"
|
|
echo $msg "Task 2"
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_workers_with_for_loop() {
|
|
// Test that workers can contain for loops with variables
|
|
let script = r#"
|
|
prefix = "Item"
|
|
|
|
workers 2 {
|
|
for num in 1 2 3 {
|
|
echo $prefix $num
|
|
}
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_for_loops() {
|
|
// Test nested for loops with proper scoping
|
|
let script = r#"
|
|
for i in 1 2 {
|
|
for j in a b {
|
|
echo $i $j
|
|
}
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_variables() {
|
|
// Test multiple variable definitions and usage
|
|
let script = r#"
|
|
user = "Alice"
|
|
project = "RushShell"
|
|
version = "1.0"
|
|
|
|
echo $user "is working on" $project "version" $version
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_for_loop_with_outer_variables() {
|
|
// Test for loops can access both loop vars and outer vars
|
|
let script = r#"
|
|
prefix = "Item"
|
|
|
|
for num in 1 2 3 {
|
|
echo $prefix $num
|
|
}
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_comprehensive_variable_usage() {
|
|
// Test a comprehensive script with all variable features
|
|
let script = r#"
|
|
user = "Alice"
|
|
project = "RushShell"
|
|
|
|
echo "Welcome" $user "to" $project
|
|
|
|
for item in "docs" "tests" "src" {
|
|
echo $user "is checking" $item
|
|
}
|
|
|
|
parallel {
|
|
run { echo "Parallel 1:" $user }
|
|
run { echo "Parallel 2:" $project }
|
|
}
|
|
|
|
workers 2 {
|
|
for num in 1 2 {
|
|
echo $project "worker task" $num
|
|
}
|
|
}
|
|
|
|
echo "Done with" $project
|
|
"#;
|
|
let parser = Parser::new();
|
|
let result = parser.parse(script);
|
|
assert!(result.is_ok());
|
|
}
|
|
}
|