test: add tests for TemplateRenderer error handling and edge cases
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
import json
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
from behave import given
|
||||
from behave import then
|
||||
from behave import when
|
||||
|
||||
from cleveragents.core.exceptions import TemplateError
|
||||
from cleveragents.templates.renderer import TemplateEngine
|
||||
from cleveragents.templates.renderer import TemplateRenderer
|
||||
|
||||
|
||||
@given('I try to initialize a TemplateRenderer with the "{engine}" engine')
|
||||
def step_impl(context, engine):
|
||||
context.engine_type_str = engine
|
||||
if engine == "jinja2":
|
||||
context.engine_type_enum = TemplateEngine.JINJA2
|
||||
elif engine == "mustache":
|
||||
context.engine_type_enum = TemplateEngine.MUSTACHE
|
||||
|
||||
|
||||
@when('the required package "{package}" is not installed')
|
||||
def step_impl(context, package):
|
||||
with patch.dict(sys.modules, {package: None}):
|
||||
try:
|
||||
TemplateRenderer(context.engine_type_enum)
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@then('a TemplateError should be raised with a message containing "{message}"')
|
||||
def step_impl(context, message):
|
||||
assert hasattr(context, "error"), "TemplateError was not raised"
|
||||
assert isinstance(
|
||||
context.error, TemplateError
|
||||
), f"Expected TemplateError, but got {type(context.error)}"
|
||||
assert message in str(context.error), f"'{message}' not in '{str(context.error)}'"
|
||||
|
||||
|
||||
@given("I have an unsupported template engine type")
|
||||
def step_impl(context):
|
||||
context.unsupported_engine = "unsupported_engine_type"
|
||||
|
||||
|
||||
@when("I try to initialize a TemplateRenderer with this engine type")
|
||||
def step_impl(context):
|
||||
try:
|
||||
# We need to bypass the Enum type check for this test
|
||||
renderer = TemplateRenderer()
|
||||
renderer.engine_type = context.unsupported_engine
|
||||
renderer._initialize_engine()
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@given('a TemplateRenderer with the "{engine}" engine')
|
||||
def step_impl(context, engine):
|
||||
# This step assumes packages are installed for successful initialization
|
||||
context.renderer = TemplateRenderer(TemplateEngine(engine))
|
||||
|
||||
|
||||
@when("I attempt to register a template with an empty name")
|
||||
def step_impl(context):
|
||||
try:
|
||||
context.renderer.register_template("", "some content")
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@when('I try to register a template with invalid Jinja2 syntax "{syntax}"')
|
||||
def step_impl(context, syntax):
|
||||
try:
|
||||
context.renderer.register_template("invalid", syntax)
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@given('a template named "{name}" with content "{content}"')
|
||||
def step_impl(context, name, content):
|
||||
context.renderer.register_template(name, content)
|
||||
|
||||
|
||||
@when('I try to render the "{template_name}" template with an empty context')
|
||||
def step_impl(context, template_name):
|
||||
try:
|
||||
context.renderer.render(template_name, {})
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@when('I try to render the string "{template_str}" with an empty context')
|
||||
def step_impl(context, template_str):
|
||||
try:
|
||||
context.renderer.render_string(template_str, {})
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@when("I render the \"{template_name}\" template with context '{json_context}'")
|
||||
def step_impl(context, template_name, json_context):
|
||||
ctx = json.loads(json_context)
|
||||
context.result = context.renderer.render(template_name, ctx)
|
||||
|
||||
|
||||
@then('the result should be "{expected_result}"')
|
||||
def step_impl(context, expected_result):
|
||||
assert (
|
||||
context.result == expected_result
|
||||
), f"Expected '{expected_result}', got '{context.result}'"
|
||||
|
||||
|
||||
@when('I try to render a template named "{template_name}" with any context')
|
||||
@when('I try to render the "{template_name}" template with any context')
|
||||
def step_impl(context, template_name):
|
||||
try:
|
||||
context.renderer.render(template_name, {"foo": "bar"})
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@when('I try to render the string "{template_str}" with any context')
|
||||
def step_impl(context, template_str):
|
||||
try:
|
||||
context.renderer.render_string(template_str, {"foo": "bar"})
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@when('I try to get a template named "{template_name}"')
|
||||
def step_impl(context, template_name):
|
||||
try:
|
||||
context.renderer.get_template(template_name)
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@given("I have manually modified the engine to be invalid")
|
||||
def step_impl(context):
|
||||
# Replace engine with an object that doesn't have the required methods
|
||||
context.renderer.engine = object()
|
||||
|
||||
|
||||
@when('I try to register a template named "{name}" with content "{content}"')
|
||||
def step_impl(context, name, content):
|
||||
try:
|
||||
context.renderer.register_template(name, content)
|
||||
except TemplateError as e:
|
||||
context.error = e
|
||||
|
||||
|
||||
@given(
|
||||
'I have manually registered a template named "{template_name}" that is not a valid Jinja2 template object'
|
||||
)
|
||||
def step_impl(context, template_name):
|
||||
# Manually insert a non-template object into the templates dict
|
||||
context.renderer.templates[template_name] = "just a string"
|
||||
|
||||
|
||||
@given("I have manually set the engine type to an unsupported value")
|
||||
def step_impl(context):
|
||||
context.renderer.engine_type = "unsupported"
|
||||
@@ -0,0 +1,108 @@
|
||||
Feature: Template Renderer Error Handling and Edge Cases
|
||||
|
||||
Scenario Outline: Template renderer initialization failures for missing packages
|
||||
Given I try to initialize a TemplateRenderer with the "<engine>" engine
|
||||
When the required package "<package>" is not installed
|
||||
Then a TemplateError should be raised with a message containing "<message>"
|
||||
|
||||
Examples:
|
||||
| engine | package | message |
|
||||
| jinja2 | jinja2 | Jinja2 is not installed. Install it with 'pip install jinja2'. |
|
||||
| mustache | pystache | Pystache is not installed. Install it with 'pip install pystache'. |
|
||||
|
||||
Scenario: Template renderer initialization with unsupported engine
|
||||
Given I have an unsupported template engine type
|
||||
When I try to initialize a TemplateRenderer with this engine type
|
||||
Then a TemplateError should be raised with a message containing "Unsupported template engine"
|
||||
|
||||
Scenario: Registering a template with an empty name
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
When I attempt to register a template with an empty name
|
||||
Then a TemplateError should be raised with a message containing "Template name cannot be empty"
|
||||
|
||||
Scenario: Registering an invalid Jinja2 template
|
||||
Given a TemplateRenderer with the "jinja2" engine
|
||||
When I try to register a template with invalid Jinja2 syntax "Hello, {{ name"
|
||||
Then a TemplateError should be raised with a message containing "Failed to register Jinja2 template 'invalid'"
|
||||
|
||||
Scenario: Rendering a simple template with missing format variables
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
And a template named "test" with content "Hello, {name}"
|
||||
When I try to render the "test" template with an empty context
|
||||
Then a TemplateError should be raised with a message containing "Missing template variable: name"
|
||||
|
||||
Scenario: Rendering a simple string with missing format variables
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
When I try to render the string "Hello, {name}" with an empty context
|
||||
Then a TemplateError should be raised with a message containing "Missing template variable: name"
|
||||
|
||||
Scenario: Rendering a simple template with a placeholder evaluating to None
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
And a template named "test" with content "Value: {{novalue}}"
|
||||
When I render the "test" template with context '{"novalue": null}'
|
||||
Then the result should be "Value: "
|
||||
|
||||
Scenario: Rendering a simple template with an invalid expression
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
And a template named "test" with content "Value: {{ 1 +/ 2 }}"
|
||||
When I try to render the "test" template with any context
|
||||
Then a TemplateError should be raised with a message containing "Failed to render template 'test'"
|
||||
|
||||
Scenario: Rendering a simple string with an invalid expression
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
When I try to render the string "Value: {{ 1 +/ 2 }}" with any context
|
||||
Then a TemplateError should be raised with a message containing "Failed to render template string"
|
||||
|
||||
Scenario: Getting a non-existent template
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
When I try to get a template named "nonexistent"
|
||||
Then a TemplateError should be raised with a message containing "Template 'nonexistent' not found"
|
||||
|
||||
Scenario: Rendering a non-existent template
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
When I try to render a template named "nonexistent" with any context
|
||||
Then a TemplateError should be raised with a message containing "Template 'nonexistent' not found"
|
||||
|
||||
Scenario: Registration failure with Jinja2 due to bad engine object
|
||||
Given a TemplateRenderer with the "jinja2" engine
|
||||
And I have manually modified the engine to be invalid
|
||||
When I try to register a template named "test" with content "Hello"
|
||||
Then a TemplateError should be raised with a message containing "Jinja2 environment has no from_string method"
|
||||
|
||||
Scenario: Rendering failure with Jinja2 due to bad template object
|
||||
Given a TemplateRenderer with the "jinja2" engine
|
||||
And I have manually registered a template named "bad_template" that is not a valid Jinja2 template object
|
||||
When I try to render the "bad_template" template with any context
|
||||
Then a TemplateError should be raised with a message containing "Jinja2 template has no render method"
|
||||
|
||||
Scenario: String rendering failure with Jinja2 due to bad engine object
|
||||
Given a TemplateRenderer with the "jinja2" engine
|
||||
And I have manually modified the engine to be invalid
|
||||
When I try to render the string "Hello, {{name}}" with any context
|
||||
Then a TemplateError should be raised with a message containing "Jinja2 environment has no from_string method"
|
||||
|
||||
Scenario: Rendering failure with Mustache due to bad engine object
|
||||
Given a TemplateRenderer with the "mustache" engine
|
||||
And I have manually modified the engine to be invalid
|
||||
And a template named "test" with content "Hello, {{name}}"
|
||||
When I try to render the "test" template with any context
|
||||
Then a TemplateError should be raised with a message containing "Mustache renderer has no render method"
|
||||
|
||||
Scenario: String rendering failure with Mustache due to bad engine object
|
||||
Given a TemplateRenderer with the "mustache" engine
|
||||
And I have manually modified the engine to be invalid
|
||||
When I try to render the string "Hello, {{name}}" with any context
|
||||
Then a TemplateError should be raised with a message containing "Mustache renderer has no render method"
|
||||
|
||||
Scenario: Rendering with an unsupported engine type
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
And I have manually set the engine type to an unsupported value
|
||||
And a template named "test" with content "Hello"
|
||||
When I try to render the "test" template with any context
|
||||
Then a TemplateError should be raised with a message containing "Unsupported template engine"
|
||||
|
||||
Scenario: String rendering with an unsupported engine type
|
||||
Given a TemplateRenderer with the "simple" engine
|
||||
And I have manually set the engine type to an unsupported value
|
||||
When I try to render the string "Hello" with any context
|
||||
Then a TemplateError should be raised with a message containing "Unsupported template engine"
|
||||
Reference in New Issue
Block a user