use std::fs::File; use std::io::Write; use std::path::PathBuf; use std::sync::{Arc, RwLock}; use rhai::Engine; use tempfile::TempDir; use tera::Context; use rhai_factory::RhaiFactory; use tera_factory::TeraFactory; // Helper function to create a temporary directory with test files fn setup_test_environment() -> (TempDir, PathBuf, PathBuf) { // Create a temporary directory for our test files let temp_dir = TempDir::new().expect("Failed to create temp directory"); let temp_path = temp_dir.path(); // Create a templates directory let templates_dir = temp_path.join("templates"); std::fs::create_dir(&templates_dir).expect("Failed to create templates directory"); // Create a scripts directory let scripts_dir = temp_path.join("scripts"); std::fs::create_dir(&scripts_dir).expect("Failed to create scripts directory"); // Create a simple Rhai script with test functions let script_path = scripts_dir.join("test_functions.rhai"); let mut script_file = File::create(&script_path).expect("Failed to create script file"); script_file.write_all(b" // Test function to add two numbers fn add(a, b) { a + b } // Test function to format a string fn format_greeting(name) { `Hello, ${name}!` } ").expect("Failed to write to script file"); // Create a simple template file with .html.tera extension let template_path = templates_dir.join("test.html.tera"); let mut template_file = File::create(&template_path).expect("Failed to create template file"); template_file.write_all(b"

{{ format_greeting(name=name) }}

The sum of {{ a }} and {{ b }} is: {{ add(a=a, b=b) }}

