//! Unit tests for template functionality //! //! These tests validate the TemplateBuilder including: //! - Template loading from files //! - Variable substitution (string, int, float, bool, array) //! - Template rendering to string and file //! - Error handling for missing variables and invalid templates //! - Complex template scenarios with loops and conditionals use sal_text::TemplateBuilder; use std::collections::HashMap; use std::fs; use tempfile::NamedTempFile; #[test] fn test_template_builder_basic_string_variable() { // Create a temporary template file let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "Hello {{name}}!"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("name", "World") .render() .expect("Failed to render template"); assert_eq!(result, "Hello World!"); } #[test] fn test_template_builder_multiple_variables() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "{{greeting}} {{name}}, you have {{count}} messages."; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("greeting", "Hello") .add_var("name", "Alice") .add_var("count", 5) .render() .expect("Failed to render template"); assert_eq!(result, "Hello Alice, you have 5 messages."); } #[test] fn test_template_builder_different_types() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "String: {{text}}, Int: {{number}}, Float: {{decimal}}, Bool: {{flag}}"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("text", "hello") .add_var("number", 42) .add_var("decimal", 3.14) .add_var("flag", true) .render() .expect("Failed to render template"); assert_eq!(result, "String: hello, Int: 42, Float: 3.14, Bool: true"); } #[test] fn test_template_builder_array_variable() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "Items: {% for item in items %}{{item}}{% if not loop.last %}, {% endif %}{% endfor %}"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let items = vec!["apple", "banana", "cherry"]; let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("items", items) .render() .expect("Failed to render template"); assert_eq!(result, "Items: apple, banana, cherry"); } #[test] fn test_template_builder_add_vars_hashmap() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "{{title}}: {{description}}"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let mut vars = HashMap::new(); vars.insert("title".to_string(), "Report".to_string()); vars.insert("description".to_string(), "Monthly summary".to_string()); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_vars(vars) .render() .expect("Failed to render template"); assert_eq!(result, "Report: Monthly summary"); } #[test] fn test_template_builder_render_to_file() { // Create template file let mut template_file = NamedTempFile::new().expect("Failed to create template file"); let template_content = "Hello {{name}}, today is {{day}}."; fs::write(template_file.path(), template_content).expect("Failed to write template"); // Create output file let output_file = NamedTempFile::new().expect("Failed to create output file"); TemplateBuilder::open(template_file.path()) .expect("Failed to open template") .add_var("name", "Bob") .add_var("day", "Monday") .render_to_file(output_file.path()) .expect("Failed to render to file"); let result = fs::read_to_string(output_file.path()).expect("Failed to read output file"); assert_eq!(result, "Hello Bob, today is Monday."); } #[test] fn test_template_builder_conditional() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "{% if show_message %}Message: {{message}}{% else %}No message{% endif %}"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); // Test with condition true let result_true = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("show_message", true) .add_var("message", "Hello World") .render() .expect("Failed to render template"); assert_eq!(result_true, "Message: Hello World"); // Test with condition false let result_false = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("show_message", false) .add_var("message", "Hello World") .render() .expect("Failed to render template"); assert_eq!(result_false, "No message"); } #[test] fn test_template_builder_loop_with_index() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "{% for item in items %}{{loop.index}}: {{item}}\n{% endfor %}"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let items = vec!["first", "second", "third"]; let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("items", items) .render() .expect("Failed to render template"); assert_eq!(result, "1: first\n2: second\n3: third\n"); } #[test] fn test_template_builder_nested_variables() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "User: {{user.name}} ({{user.email}})"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let mut user = HashMap::new(); user.insert("name".to_string(), "John Doe".to_string()); user.insert("email".to_string(), "john@example.com".to_string()); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("user", user) .render() .expect("Failed to render template"); assert_eq!(result, "User: John Doe (john@example.com)"); } #[test] fn test_template_builder_missing_variable_error() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "Hello {{missing_var}}!"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .render(); assert!(result.is_err()); } #[test] fn test_template_builder_invalid_template_syntax() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "Hello {{unclosed_var!"; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .render(); assert!(result.is_err()); } #[test] fn test_template_builder_nonexistent_file() { let result = TemplateBuilder::open("/nonexistent/template.txt"); assert!(result.is_err()); } #[test] fn test_template_builder_empty_template() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); fs::write(temp_file.path(), "").expect("Failed to write empty template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .render() .expect("Failed to render empty template"); assert_eq!(result, ""); } #[test] fn test_template_builder_template_with_no_variables() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = "This is a static template with no variables."; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .render() .expect("Failed to render template"); assert_eq!(result, template_content); } #[test] fn test_template_builder_complex_report() { let mut temp_file = NamedTempFile::new().expect("Failed to create temp file"); let template_content = r#" # {{report_title}} Generated on: {{date}} ## Summary Total items: {{total_items}} Status: {{status}} ## Items {% for item in items %} - {{item.name}}: {{item.value}}{% if item.important %} (IMPORTANT){% endif %} {% endfor %} ## Footer {% if show_footer %} Report generated by {{generator}} {% endif %} "#; fs::write(temp_file.path(), template_content).expect("Failed to write template"); let mut item1 = HashMap::new(); item1.insert("name".to_string(), "Item 1".to_string()); item1.insert("value".to_string(), "100".to_string()); item1.insert("important".to_string(), true.to_string()); let mut item2 = HashMap::new(); item2.insert("name".to_string(), "Item 2".to_string()); item2.insert("value".to_string(), "200".to_string()); item2.insert("important".to_string(), false.to_string()); let items = vec![item1, item2]; let result = TemplateBuilder::open(temp_file.path()) .expect("Failed to open template") .add_var("report_title", "Monthly Report") .add_var("date", "2023-12-01") .add_var("total_items", 2) .add_var("status", "Complete") .add_var("items", items) .add_var("show_footer", true) .add_var("generator", "SAL Text") .render() .expect("Failed to render template"); assert!(result.contains("# Monthly Report")); assert!(result.contains("Generated on: 2023-12-01")); assert!(result.contains("Total items: 2")); assert!(result.contains("- Item 1: 100")); assert!(result.contains("- Item 2: 200")); assert!(result.contains("Report generated by SAL Text")); }