Files
cleveragents-core/tests/features/steps/templates_base_steps.py
T

1103 lines
40 KiB
Python

"""
Step definitions for templates base module testing.
"""
from unittest.mock import Mock
from behave import given, then, when
from cleveragents.templates.base import (
BaseTemplate,
ComponentReference,
InstantiationContext,
TemplateParameter,
TemplateType,
)
@given("I have a clean test environment for templates")
def step_clean_template_environment(context):
"""Set up clean test environment for templates."""
context.template_types = None
context.template_param = None
context.validation_result = None
context.error = None
context.component_ref = None
context.context_instance = None
context.template_instance = None
context.components = {}
context.params = {}
context.result = None
# TemplateType enum tests
@when("I access all TemplateType enum values")
def step_access_template_types(context):
"""Access all TemplateType enum values."""
try:
context.template_types = {
"AGENT": TemplateType.AGENT,
"GRAPH": TemplateType.GRAPH,
"STREAM": TemplateType.STREAM,
}
except Exception as e:
context.error = e
@then("all template types should be available")
def step_verify_template_types_available(context):
"""Verify all template types are available."""
assert context.error is None
assert context.template_types is not None
assert "AGENT" in context.template_types
assert "GRAPH" in context.template_types
assert "STREAM" in context.template_types
@then("enum values should have correct string representations")
def step_verify_enum_string_representations(context):
"""Verify enum string representations."""
assert context.template_types["AGENT"].value == "agent"
assert context.template_types["GRAPH"].value == "graph"
assert context.template_types["STREAM"].value == "stream"
# TemplateParameter tests - string type
@given("I have a string template parameter with default value")
def step_string_template_parameter(context):
"""Create string template parameter."""
context.template_param = TemplateParameter(
name="test_param",
default="default_value",
type="string",
description="Test string parameter",
)
@when("I validate different string values")
def step_validate_string_values(context):
"""Validate different string values."""
context.results = {}
try:
# Test normal string
context.results["normal"] = context.template_param.validate("test_string")
# Test None (should use default)
context.results["none"] = context.template_param.validate(None)
# Test number conversion to string
context.results["number"] = context.template_param.validate(123)
except Exception as e:
context.error = e
@then("string validation should work correctly")
def step_verify_string_validation(context):
"""Verify string validation works."""
assert context.error is None
assert context.results["normal"] == "test_string"
assert context.results["number"] == "123"
@then("default values should be used when None")
def step_verify_default_values(context):
"""Verify default values are used for None."""
assert context.results["none"] == "default_value"
# TemplateParameter tests - int type
@given("I have an integer template parameter")
def step_integer_template_parameter(context):
"""Create integer template parameter."""
context.template_param = TemplateParameter(name="int_param", type="int", default=42)
@when("I validate integer values including conversions")
def step_validate_integer_values(context):
"""Validate integer values."""
context.results = {}
context.errors = {}
try:
# Test normal int
context.results["normal"] = context.template_param.validate(100)
# Test string conversion
context.results["string_convert"] = context.template_param.validate("200")
# Test None (default)
context.results["none"] = context.template_param.validate(None)
except Exception as e:
context.error = e
# Test invalid conversion
try:
context.template_param.validate("invalid_int")
except ValueError as e:
context.errors["invalid"] = e
@then("integer validation should work correctly")
def step_verify_integer_validation(context):
"""Verify integer validation."""
assert context.error is None
assert context.results["normal"] == 100
assert context.results["string_convert"] == 200
assert context.results["none"] == 42
@then("invalid integers should raise errors")
def step_verify_invalid_integers_error(context):
"""Verify invalid integers raise errors."""
assert "invalid" in context.errors
assert isinstance(context.errors["invalid"], ValueError)
# TemplateParameter tests - float type
@given("I have a float template parameter")
def step_float_template_parameter(context):
"""Create float template parameter."""
context.template_param = TemplateParameter(name="float_param", type="float", default=3.14)
@when("I validate float values including conversions")
def step_validate_float_values(context):
"""Validate float values."""
context.results = {}
try:
# Test normal float
context.results["normal"] = context.template_param.validate(2.5)
# Test string conversion
context.results["string_convert"] = context.template_param.validate("1.5")
# Test int conversion
context.results["int_convert"] = context.template_param.validate(5)
# Test None (default)
context.results["none"] = context.template_param.validate(None)
except Exception as e:
context.error = e
@then("float validation should work correctly")
def step_verify_float_validation(context):
"""Verify float validation."""
assert context.error is None
assert context.results["normal"] == 2.5
assert context.results["string_convert"] == 1.5
assert context.results["int_convert"] == 5.0
assert context.results["none"] == 3.14
# TemplateParameter tests - boolean type
@given("I have a boolean template parameter")
def step_boolean_template_parameter(context):
"""Create boolean template parameter."""
context.template_param = TemplateParameter(name="bool_param", type="boolean", default=False)
@when("I validate boolean values including string conversions")
def step_validate_boolean_values(context):
"""Validate boolean values."""
context.results = {}
try:
# Test normal bool
context.results["normal_true"] = context.template_param.validate(True)
context.results["normal_false"] = context.template_param.validate(False)
# Test string conversions
context.results["string_true"] = context.template_param.validate("true")
context.results["string_yes"] = context.template_param.validate("yes")
context.results["string_1"] = context.template_param.validate("1")
context.results["string_on"] = context.template_param.validate("on")
context.results["string_false"] = context.template_param.validate("false")
context.results["string_no"] = context.template_param.validate("no")
# Test other types
context.results["int_1"] = context.template_param.validate(1)
context.results["int_0"] = context.template_param.validate(0)
# Test None (default)
context.results["none"] = context.template_param.validate(None)
except Exception as e:
context.error = e
@then("boolean validation should work correctly")
def step_verify_boolean_validation(context):
"""Verify boolean validation."""
assert context.error is None
assert context.results["normal_true"] is True
assert context.results["normal_false"] is False
assert context.results["int_1"] is True
assert context.results["int_0"] is False
assert context.results["none"] is False
@then("string boolean values should convert properly")
def step_verify_string_boolean_conversion(context):
"""Verify string boolean conversion."""
assert context.results["string_true"] is True
assert context.results["string_yes"] is True
assert context.results["string_1"] is True
assert context.results["string_on"] is True
assert context.results["string_false"] is False
assert context.results["string_no"] is False
# TemplateParameter tests - enum type
@given("I have an enum template parameter with allowed values")
def step_enum_template_parameter(context):
"""Create enum template parameter."""
context.template_param = TemplateParameter(
name="enum_param",
type="enum",
values=["option1", "option2", "option3"],
default="option1",
)
@when("I validate enum values")
def step_validate_enum_values(context):
"""Validate enum values."""
context.results = {}
context.errors = {}
try:
# Test valid values
context.results["valid1"] = context.template_param.validate("option1")
context.results["valid2"] = context.template_param.validate("option2")
# Test None (default)
context.results["none"] = context.template_param.validate(None)
except Exception as e:
context.error = e
# Test invalid value
try:
context.template_param.validate("invalid_option")
except ValueError as e:
context.errors["invalid"] = e
@then("valid enum values should pass")
def step_verify_valid_enum_values(context):
"""Verify valid enum values pass."""
assert context.error is None
assert context.results["valid1"] == "option1"
assert context.results["valid2"] == "option2"
assert context.results["none"] == "option1"
@then("invalid enum values should raise errors")
def step_verify_invalid_enum_error(context):
"""Verify invalid enum values raise errors."""
assert "invalid" in context.errors
assert isinstance(context.errors["invalid"], ValueError)
assert "must be one of" in str(context.errors["invalid"])
# TemplateParameter tests - list type
@given("I have a list template parameter")
def step_list_template_parameter(context):
"""Create list template parameter."""
context.template_param = TemplateParameter(name="list_param", type="list", default=[])
@when("I validate list values including single value conversion")
def step_validate_list_values(context):
"""Validate list values."""
context.results = {}
try:
# Test normal list
context.results["normal"] = context.template_param.validate([1, 2, 3])
# Test single value conversion
context.results["single"] = context.template_param.validate("single_item")
# Test None (default)
context.results["none"] = context.template_param.validate(None)
except Exception as e:
context.error = e
@then("list validation should work correctly")
def step_verify_list_validation(context):
"""Verify list validation."""
assert context.error is None
assert context.results["normal"] == [1, 2, 3]
assert context.results["none"] == []
@then("single values should convert to lists")
def step_verify_single_value_conversion(context):
"""Verify single values convert to lists."""
assert context.results["single"] == ["single_item"]
# TemplateParameter tests - dict and reference types
@given("I have parameters of different reference types")
def step_reference_type_parameters(context):
"""Create parameters of different reference types."""
context.params = {
"dict": TemplateParameter(name="dict_param", type="dict"),
"agent_ref": TemplateParameter(name="agent_ref_param", type="agent_ref"),
"component_ref": TemplateParameter(name="comp_ref_param", type="component_ref"),
"unknown": TemplateParameter(name="unknown_param", type="unknown_type"),
}
@when("I validate dict, agent_ref, and component_ref values")
def step_validate_reference_values(context):
"""Validate reference type values."""
context.results = {}
try:
# Test dict type
test_dict = {"key": "value"}
context.results["dict"] = context.params["dict"].validate(test_dict)
# Test agent_ref type
agent_ref = {"type": "agent", "name": "test_agent"}
context.results["agent_ref"] = context.params["agent_ref"].validate(agent_ref)
# Test component_ref type
comp_ref = {"type": "component", "name": "test_comp"}
context.results["component_ref"] = context.params["component_ref"].validate(comp_ref)
# Test unknown type (should pass through)
context.results["unknown"] = context.params["unknown"].validate("any_value")
except Exception as e:
context.error = e
@then("reference type validation should work correctly")
def step_verify_reference_validation(context):
"""Verify reference type validation."""
assert context.error is None
assert context.results["dict"] == {"key": "value"}
assert context.results["agent_ref"] == {"type": "agent", "name": "test_agent"}
assert context.results["component_ref"] == {
"type": "component",
"name": "test_comp",
}
assert context.results["unknown"] == "any_value"
# TemplateParameter tests - required parameter
@given("I have a required template parameter")
def step_required_template_parameter(context):
"""Create required template parameter."""
context.template_param = TemplateParameter(name="required_param", type="string", required=True)
@when("I validate with None value")
def step_validate_none_required(context):
"""Validate None value on required parameter."""
try:
context.result = context.template_param.validate(None)
except ValueError as e:
context.error = e
@then("a ValueError should be raised for missing required parameter")
def step_verify_required_error(context):
"""Verify ValueError for missing required parameter."""
assert context.error is not None
assert isinstance(context.error, ValueError)
assert "Required parameter" in str(context.error)
# ComponentReference tests
@given("I have component references of different types")
def step_component_references(context):
"""Create component references."""
context.component_refs = {
"agent": ComponentReference("agent", "test_agent", {"param": "value"}),
"graph": ComponentReference("graph", "test_graph"),
"stream": ComponentReference("stream", "test_stream", {"config": "test"}),
}
@when("I create ComponentReference instances")
def step_create_component_references(context):
"""Create ComponentReference instances."""
try:
# Already created in given step
context.result = "success"
except Exception as e:
context.error = e
@then("component references should be created correctly")
def step_verify_component_references(context):
"""Verify component references are created correctly."""
assert context.error is None
assert context.result == "success"
agent_ref = context.component_refs["agent"]
assert agent_ref.ref_type == "agent"
assert agent_ref.ref_name == "test_agent"
assert agent_ref.ref_params == {"param": "value"}
graph_ref = context.component_refs["graph"]
assert graph_ref.ref_type == "graph"
assert graph_ref.ref_name == "test_graph"
assert graph_ref.ref_params == {}
@then("reference properties should be accessible")
def step_verify_reference_properties(context):
"""Verify reference properties are accessible."""
stream_ref = context.component_refs["stream"]
assert stream_ref.ref_type == "stream"
assert stream_ref.ref_name == "test_stream"
assert stream_ref.ref_params == {"config": "test"}
# InstantiationContext tests
@given("I have an InstantiationContext")
def step_instantiation_context(context):
"""Create InstantiationContext."""
context.context_instance = InstantiationContext()
@when("I add components of different types")
def step_add_components(context):
"""Add components to context."""
try:
context.context_instance.add_component("agent", "agent1", {"type": "test_agent"})
context.context_instance.add_component("graph", "graph1", {"type": "test_graph"})
context.context_instance.add_component("stream", "stream1", {"type": "test_stream"})
except Exception as e:
context.error = e
@then("components should be stored correctly")
def step_verify_components_stored(context):
"""Verify components are stored correctly."""
assert context.error is None
components = context.context_instance.components
assert "agent1" in components["agents"]
assert "graph1" in components["graphs"]
assert "stream1" in components["streams"]
@then("component retrieval should work")
def step_verify_component_retrieval(context):
"""Verify component retrieval works."""
components = context.context_instance.components
assert components["agents"]["agent1"]["type"] == "test_agent"
assert components["graphs"]["graph1"]["type"] == "test_graph"
assert components["streams"]["stream1"]["type"] == "test_stream"
# InstantiationContext with parent tests
@given("I have a parent InstantiationContext with components")
def step_parent_context_with_components(context):
"""Create parent context with components."""
context.parent_context = InstantiationContext()
context.parent_context.add_component("agent", "parent_agent", {"type": "parent"})
@given("I have a child context")
def step_child_context(context):
"""Create child context."""
context.child_context = InstantiationContext(parent=context.parent_context)
context.child_context.add_component("agent", "child_agent", {"type": "child"})
@when("I try to resolve references in child context")
def step_resolve_references_child(context):
"""Resolve references in child context."""
try:
# Create references
parent_ref = ComponentReference("agent", "parent_agent")
child_ref = ComponentReference("agent", "child_agent")
missing_ref = ComponentReference("agent", "missing_agent")
# Test resolution
context.results = {
"parent": context.child_context.resolve_reference(parent_ref),
"child": context.child_context.resolve_reference(child_ref),
"missing": context.child_context.resolve_reference(missing_ref),
}
except Exception as e:
context.error = e
@then("child context should check parent for references")
def step_verify_parent_resolution(context):
"""Verify child context checks parent for references."""
assert context.error is None
assert context.results["parent"]["type"] == "parent"
assert context.results["child"]["type"] == "child"
assert context.results["missing"] is None
# InstantiationContext reference resolution tests
@given("I have an InstantiationContext with components")
def step_context_with_components(context):
"""Create context with components."""
context.context_instance = InstantiationContext()
context.context_instance.add_component("agent", "existing_agent", {"data": "test"})
@when("I resolve component references")
def step_resolve_component_references(context):
"""Resolve component references."""
try:
existing_ref = ComponentReference("agent", "existing_agent")
missing_ref = ComponentReference("agent", "missing_agent")
context.results = {
"existing": context.context_instance.resolve_reference(existing_ref),
"missing": context.context_instance.resolve_reference(missing_ref),
}
except Exception as e:
context.error = e
@then("existing references should be resolved correctly")
def step_verify_existing_resolution(context):
"""Verify existing references resolve correctly."""
assert context.error is None
assert context.results["existing"]["data"] == "test"
@then("missing references should return None")
def step_verify_missing_return_none(context):
"""Verify missing references return None."""
assert context.results["missing"] is None
# InstantiationContext pending references tests
@when("I resolve references that don't exist yet")
def step_resolve_pending_references(context):
"""Resolve references that don't exist yet."""
try:
pending_ref = ComponentReference("graph", "pending_graph")
result = context.context_instance.resolve_reference(pending_ref)
context.pending_result = result
# Check pending list
context.pending_count = len(context.context_instance._pending_resolutions)
except Exception as e:
context.error = e
@then("references should be added to pending list")
def step_verify_pending_list(context):
"""Verify references are added to pending list."""
assert context.error is None
assert context.pending_result is None
assert context.pending_count > 0
@then("resolve_pending should handle unresolved references")
def step_verify_resolve_pending(context):
"""Verify resolve_pending handles unresolved references."""
try:
context.context_instance.resolve_pending()
except ValueError as e:
context.pending_error = e
# Should raise error for unresolved references
assert hasattr(context, "pending_error")
assert "Cannot resolve references" in str(context.pending_error)
# InstantiationContext get_all_components tests
@given("I have an InstantiationContext with various components")
def step_context_various_components(context):
"""Create context with various components."""
context.context_instance = InstantiationContext()
context.context_instance.add_component("agent", "agent1", {"type": "llm"})
context.context_instance.add_component("graph", "graph1", {"nodes": ["a", "b"]})
context.original_components = context.context_instance.components
@when("I get all components")
def step_get_all_components(context):
"""Get all components."""
try:
context.all_components = context.context_instance.get_all_components()
except Exception as e:
context.error = e
@then("a deep copy of all components should be returned")
def step_verify_deep_copy_components(context):
"""Verify deep copy of components."""
assert context.error is None
assert context.all_components == context.original_components
# Verify it's a deep copy by modifying original
context.original_components["agents"]["agent1"]["modified"] = True
assert "modified" not in context.all_components["agents"]["agent1"]
# Concrete BaseTemplate implementation for testing
class TestTemplate(BaseTemplate):
def instantiate(self, params, registry, context):
return {"template": self.name, "params": params}
# BaseTemplate parameter parsing tests - dict format
@given("I have a template definition with dict format parameters")
def step_template_dict_params(context):
"""Create template with dict format parameters."""
context.template_definition = {
"parameters": {
"param1": {
"type": "string",
"default": "default1",
"description": "First parameter",
},
"param2": {"type": "int", "required": True},
"param3": "simple_default", # Simple value format
}
}
@when("I create a BaseTemplate instance")
def step_create_template_instance(context):
"""Create BaseTemplate instance."""
try:
context.template_instance = TestTemplate("test_template", TemplateType.AGENT, context.template_definition)
except Exception as e:
context.error = e
@then("parameters should be parsed correctly from dict format")
def step_verify_dict_params_parsing(context):
"""Verify dict format parameters parsing."""
assert context.error is None
params = context.template_instance.parameters
assert "param1" in params
assert params["param1"].type == "string"
assert params["param1"].default == "default1"
assert params["param1"].description == "First parameter"
assert "param2" in params
assert params["param2"].type == "int"
assert params["param2"].required is True
assert "param3" in params
assert params["param3"].default == "simple_default"
# BaseTemplate parameter parsing tests - list format
@given("I have a template definition with list format parameters")
def step_template_list_params(context):
"""Create template with list format parameters."""
context.template_definition = {
"parameters": [
{"name": "param1", "type": "string", "default": "list_default"},
{"name": "param2", "type": "boolean", "required": True},
"simple_param", # Simple parameter name
]
}
@then("parameters should be parsed correctly from list format")
def step_verify_list_params_parsing(context):
"""Verify list format parameters parsing."""
assert context.error is None
params = context.template_instance.parameters
assert "param1" in params
assert params["param1"].type == "string"
assert params["param1"].default == "list_default"
assert "param2" in params
assert params["param2"].type == "boolean"
assert params["param2"].required is True
assert "simple_param" in params
assert params["simple_param"].name == "simple_param"
# BaseTemplate parameter parsing tests - mixed formats
@given("I have a template definition with mixed parameter formats")
def step_template_mixed_params(context):
"""Create template with mixed parameter formats."""
context.template_definition = {
"parameters": {"dict_param": {"type": "float", "default": 3.14}},
"other_config": "not_parameters",
}
@then("all parameter formats should be parsed correctly")
def step_verify_mixed_params_parsing(context):
"""Verify mixed format parameters parsing."""
assert context.error is None
params = context.template_instance.parameters
assert "dict_param" in params
assert params["dict_param"].type == "float"
assert params["dict_param"].default == 3.14
# BaseTemplate validate_params tests
@given("I have a BaseTemplate with various parameter types")
def step_template_various_param_types(context):
"""Create template with various parameter types."""
context.template_definition = {
"parameters": {
"string_param": {"type": "string", "default": "default"},
"int_param": {"type": "int", "required": True},
"bool_param": {"type": "boolean", "default": False},
}
}
context.template_instance = TestTemplate("test_template", TemplateType.AGENT, context.template_definition)
@when("I validate parameters with different values")
def step_validate_various_params(context):
"""Validate parameters with different values."""
try:
input_params = {
"string_param": "custom_string",
"int_param": 42,
"extra_param": "extra_value", # Not in definition
}
context.validated_params = context.template_instance.validate_params(input_params)
except Exception as e:
context.error = e
@then("parameter validation should work correctly")
def step_verify_param_validation(context):
"""Verify parameter validation works correctly."""
assert context.error is None
params = context.validated_params
assert params["string_param"] == "custom_string"
assert params["int_param"] == 42
assert params["bool_param"] is False # Default value
@then("extra parameters should be included")
def step_verify_extra_params_included(context):
"""Verify extra parameters are included."""
assert context.validated_params["extra_param"] == "extra_value"
# BaseTemplate _apply_template_vars tests - string templates
@given("I have a BaseTemplate instance")
def step_basic_template_instance(context):
"""Create basic BaseTemplate instance."""
context.template_instance = TestTemplate("test_template", TemplateType.AGENT, {})
@when("I apply template variables to string templates")
def step_apply_string_templates(context):
"""Apply template variables to string templates."""
try:
test_params = {"name": "test", "count": 5, "enabled": True}
context.results = {
"simple": context.template_instance._apply_template_vars("Hello {{ name }}", test_params),
"complex": context.template_instance._apply_template_vars("Count: {{ count }}", test_params),
"boolean_true": context.template_instance._apply_template_vars("{{ enabled }}", test_params),
"boolean_false": context.template_instance._apply_template_vars("{{ not enabled }}", test_params),
"boolean_string_true": context.template_instance._apply_template_vars("true", test_params),
"boolean_string_false": context.template_instance._apply_template_vars("false", test_params),
"no_template": context.template_instance._apply_template_vars("plain string", test_params),
}
except Exception as e:
context.error = e
@then("Jinja2 templates should be rendered correctly")
def step_verify_jinja_rendering(context):
"""Verify Jinja2 templates are rendered correctly."""
assert context.error is None
assert context.results["simple"] == "Hello test"
assert context.results["complex"] == "Count: 5"
assert context.results["no_template"] == "plain string"
@then("boolean strings should convert to boolean values")
def step_verify_boolean_string_conversion(context):
"""Verify boolean strings convert to boolean values."""
# Template-rendered booleans should convert
assert context.results["boolean_true"] is True
assert context.results["boolean_false"] is False
# Plain boolean strings should remain as strings (only templated ones convert)
assert context.results["boolean_string_true"] == "true"
assert context.results["boolean_string_false"] == "false"
# BaseTemplate _apply_template_vars tests - JSON parsing
@when("I apply template variables that result in JSON-like strings")
def step_apply_json_templates(context):
"""Apply template variables that result in JSON-like strings."""
try:
test_params = {"items": ["a", "b", "c"], "config": {"key": "value"}}
context.results = {
"list": context.template_instance._apply_template_vars("{{ items }}", test_params),
"dict": context.template_instance._apply_template_vars("{{ config }}", test_params),
"malformed": context.template_instance._apply_template_vars("[invalid json", test_params),
}
except Exception as e:
context.error = e
@then("JSON structures should be parsed correctly")
def step_verify_json_parsing(context):
"""Verify JSON structures are parsed correctly."""
assert context.error is None
assert isinstance(context.results["list"], list)
assert isinstance(context.results["dict"], dict)
@then("malformed JSON should fall back to string")
def step_verify_json_fallback(context):
"""Verify malformed JSON falls back to string."""
assert isinstance(context.results["malformed"], str)
# BaseTemplate _apply_template_vars tests - number parsing
@when("I apply template variables that result in numbers")
def step_apply_number_templates(context):
"""Apply template variables that result in numbers."""
try:
test_params = {"int_val": 42, "float_val": 3.14}
context.results = {
"integer": context.template_instance._apply_template_vars("{{ int_val }}", test_params),
"float": context.template_instance._apply_template_vars("{{ float_val }}", test_params),
"rendered_int": context.template_instance._apply_template_vars("{{ 42 }}", test_params),
"rendered_float": context.template_instance._apply_template_vars("{{ 3.14 }}", test_params),
"string_int": context.template_instance._apply_template_vars("42", test_params),
"string_float": context.template_instance._apply_template_vars("3.14", test_params),
}
except Exception as e:
context.error = e
@then("integers and floats should be parsed correctly")
def step_verify_number_parsing(context):
"""Verify integers and floats are parsed correctly."""
assert context.error is None
# Template-rendered numbers should convert to int/float
assert context.results["integer"] == 42
assert context.results["float"] == 3.14
assert context.results["rendered_int"] == 42
assert context.results["rendered_float"] == 3.14
# Plain number strings should remain as strings (only templated ones convert)
assert context.results["string_int"] == "42"
assert context.results["string_float"] == "3.14"
# BaseTemplate _apply_template_vars tests - dict processing
@when("I apply template variables to dictionary structures")
def step_apply_dict_templates(context):
"""Apply template variables to dictionary structures."""
try:
test_params = {"key1": "value1", "key2": "value2"}
test_dict = {
"static_key": "static_value",
"{{ key1 }}": "templated_key",
"normal_key": "{{ key2 }}",
"nested": {"inner_key": "{{ key1 }}"},
}
context.result = context.template_instance._apply_template_vars(test_dict, test_params)
except Exception as e:
context.error = e
@then("dictionary keys and values should be processed recursively")
def step_verify_dict_processing(context):
"""Verify dictionary processing."""
assert context.error is None
result = context.result
assert result["static_key"] == "static_value"
assert result["value1"] == "templated_key" # Key was templated
assert result["normal_key"] == "value2" # Value was templated
assert result["nested"]["inner_key"] == "value1" # Nested processing
@then("None values should be filtered out")
def step_verify_none_filtering(context):
"""Verify None values are filtered out."""
# This will be tested with conditional blocks
# BaseTemplate _apply_template_vars tests - conditional blocks
@given("I have a BaseTemplate instance with conditional blocks")
def step_template_conditional_blocks(context):
"""Create template with conditional blocks."""
context.template_instance = TestTemplate("test_template", TemplateType.AGENT, {})
@when("I apply template variables to conditional structures")
def step_apply_conditional_templates(context):
"""Apply template variables to conditional structures."""
try:
test_params = {"show_section": True, "hide_section": False}
# Test conditional block that should be included
conditional_true = {"{% if show_section %}": "content: included"}
# Test conditional block that should be excluded
conditional_false = {"{% if hide_section %}": "content: excluded"}
context.results = {
"included": context.template_instance._apply_template_vars(conditional_true, test_params),
"excluded": context.template_instance._apply_template_vars(conditional_false, test_params),
}
except Exception as e:
context.error = e
@then("conditional blocks should be evaluated correctly")
def step_verify_conditional_evaluation(context):
"""Verify conditional blocks are evaluated correctly."""
assert context.error is None
# The included condition should return parsed content
assert context.results["included"] is not None
@then("false conditions should return None")
def step_verify_false_conditions_none(context):
"""Verify false conditions return None."""
assert context.results["excluded"] is None
# BaseTemplate _apply_template_vars tests - list processing
@when("I apply template variables to list structures")
def step_apply_list_templates(context):
"""Apply template variables to list structures."""
try:
test_params = {"item1": "first", "item2": "second", "show": True, "hide": False}
test_list = [
"{{ item1 }}",
"{{ item2 }}",
{"{% if show %}": "included_item"},
{"{% if hide %}": "excluded_item"},
"static_item",
]
context.result = context.template_instance._apply_template_vars(test_list, test_params)
except Exception as e:
context.error = e
@then("list items should be processed recursively")
def step_verify_list_processing(context):
"""Verify list processing."""
assert context.error is None
result = context.result
assert "first" in result
assert "second" in result
assert "static_item" in result
@then("None values should be filtered from lists")
def step_verify_list_none_filtering(context):
"""Verify None values are filtered from lists."""
# None values from false conditions should be filtered out
assert None not in context.result
# BaseTemplate _apply_template_vars tests - error handling
@when("I apply template variables with invalid templates")
def step_apply_invalid_templates(context):
"""Apply template variables with invalid templates."""
try:
test_params = {"valid": "test"}
invalid_template = "{{ invalid_syntax }" # Missing closing }}
context.result = context.template_instance._apply_template_vars(invalid_template, test_params)
context.error_handled = True
except Exception as e:
context.error = e
@then("template errors should be handled gracefully")
def step_verify_error_handling(context):
"""Verify template errors are handled gracefully."""
assert hasattr(context, "error_handled")
assert context.error_handled is True
@then("original values should be returned on error")
def step_verify_original_on_error(context):
"""Verify original values are returned on error."""
assert context.result == "{{ invalid_syntax }"
# BaseTemplate _merge_params tests
@when("I merge parameter dictionaries with overrides")
def step_merge_params(context):
"""Merge parameter dictionaries with overrides."""
try:
base_params = {
"base_param": "base_value",
"override_me": "original",
"template_param": "{{ base_param }}",
}
override_params = {
"override_me": "overridden",
"new_param": "new_value",
"templated_override": "Value: {{ base_param }}",
}
context.result = context.template_instance._merge_params(base_params, override_params)
except Exception as e:
context.error = e
@then("parameters should be merged correctly")
def step_verify_params_merge(context):
"""Verify parameters are merged correctly."""
assert context.error is None
result = context.result
assert result["base_param"] == "base_value"
assert result["override_me"] == "overridden"
assert result["new_param"] == "new_value"
@then("override values should be template-processed")
def step_verify_override_template_processing(context):
"""Verify override values are template-processed."""
assert context.result["templated_override"] == "Value: base_value"
# Error conditions and edge cases
@given("I have various edge case scenarios")
def step_edge_case_scenarios(context):
"""Set up edge case scenarios."""
context.edge_cases = {
"empty_template": TestTemplate("empty", TemplateType.STREAM, {}),
"no_params_def": TestTemplate("no_params", TemplateType.GRAPH, {"config": "test"}),
}
@when("I test error conditions")
def step_test_error_conditions(context):
"""Test various error conditions."""
context.errors = {}
# Test ComponentReference resolve with missing context method
try:
ref = ComponentReference("agent", "test")
mock_context = Mock()
mock_context.resolve_reference.side_effect = ValueError("Test error")
ref.resolve(mock_context)
except ValueError as e:
context.errors["resolve_error"] = e
@then("appropriate errors should be raised")
def step_verify_appropriate_errors(context):
"""Verify appropriate errors are raised."""
assert "resolve_error" in context.errors
assert isinstance(context.errors["resolve_error"], ValueError)
@then("edge cases should be handled correctly")
def step_verify_edge_cases(context):
"""Verify edge cases are handled correctly."""
# Empty template should work
empty_template = context.edge_cases["empty_template"]
assert empty_template.parameters == {}
# Template without parameters section should work
no_params = context.edge_cases["no_params_def"]
assert no_params.parameters == {}