").expect("Failed to write to template file"); println!("Test environment set up with:"); println!(" Templates directory: {:?}", templates_dir); println!(" Scripts directory: {:?}", scripts_dir); (temp_dir, templates_dir, scripts_dir) } #[test] fn test_create_tera_engine() { println!("Running test_create_tera_engine"); // Set up the test environment let (temp_dir, templates_dir, _) = setup_test_environment(); // Create a TeraFactory let factory = TeraFactory::new(); // Create a Tera engine let tera = factory.create_tera_engine(&[&templates_dir]).expect("Failed to create Tera engine"); // Verify that the template was loaded assert!(tera.get_template_names().any(|name| name == "test.html.tera"), "Template 'test.html.tera' was not loaded"); println!("test_create_tera_engine passed"); // Keep temp_dir in scope until the end of the test drop(temp_dir); } #[test] fn test_create_tera_with_rhai() { println!("Running test_create_tera_with_rhai"); // Set up the test environment let (temp_dir, templates_dir, scripts_dir) = setup_test_environment(); // Create factories let rhai_factory = RhaiFactory::with_caching(); let tera_factory = TeraFactory::new(); // Compile the Rhai script let script_path = scripts_dir.join("test_functions.rhai"); println!("Compiling script: {:?}", script_path); let ast = rhai_factory.compile_modules(&[&script_path], None) .expect("Failed to compile Rhai script"); // Verify that the functions were compiled let _engine = Engine::new(); let fn_names: Vec = ast.iter_functions().map(|f| f.name.to_string()).collect(); println!("Compiled functions: {:?}", fn_names); assert!(fn_names.contains(&"add".to_string()), "Function 'add' was not compiled"); assert!(fn_names.contains(&"format_greeting".to_string()), "Function 'format_greeting' was not compiled"); // Create a hot reloadable AST let hot_ast = Arc::new(RwLock::new(ast)); // Create a Tera engine with Rhai integration println!("Creating Tera engine with Rhai integration"); let tera = tera_factory.create_tera_with_rhai(&[&templates_dir], hot_ast.clone()) .expect("Failed to create Tera engine with Rhai"); // Render the template let mut context = Context::new(); context.insert("name", "World"); context.insert("a", &10); context.insert("b", &5); println!("Rendering template with context: {:?}", context); let rendered = tera.render("test.html.tera", &context).expect("Failed to render template"); // Verify the rendered output println!("Rendered output: {}", rendered); assert!(rendered.contains("Hello, World!"), "Rendered output does not contain greeting"); assert!(rendered.contains("The sum of 10 and 5 is: 15"), "Rendered output does not contain correct sum"); println!("test_create_tera_with_rhai passed"); // Keep temp_dir in scope until the end of the test drop(temp_dir); } #[test] fn test_hot_reload() { println!("Running test_hot_reload"); // Set up the test environment let (temp_dir, templates_dir, scripts_dir) = setup_test_environment(); // Create factories let rhai_factory = RhaiFactory::with_hot_reload().expect("Failed to create RhaiFactory with hot reload"); let tera_factory = TeraFactory::new(); // Compile the Rhai script let script_path = scripts_dir.join("test_functions.rhai"); println!("Compiling script: {:?}", script_path); let ast = rhai_factory.compile_modules(&[&script_path], None) .expect("Failed to compile Rhai script"); // Create a hot reloadable AST let hot_ast = Arc::new(RwLock::new(ast)); // Enable hot reloading println!("Enabling hot reloading"); let _handle = rhai_factory.enable_hot_reload( hot_ast.clone(), &[&script_path], None, Some(Box::new(|| println!("Script reloaded!"))) ).expect("Failed to enable hot reloading"); // Create a Tera engine with Rhai integration println!("Creating Tera engine with Rhai integration"); let tera = tera_factory.create_tera_with_rhai(&[&templates_dir], hot_ast.clone()) .expect("Failed to create Tera engine with Rhai"); // Render the template before modification let mut context = Context::new(); context.insert("name", "World"); context.insert("a", &10); context.insert("b", &5); println!("Rendering template before script modification"); let rendered_before = tera.render("test.html.tera", &context).expect("Failed to render template"); // Verify the rendered output before modification println!("Rendered output before: {}", rendered_before); assert!(rendered_before.contains("Hello, World!"), "Rendered output does not contain greeting"); assert!(rendered_before.contains("The sum of 10 and 5 is: 15"), "Rendered output does not contain correct sum"); // Modify the script file println!("Modifying script file"); let mut script_file = File::create(&script_path).expect("Failed to create script file"); script_file.write_all(b" // Modified test function to add two numbers fn add(a, b) { a + b + 1 // Changed to add 1 to the result } // Modified test function to format a string fn format_greeting(name) { `Greetings, ${name}!` // Changed greeting format } ").expect("Failed to write to script file"); // Check for changes println!("Checking for script changes"); let changes_detected = rhai_factory.check_for_changes().expect("Failed to check for changes"); assert!(changes_detected, "Changes were not detected"); // Render the template after modification println!("Rendering template after script modification"); let rendered_after = tera.render("test.html.tera", &context).expect("Failed to render template"); // Verify the rendered output after modification println!("Rendered output after: {}", rendered_after); assert!(rendered_after.contains("Greetings, World!"), "Rendered output does not contain modified greeting"); assert!(rendered_after.contains("The sum of 10 and 5 is: 16"), "Rendered output does not contain modified sum"); println!("test_hot_reload passed"); // Keep temp_dir in scope until the end of the test drop(temp_dir); } #[test] fn test_error_handling() { println!("Running test_error_handling"); // Set up the test environment let (temp_dir, templates_dir, scripts_dir) = setup_test_environment(); // Create factories let rhai_factory = RhaiFactory::with_caching(); let tera_factory = TeraFactory::new(); // Create a script with syntax errors let invalid_script_path = scripts_dir.join("invalid.rhai"); let mut invalid_script_file = File::create(&invalid_script_path).expect("Failed to create invalid script file"); invalid_script_file.write_all(b" // This script has a syntax error fn broken_function(a, b { // Missing closing parenthesis a + b } ").expect("Failed to write to invalid script file"); // Try to compile the invalid script println!("Attempting to compile invalid script"); let compile_result = rhai_factory.compile_modules(&[&invalid_script_path], None); // Verify that compilation fails with an error assert!(compile_result.is_err(), "Compilation of invalid script should fail"); println!("Compilation error (expected): {:?}", compile_result.err()); // Create a template with invalid syntax let invalid_template_path = templates_dir.join("invalid.html.tera"); let mut invalid_template_file = File::create(&invalid_template_path).expect("Failed to create invalid template file"); invalid_template_file.write_all(b"

