sal-text 0.1.0

SAL Text - Text processing and manipulation utilities with regex, templating, and normalization
Documentation
//! 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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"));
}