//! Tests for sal-rhai core module functionality //! //! These tests verify the core Rhai integration functions work correctly. use rhai::Engine; use sal_rhai::{error::ToRhaiError, register}; use std::fs; use tempfile::TempDir; /// Test the ToRhaiError trait implementation #[test] fn test_to_rhai_error_trait() { // Test with a standard Result where E implements std::error::Error let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found"); let result: Result = Err(io_error); let rhai_result = result.to_rhai_error(); assert!(rhai_result.is_err(), "Should convert to Rhai error"); let error = rhai_result.unwrap_err(); let error_str = error.to_string(); assert!( error_str.contains("File not found"), "Error message should be preserved: {}", error_str ); } /// Test the ToRhaiError trait with successful result #[test] fn test_to_rhai_error_success() { let result: Result = Ok("success".to_string()); let rhai_result = result.to_rhai_error(); assert!(rhai_result.is_ok(), "Should preserve successful result"); assert_eq!(rhai_result.unwrap(), "success", "Value should be preserved"); } /// Test core module registration #[test] fn test_core_module_registration() { let mut engine = Engine::new(); // Register only the core module let result = sal_rhai::core::register_core_module(&mut engine); assert!( result.is_ok(), "Core module registration should succeed: {:?}", result ); // Verify exec function is registered let script = r#"exec("42")"#; let result = engine.eval::(script); assert!( result.is_ok(), "Exec function should be available: {:?}", result ); assert_eq!( result.unwrap(), 42, "Exec should return the evaluated result" ); } /// Test exec function with direct code execution #[test] fn test_exec_direct_code() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Test simple arithmetic let result = engine.eval::(r#"exec("10 + 20")"#); assert!(result.is_ok(), "Direct code execution failed: {:?}", result); assert_eq!(result.unwrap(), 30, "Should return 30"); // Test string operations let result = engine.eval::(r#"exec(`"Hello" + " " + "World"`)"#); assert!(result.is_ok(), "String operation failed: {:?}", result); assert_eq!(result.unwrap(), "Hello World", "Should concatenate strings"); // Test variable assignment and usage let result = engine.eval::(r#"exec("let x = 5; let y = 10; x * y")"#); assert!(result.is_ok(), "Variable operations failed: {:?}", result); assert_eq!(result.unwrap(), 50, "Should return 5 * 10 = 50"); } /// Test exec function with file execution #[test] fn test_exec_file_execution() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); let temp_dir = TempDir::new().expect("Failed to create temp directory"); let script_file = temp_dir.path().join("test_exec.rhai"); // Create a test script file let script_content = r#" let numbers = [1, 2, 3, 4, 5]; let sum = 0; for num in numbers { sum += num; } sum "#; fs::write(&script_file, script_content).expect("Failed to write script file"); // Execute the script file let exec_script = format!(r#"exec("{}")"#, script_file.display()); let result = engine.eval::(&exec_script); assert!(result.is_ok(), "File execution failed: {:?}", result); assert_eq!(result.unwrap(), 15, "Should return sum of 1+2+3+4+5 = 15"); } /// Test exec function with non-existent file #[test] fn test_exec_nonexistent_file() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Try to execute a non-existent file let result = engine.eval::(r#"exec(`nonexistent_file_xyz123.rhai`)"#); assert!(result.is_err(), "Should fail for non-existent file"); let error = result.unwrap_err(); let error_str = error.to_string(); assert!( error_str.contains("No files found") || error_str.contains("File not found") || error_str.contains("File system error") || error_str.contains("Variable not found"), "Error should indicate file not found: {}", error_str ); } /// Test exec function with malformed Rhai code #[test] fn test_exec_malformed_code() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Test with syntax error let result = engine.eval::(r#"exec("let x = ; // malformed")"#); assert!(result.is_err(), "Should fail for malformed code"); // Test with undefined variable let result = engine.eval::(r#"exec("undefined_variable")"#); assert!(result.is_err(), "Should fail for undefined variable"); } /// Test exec function with complex nested operations #[test] fn test_exec_complex_operations() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); let complex_script = r#" exec(` fn factorial(n) { if n <= 1 { 1 } else { n * factorial(n - 1) } } factorial(5) `) "#; let result = engine.eval::(complex_script); assert!(result.is_ok(), "Complex operation failed: {:?}", result); assert_eq!(result.unwrap(), 120, "Should return 5! = 120"); } /// Test exec function with SAL functions #[test] fn test_exec_with_sal_functions() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Test using SAL functions within exec let script = r#"exec(`exist("Cargo.toml")`)"#; let result = engine.eval::(script); assert!(result.is_ok(), "SAL function in exec failed: {:?}", result); assert!(result.unwrap(), "Cargo.toml should exist"); } /// Test exec function return types #[test] fn test_exec_return_types() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Test boolean return let result = engine.eval::(r#"exec("true")"#); assert!( result.is_ok() && result.unwrap(), "Should return boolean true" ); // Test string return let result = engine.eval::(r#"exec(`"test string"`)"#); assert!(result.is_ok(), "String return failed: {:?}", result); assert_eq!( result.unwrap(), "test string", "Should return correct string" ); // Test array return let result = engine.eval::(r#"exec("[1, 2, 3]")"#); assert!(result.is_ok(), "Array return failed: {:?}", result); let array = result.unwrap(); assert_eq!(array.len(), 3, "Array should have 3 elements"); // Test unit return (no return value) let result = engine.eval::<()>(r#"exec("let x = 42;")"#); assert!(result.is_ok(), "Unit return failed: {:?}", result); } /// Test error propagation in exec function #[test] fn test_exec_error_propagation() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); // Test that errors from executed code are properly propagated let result = engine.eval::(r#"exec("1 / 0")"#); assert!(result.is_err(), "Division by zero should cause error"); // Test that runtime errors are caught let result = engine.eval::(r#"exec("throw 'Custom error'")"#); assert!(result.is_err(), "Thrown errors should be caught"); } /// Test exec function with file containing SAL operations #[test] fn test_exec_file_with_sal_operations() { let mut engine = Engine::new(); register(&mut engine).expect("Failed to register SAL modules"); let temp_dir = TempDir::new().expect("Failed to create temp directory"); let script_file = temp_dir.path().join("sal_operations.rhai"); // Create a script that uses SAL functions let script_content = r#" // Test text processing let text = " indented text "; let processed = dedent(text); let prefixed = prefix(processed, ">> "); // Return length of processed text prefixed.len() "#; fs::write(&script_file, script_content).expect("Failed to write script file"); // Execute the script file let exec_script = format!(r#"exec("{}")"#, script_file.display()); let result = engine.eval::(&exec_script); assert!( result.is_ok(), "SAL operations in file failed: {:?}", result ); assert!(result.unwrap() > 0, "Should return positive length"); }