forked from HAL9000/cleveragents-core
1175 lines
41 KiB
Python
1175 lines
41 KiB
Python
"""
|
|
Step definitions for templates base module testing.
|
|
"""
|
|
|
|
import copy
|
|
import json
|
|
from typing import Any
|
|
from typing import Dict
|
|
from unittest.mock import Mock
|
|
|
|
from behave import given
|
|
from behave import then
|
|
from behave import when
|
|
|
|
from cleveragents.templates.base import BaseTemplate
|
|
from cleveragents.templates.base import ComponentReference
|
|
from cleveragents.templates.base import InstantiationContext
|
|
from cleveragents.templates.base import TemplateParameter
|
|
from cleveragents.templates.base import 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 == {}
|