{{ unclosed tag

").expect("Failed to write to invalid template file"); // Try to create a Tera engine with the invalid template println!("Attempting to create Tera engine with invalid template"); let tera_result = tera_factory.create_tera_engine(&[&templates_dir]); // Verify that Tera creation still succeeds (Tera loads valid templates and logs errors for invalid ones) assert!(tera_result.is_ok(), "Tera engine creation should succeed even with invalid templates"); println!("test_error_handling passed"); // Keep temp_dir in scope until the end of the test drop(temp_dir); } #[test] fn test_function_adapter() { println!("Running test_function_adapter"); // Set up the test environment let (temp_dir, templates_dir, scripts_dir) = setup_test_environment(); // Create factories let rhai_factory = RhaiFactory::with_caching(); let tera_factory = TeraFactory::new(); // Create a script with functions that use different parameter types let types_script_path = scripts_dir.join("types.rhai"); let mut types_script_file = File::create(&types_script_path).expect("Failed to create types script file"); types_script_file.write_all(b" // Function that returns an integer fn return_int() { 42 } // Function that returns a float fn return_float() { 3.14159 } // Function that returns a string fn return_string() { \"Hello, World!\" } // Function that returns a boolean fn return_bool() { true } // Function that returns an array fn return_array() { [1, 2, 3, 4, 5] } // Function that returns a map fn return_map() { #{ \"name\": \"John\", \"age\": 30, \"city\": \"New York\" } } ").expect("Failed to write to types script file"); // Create a template that uses these functions with .html.tera extension let types_template_path = templates_dir.join("types.html.tera"); let mut types_template_file = File::create(&types_template_path).expect("Failed to create types template file"); println!("Created template file at: {:?}", types_template_path); types_template_file.write_all(b"

Integer: {{ return_int() }}

Float: {{ return_float() }}

String: {{ return_string() }}

Boolean: {{ return_bool() }}

Array: {{ return_array() }}

Map name: {{ return_map().name }}

Map age: {{ return_map().age }}

").expect("Failed to write to types template file"); // Compile the script println!("Compiling types script"); let ast = rhai_factory.compile_modules(&[&types_script_path], None) .expect("Failed to compile types script"); // Create a hot reloadable AST let hot_ast = Arc::new(RwLock::new(ast)); // Create a Tera engine with Rhai integration println!("Creating Tera engine with Rhai integration for types test"); println!("Template directory exists: {:?}", std::fs::metadata(&templates_dir).is_ok()); println!("Template directory contents:"); if let Ok(entries) = std::fs::read_dir(&templates_dir) { for entry in entries.filter_map(Result::ok) { println!(" - {:?}", entry.path()); } } let tera = tera_factory.create_tera_with_rhai(&[&templates_dir], hot_ast.clone()) .expect("Failed to create Tera engine with Rhai"); // Print available template names for debugging println!("Available templates: {:?}", tera.get_template_names().collect::>()); // Render the template println!("Rendering types template"); let rendered = tera.render("types.html.tera", &Context::new()).expect("Failed to render types template"); // Verify the rendered output for each type println!("Rendered output: {}", rendered); assert!(rendered.contains("Integer: 42"), "Integer not correctly rendered"); assert!(rendered.contains("Float: 3.14159"), "Float not correctly rendered"); assert!(rendered.contains("String: Hello, World!"), "String not correctly rendered"); assert!(rendered.contains("Boolean: true"), "Boolean not correctly rendered"); assert!(rendered.contains("Array: [1, 2, 3, 4, 5]"), "Array not correctly rendered"); assert!(rendered.contains("Map name: John"), "Map name not correctly rendered"); assert!(rendered.contains("Map age: 30"), "Map age not correctly rendered"); println!("test_function_adapter passed"); // Keep temp_dir in scope until the end of the test drop(temp_dir); }