use crate::templating::renderer::TemplateRenderer;
use anyhow::Result;
use std::collections::HashMap;
use tera::Context as TeraContext;
#[test]
fn test_template_renderer() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let result = renderer.render_template("# Plain Markdown", &TeraContext::new(), None)?;
assert_eq!(result, "# Plain Markdown");
let mut context = TeraContext::new();
context.insert("test_var", "test_value");
let result = renderer.render_template("# {{ test_var }}", &context, None)?;
assert_eq!(result, "# test_value");
Ok(())
}
#[test]
fn test_template_renderer_disabled() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(false, project_dir, None)?;
let mut context = TeraContext::new();
context.insert("test_var", "test_value");
let result = renderer.render_template("# {{ test_var }}", &context, None)?;
assert_eq!(result, "# {{ test_var }}");
Ok(())
}
#[test]
fn test_template_error_formatting() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let context = TeraContext::new();
let result = renderer.render_template("# {{ missing_var }}", &context, None);
assert!(result.is_err());
let error = result.unwrap_err();
let error_msg = format!("{}", error);
assert!(
!error_msg.contains("__tera_one_off"),
"Error should not expose internal Tera template names"
);
assert!(
error_msg.contains("Variable") && error_msg.contains("not found"),
"Error should indicate missing variable. Got: {}",
error_msg
);
Ok(())
}
#[test]
fn test_to_native_path_display() {
let unix_path = ".claude/agents/test.md";
let native_path = crate::templating::utils::to_native_path_display(unix_path);
#[cfg(windows)]
{
assert_eq!(native_path, ".claude\\agents\\test.md");
}
#[cfg(not(windows))]
{
assert_eq!(native_path, ".claude/agents/test.md");
}
}
#[test]
fn test_to_native_path_display_nested() {
let unix_path = ".claude/agents/ai/helpers/test.md";
let native_path = crate::templating::utils::to_native_path_display(unix_path);
#[cfg(windows)]
{
assert_eq!(native_path, ".claude\\agents\\ai\\helpers\\test.md");
}
#[cfg(not(windows))]
{
assert_eq!(native_path, ".claude/agents/ai/helpers/test.md");
}
}
#[test]
fn test_protect_literal_blocks_basic() -> Result<()> {
let project_dir = std::env::current_dir()?;
let renderer = TemplateRenderer::new(true, project_dir, None)?;
let content = r#"# Documentation
Use this syntax:
```literal
{{ agpm.deps.snippets.example.content }}
```
That's how you embed content."#;
let (protected, placeholders) = renderer.protect_literal_blocks(content);
assert_eq!(placeholders.len(), 1);
assert!(protected.contains("__AGPM_LITERAL_BLOCK_0__"));
assert!(!protected.contains("{{ agpm.deps.snippets.example.content }}"));
let placeholder_content = placeholders
.get("__AGPM_LITERAL_BLOCK_0__")
.ok_or_else(|| anyhow::anyhow!("Placeholder __AGPM_LITERAL_BLOCK_0__ not found"))?;
assert!(placeholder_content.contains("{{ agpm.deps.snippets.example.content }}"));
Ok(())
}
#[test]
fn test_protect_literal_blocks_multiple() -> Result<()> {
let project_dir = std::env::current_dir()?;
let renderer = TemplateRenderer::new(true, project_dir, None)?;
let content = r#"# First Example
```literal
{{ first.example }}
```
# Second Example
```literal
{{ second.example }}
```"#;
let (protected, placeholders) = renderer.protect_literal_blocks(content);
assert_eq!(placeholders.len(), 2);
assert!(protected.contains("__AGPM_LITERAL_BLOCK_0__"));
assert!(protected.contains("__AGPM_LITERAL_BLOCK_1__"));
assert!(!protected.contains("{{ first.example }}"));
assert!(!protected.contains("{{ second.example }}"));
Ok(())
}
#[test]
fn test_restore_literal_blocks() -> Result<()> {
let project_dir = std::env::current_dir()?;
let renderer = TemplateRenderer::new(true, project_dir, None)?;
let mut placeholders = HashMap::new();
placeholders.insert(
"__AGPM_LITERAL_BLOCK_0__".to_string(),
"{{ agpm.deps.snippets.example.content }}".to_string(),
);
let content = "# Example\n\n__AGPM_LITERAL_BLOCK_0__\n\nDone.";
let restored = renderer.restore_literal_blocks(content, placeholders);
assert!(restored.contains("```\n{{ agpm.deps.snippets.example.content }}\n```"));
assert!(!restored.contains("__AGPM_LITERAL_BLOCK_0__"));
Ok(())
}
#[test]
fn test_literal_blocks_integration_with_rendering() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let template = r#"# Agent: {{ agent_name }}
## Documentation
Here's how to use template syntax:
```literal
{{ agpm.deps.snippets.helper.content }}
```
The agent name is: {{ agent_name }}"#;
let mut context = TeraContext::new();
context.insert("agent_name", "test-agent");
let result = renderer.render_template(template, &context, None)?;
assert!(result.contains("# Agent: test-agent"));
assert!(result.contains("The agent name is: test-agent"));
assert!(result.contains("```\n{{ agpm.deps.snippets.helper.content }}\n```"));
assert!(result.contains("{{ agpm.deps.snippets.helper.content }}"));
Ok(())
}
#[test]
fn test_literal_blocks_with_complex_template_syntax() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let template = r#"# Documentation
```literal
{% for item in agpm.deps.agents %}
{{ item.name }}: {{ item.version }}
{% endfor %}
```"#;
let context = TeraContext::new();
let result = renderer.render_template(template, &context, None)?;
assert!(result.contains("{% for item in agpm.deps.agents %}"));
assert!(result.contains("{{ item.name }}"));
assert!(result.contains("{% endfor %}"));
Ok(())
}
#[test]
fn test_literal_blocks_empty() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let template = r#"# Example
```literal
```
Done."#;
let context = TeraContext::new();
let result = renderer.render_template(template, &context, None)?;
assert!(result.contains("# Example"));
assert!(result.contains("Done."));
Ok(())
}
#[test]
fn test_literal_blocks_unclosed() -> Result<()> {
let project_dir = std::env::current_dir()?;
let renderer = TemplateRenderer::new(true, project_dir, None)?;
let content = r#"# Example
```literal
{{ template.syntax }}
This block is not closed"#;
let (protected, placeholders) = renderer.protect_literal_blocks(content);
assert_eq!(placeholders.len(), 0);
assert!(protected.contains("```literal"));
assert!(protected.contains("{{ template.syntax }}"));
Ok(())
}
#[test]
fn test_literal_blocks_with_indentation() -> Result<()> {
let project_dir = std::env::current_dir()?;
let renderer = TemplateRenderer::new(true, project_dir, None)?;
let content = r#"# Example
```literal
{{ indented.template }}
```"#;
let (_protected, placeholders) = renderer.protect_literal_blocks(content);
assert_eq!(placeholders.len(), 1);
let placeholder_content = placeholders
.get("__AGPM_LITERAL_BLOCK_0__")
.ok_or_else(|| anyhow::anyhow!("Placeholder __AGPM_LITERAL_BLOCK_0__ not found"))?;
assert!(placeholder_content.contains("{{ indented.template }}"));
Ok(())
}
#[test]
fn test_error_line_numbers_with_frontmatter() -> Result<()> {
let project_dir = std::env::current_dir()?;
let mut renderer = TemplateRenderer::new(true, project_dir, None)?;
let context = TeraContext::new();
let template = r#"---
name: test
description: A test
author: Test Author
version: 1.0.0
tags:
- example
- test
agpm:
templating: true
---
# Test Content
{{ variable >+ invalid }}
More content here."#;
let result = renderer.render_template(template, &context, None);
assert!(result.is_err(), "Should fail with syntax error");
let error = result.unwrap_err();
let error_msg = format!("{:?}", error);
println!("Error message:\n{}", error_msg);
assert!(
error_msg.contains("15") || error_msg.contains("16"),
"Error should report line 15 or 16 (near the template error), not line 5. Error: {}",
error_msg
);
Ok(())
}