Files
Dmytro Struk 57da1bcfeb Python: Fixed declarative samples (#4051)
* Updated declarative kind mapping

* Fixed required property handling

* Updated inline yaml sample

* Fixed remaining declarative samples

* Added lazy initialization for PowerFx engine

* Small fix
2026-02-18 23:08:31 +00:00

1196 lines
42 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
"""Tests for MAML model classes."""
import sys
import pytest
from agent_framework_declarative._models import (
AgentDefinition,
AgentManifest,
AnonymousConnection,
ApiKeyConnection,
ArrayProperty,
Binding,
CodeInterpreterTool,
Connection,
CustomTool,
EnvironmentVariable,
FileSearchTool,
Format,
FunctionTool,
McpServerApprovalMode,
McpServerToolAlwaysRequireApprovalMode,
McpServerToolNeverRequireApprovalMode,
McpServerToolSpecifyApprovalMode,
McpTool,
Model,
ModelOptions,
ModelResource,
ObjectProperty,
OpenApiTool,
Parser,
PromptAgent,
Property,
PropertySchema,
ProtocolVersionRecord,
ReferenceConnection,
RemoteConnection,
Resource,
Template,
ToolResource,
WebSearchTool,
_safe_mode_context,
_try_powerfx_eval,
)
pytestmark = pytest.mark.skipif(sys.version_info >= (3, 14), reason="Skipping on Python 3.14+")
class TestBinding:
"""Tests for Binding class."""
def test_binding_creation(self):
binding = Binding(name="arg1", input="value1")
assert binding.name == "arg1"
assert binding.input == "value1"
def test_binding_from_dict(self):
data = {"name": "arg1", "input": "value1"}
binding = Binding.from_dict(data)
assert binding.name == "arg1"
assert binding.input == "value1"
def test_binding_to_dict(self):
binding = Binding(name="arg1", input="value1")
result = binding.to_dict()
assert result["name"] == "arg1"
assert result["input"] == "value1"
class TestProperty:
"""Tests for Property class."""
def test_property_creation(self):
prop = Property(
name="test_prop",
kind="string",
description="A test property",
required=True,
default="default_value",
example="example_value",
enum=["val1", "val2"],
)
assert prop.name == "test_prop"
assert prop.kind == "string"
assert prop.description == "A test property"
assert prop.required is True
assert prop.default == "default_value"
assert prop.example == "example_value"
assert prop.enum == ["val1", "val2"]
def test_property_from_dict(self):
data = {
"name": "test_prop",
"kind": "string",
"description": "A test property",
"required": True,
}
prop = Property.from_dict(data)
assert prop.name == "test_prop"
assert prop.kind == "string"
assert prop.description == "A test property"
assert prop.required is True
def test_property_from_dict_type_maps_to_kind(self):
"""Test that 'type' field in YAML is mapped to 'kind' internally."""
data = {
"name": "test_prop",
"type": "string",
"description": "A test property",
"required": True,
}
prop = Property.from_dict(data)
assert prop.name == "test_prop"
assert prop.kind == "string"
def test_property_from_dict_kind_takes_precedence_over_type(self):
"""Test that 'kind' takes precedence when both 'type' and 'kind' are present."""
data = {
"name": "test_prop",
"type": "integer",
"kind": "string",
}
prop = Property.from_dict(data)
assert prop.kind == "string"
def test_property_from_dict_type_dispatches_to_array(self):
"""Test that 'type: array' correctly dispatches to ArrayProperty."""
data = {
"name": "test_array",
"type": "array",
"items": {"type": "string"},
}
prop = Property.from_dict(data)
assert isinstance(prop, ArrayProperty)
assert prop.kind == "array"
def test_property_from_dict_type_dispatches_to_object(self):
"""Test that 'type: object' correctly dispatches to ObjectProperty."""
data = {
"name": "test_object",
"type": "object",
"properties": {"field": {"type": "string"}},
}
prop = Property.from_dict(data)
assert isinstance(prop, ObjectProperty)
assert prop.kind == "object"
class TestArrayProperty:
"""Tests for ArrayProperty class."""
def test_array_property_creation(self):
items = Property(name="item", kind="string")
array_prop = ArrayProperty(name="test_array", kind="array", items=items, required=True)
assert array_prop.name == "test_array"
assert array_prop.kind == "array"
assert array_prop.items.name == "item"
assert array_prop.required is True
def test_array_property_from_dict(self):
data = {
"name": "test_array",
"kind": "array",
"items": {"name": "item", "kind": "string"},
"required": True,
}
array_prop = ArrayProperty.from_dict(data)
assert array_prop.name == "test_array"
assert array_prop.kind == "array"
assert isinstance(array_prop.items, Property)
assert array_prop.items.name == "item"
class TestObjectProperty:
"""Tests for ObjectProperty class."""
def test_object_property_creation(self):
props = [
Property(name="prop1", kind="string"),
Property(name="prop2", kind="integer"),
]
obj_prop = ObjectProperty(name="test_object", kind="object", properties=props, required=True)
assert obj_prop.name == "test_object"
assert obj_prop.kind == "object"
assert len(obj_prop.properties) == 2
assert obj_prop.properties[0].name == "prop1"
def test_object_property_from_dict(self):
data = {
"name": "test_object",
"kind": "object",
"properties": [
{"name": "prop1", "kind": "string"},
{"name": "prop2", "kind": "integer"},
],
"required": True,
}
obj_prop = ObjectProperty.from_dict(data)
assert obj_prop.name == "test_object"
assert obj_prop.kind == "object"
assert len(obj_prop.properties) == 2
assert all(isinstance(p, Property) for p in obj_prop.properties)
def test_object_property_with_dict_properties(self):
"""Test ObjectProperty with dict format for properties (MAML YAML dict syntax)."""
data = {
"name": "person",
"kind": "object",
"properties": {
"name": {"kind": "string", "required": True},
"email": {"kind": "string"},
"age": {"kind": "integer"},
},
}
obj_prop = ObjectProperty.from_dict(data)
assert obj_prop.name == "person"
assert obj_prop.kind == "object"
assert len(obj_prop.properties) == 3
# Check that all properties were converted correctly
prop_names = {p.name for p in obj_prop.properties}
assert prop_names == {"name", "email", "age"}
# Check specific property
name_prop = next(p for p in obj_prop.properties if p.name == "name")
assert name_prop.kind == "string"
assert name_prop.required is True
class TestPropertySchema:
"""Tests for PropertySchema class."""
def test_property_schema_creation(self):
props = [Property(name="prop1", kind="string")]
schema = PropertySchema(properties=props, strict=True)
assert schema.strict is True
assert len(schema.properties) == 1
def test_property_schema_from_dict(self):
data = {
"strict": False,
"properties": [{"name": "prop1", "kind": "string"}],
}
schema = PropertySchema.from_dict(data)
assert schema.strict is False
assert len(schema.properties) == 1
# Properties are properly converted to Property instances
assert isinstance(schema.properties[0], Property)
assert schema.properties[0].name == "prop1"
assert schema.properties[0].kind == "string"
def test_property_schema_with_dict_properties(self):
"""Test PropertySchema with dict format for properties (MAML YAML dict syntax)."""
data = {
"strict": True,
"properties": {
"firstName": {"kind": "string", "description": "First name"},
"lastName": {"kind": "string", "description": "Last name"},
"age": {"kind": "integer", "required": True},
},
}
schema = PropertySchema.from_dict(data)
assert schema.strict is True
assert len(schema.properties) == 3
# Check that all properties were converted correctly
prop_names = {p.name for p in schema.properties}
assert prop_names == {"firstName", "lastName", "age"}
# Check specific property details
age_prop = next(p for p in schema.properties if p.name == "age")
assert age_prop.kind == "integer"
assert age_prop.required is True
def test_property_schema_with_type_field_produces_correct_json_schema(self):
"""Test that PropertySchema with 'type' fields (YAML spec format) produces valid JSON schema."""
data = {
"properties": {
"language": {"type": "string", "required": True, "description": "The language."},
"answer": {"type": "string", "required": False, "description": "The answer."},
},
}
schema = PropertySchema.from_dict(data)
assert len(schema.properties) == 2
lang_prop = next(p for p in schema.properties if p.name == "language")
assert lang_prop.kind == "string"
json_schema = schema.to_json_schema()
assert json_schema["type"] == "object"
assert json_schema["properties"]["language"]["type"] == "string"
assert json_schema["properties"]["answer"]["type"] == "string"
# required is a top-level array, not a per-property boolean
assert json_schema["required"] == ["language"]
assert "required" not in json_schema["properties"]["language"]
assert "required" not in json_schema["properties"]["answer"]
class TestConnection:
"""Tests for Connection base class."""
def test_connection_creation(self):
conn = Connection(kind="base")
assert conn.kind == "base"
def test_connection_from_dict(self):
data = {"kind": "base"}
conn = Connection.from_dict(data)
assert conn.kind == "base"
class TestReferenceConnection:
"""Tests for ReferenceConnection class."""
def test_reference_connection_creation(self):
conn = ReferenceConnection(name="my-connection", target="target-connection")
assert conn.kind == "reference"
assert conn.name == "my-connection"
assert conn.target == "target-connection"
def test_reference_connection_from_dict(self):
data = {"kind": "reference", "name": "my-connection", "target": "target-connection"}
conn = ReferenceConnection.from_dict(data)
assert conn.kind == "reference"
assert conn.name == "my-connection"
assert conn.target == "target-connection"
class TestRemoteConnection:
"""Tests for RemoteConnection class."""
def test_remote_connection_creation(self):
conn = RemoteConnection(name="my-remote", endpoint="https://api.example.com")
assert conn.kind == "remote"
assert conn.endpoint == "https://api.example.com"
def test_remote_connection_from_dict(self):
data = {"kind": "remote", "endpoint": "https://api.example.com"}
conn = RemoteConnection.from_dict(data)
assert conn.kind == "remote"
assert conn.endpoint == "https://api.example.com"
class TestApiKeyConnection:
"""Tests for ApiKeyConnection class."""
def test_api_key_connection_creation(self):
conn = ApiKeyConnection(apiKey="secret-key", endpoint="https://api.example.com")
assert conn.kind == "key"
assert conn.apiKey == "secret-key"
assert conn.endpoint == "https://api.example.com"
def test_api_key_connection_from_dict(self):
data = {"kind": "key", "apiKey": "secret-key", "endpoint": "https://api.example.com"}
conn = ApiKeyConnection.from_dict(data)
assert conn.kind == "key"
assert conn.apiKey == "secret-key"
class TestAnonymousConnection:
"""Tests for AnonymousConnection class."""
def test_anonymous_connection_creation(self):
conn = AnonymousConnection(endpoint="https://api.example.com")
assert conn.kind == "anonymous"
assert conn.endpoint == "https://api.example.com"
def test_anonymous_connection_from_dict(self):
data = {"kind": "anonymous", "endpoint": "https://api.example.com"}
conn = AnonymousConnection.from_dict(data)
assert conn.kind == "anonymous"
assert conn.endpoint == "https://api.example.com"
class TestModelOptions:
"""Tests for ModelOptions class."""
def test_model_options_creation(self):
options = ModelOptions(temperature=0.7, maxOutputTokens=1000, topP=0.9)
assert options.temperature == 0.7
assert options.maxOutputTokens == 1000
assert options.topP == 0.9
def test_model_options_from_dict(self):
data = {"temperature": 0.7, "maxOutputTokens": 1000, "topP": 0.9}
options = ModelOptions.from_dict(data)
assert options.temperature == 0.7
assert options.maxOutputTokens == 1000
assert options.topP == 0.9
class TestModel:
"""Tests for Model class."""
def test_model_creation(self):
model = Model(id="gpt-4", provider="openai")
assert model.id == "gpt-4"
assert model.provider == "openai"
def test_model_from_dict(self):
data = {"id": "gpt-4", "provider": "openai"}
model = Model.from_dict(data)
assert model.id == "gpt-4"
assert model.provider == "openai"
def test_model_with_connection(self):
data = {
"id": "gpt-4",
"connection": {"kind": "reference", "name": "my-connection"},
}
model = Model.from_dict(data)
assert model.id == "gpt-4"
assert model.connection.kind == "reference"
class TestFormat:
"""Tests for Format class."""
def test_format_creation(self):
fmt = Format(kind="json", strict=True, options={"type": "object"})
assert fmt.kind == "json"
assert fmt.strict is True
assert fmt.options == {"type": "object"}
def test_format_from_dict(self):
data = {"kind": "json", "strict": False, "options": {"type": "object"}}
fmt = Format.from_dict(data)
assert fmt.kind == "json"
assert fmt.strict is False
class TestParser:
"""Tests for Parser class."""
def test_parser_creation(self):
parser = Parser(kind="json", options={"strict": True})
assert parser.kind == "json"
assert parser.options == {"strict": True}
def test_parser_from_dict(self):
data = {"kind": "json", "options": {"strict": True}}
parser = Parser.from_dict(data)
assert parser.kind == "json"
assert parser.options == {"strict": True}
class TestTemplate:
"""Tests for Template class."""
def test_template_creation(self):
template = Template(
format=Format(kind="text"),
parser=Parser(kind="text"),
)
assert isinstance(template.format, Format)
assert isinstance(template.parser, Parser)
def test_template_from_dict(self):
data = {
"format": {"kind": "text"},
"parser": {"kind": "text"},
}
template = Template.from_dict(data)
assert isinstance(template.format, Format)
assert isinstance(template.parser, Parser)
class TestAgentDefinition:
"""Tests for AgentDefinition class."""
def test_agent_definition_creation(self):
agent = AgentDefinition(
name="test-agent",
description="A test agent",
)
assert agent.name == "test-agent"
assert agent.description == "A test agent"
def test_agent_definition_from_dict(self):
data = {
"name": "test-agent",
"description": "A test agent",
}
agent = AgentDefinition.from_dict(data)
assert agent.name == "test-agent"
assert agent.description == "A test agent"
class TestFunctionTool:
"""Tests for FunctionTool class."""
def test_function_tool_creation(self):
tool = FunctionTool(
name="my_function",
description="A test function",
kind="function",
)
assert tool.name == "my_function"
assert tool.kind == "function"
def test_function_tool_from_dict(self):
data = {
"name": "my_function",
"description": "A test function",
"kind": "function",
"strict": False,
}
tool = FunctionTool.from_dict(data)
assert tool.name == "my_function"
assert tool.kind == "function"
def test_function_tool_with_dict_bindings(self):
"""Test FunctionTool with dict format for bindings (MAML YAML dict syntax)."""
data = {
"name": "calculate",
"kind": "function",
"description": "Calculate something",
"bindings": {
"x": "input.x",
"y": "input.y",
"operation": "input.op",
},
}
tool = FunctionTool.from_dict(data)
assert tool.name == "calculate"
assert len(tool.bindings) == 3
# Check that all bindings were converted correctly
binding_names = {b.name for b in tool.bindings}
assert binding_names == {"x", "y", "operation"}
# Check specific binding
x_binding = next(b for b in tool.bindings if b.name == "x")
assert x_binding.input == "input.x"
class TestCustomTool:
"""Tests for CustomTool class."""
def test_custom_tool_creation(self):
tool = CustomTool(
name="custom_tool",
description="A custom tool",
kind="custom",
options={"endpoint": "https://tool.example.com"},
)
assert tool.name == "custom_tool"
assert tool.kind == "custom"
assert tool.options == {"endpoint": "https://tool.example.com"}
def test_custom_tool_from_dict(self):
data = {
"name": "custom_tool",
"description": "A custom tool",
"kind": "custom",
"options": {"endpoint": "https://tool.example.com"},
}
tool = CustomTool.from_dict(data)
assert tool.name == "custom_tool"
assert tool.kind == "custom"
class TestWebSearchTool:
"""Tests for WebSearchTool class."""
def test_web_search_tool_creation(self):
tool = WebSearchTool(
name="web_search",
description="Search the web",
kind="web_search",
options={"maxResults": 10},
)
assert tool.name == "web_search"
assert tool.kind == "web_search"
assert tool.options == {"maxResults": 10}
def test_web_search_tool_from_dict(self):
data = {
"name": "web_search",
"description": "Search the web",
"kind": "web_search",
"options": {"maxResults": 10},
}
tool = WebSearchTool.from_dict(data)
assert tool.name == "web_search"
assert tool.kind == "web_search"
assert tool.options == {"maxResults": 10}
class TestFileSearchTool:
"""Tests for FileSearchTool class."""
def test_file_search_tool_creation(self):
tool = FileSearchTool(
name="file_search",
description="Search files",
kind="file_search",
vectorStoreIds=["vs1", "vs2"],
)
assert tool.name == "file_search"
assert tool.kind == "file_search"
assert tool.vectorStoreIds == ["vs1", "vs2"]
def test_file_search_tool_from_dict(self):
data = {
"name": "file_search",
"description": "Search files",
"kind": "file_search",
"vectorStoreIds": ["vs1", "vs2"],
}
tool = FileSearchTool.from_dict(data)
assert tool.name == "file_search"
assert tool.kind == "file_search"
assert tool.vectorStoreIds == ["vs1", "vs2"]
class TestMcpServerApprovalMode:
"""Tests for MCP Server Approval Mode classes."""
def test_always_approval_mode(self):
mode = McpServerToolAlwaysRequireApprovalMode()
assert mode.kind == "always"
def test_always_approval_mode_from_dict(self):
data = {"kind": "always"}
mode = McpServerToolAlwaysRequireApprovalMode.from_dict(data)
assert mode.kind == "always"
def test_never_approval_mode(self):
mode = McpServerToolNeverRequireApprovalMode()
assert mode.kind == "never"
def test_never_approval_mode_from_dict(self):
data = {"kind": "never"}
mode = McpServerToolNeverRequireApprovalMode.from_dict(data)
assert mode.kind == "never"
def test_specify_approval_mode(self):
mode = McpServerToolSpecifyApprovalMode(
alwaysRequireApprovalTools=["tool1"],
neverRequireApprovalTools=["tool2"],
)
assert mode.kind == "specify"
assert mode.alwaysRequireApprovalTools == ["tool1"]
assert mode.neverRequireApprovalTools == ["tool2"]
def test_specify_approval_mode_from_dict(self):
data = {
"kind": "specify",
"alwaysRequireApprovalTools": ["tool1"],
"neverRequireApprovalTools": ["tool2"],
}
mode = McpServerToolSpecifyApprovalMode.from_dict(data)
assert mode.kind == "specify"
assert mode.alwaysRequireApprovalTools == ["tool1"]
assert mode.neverRequireApprovalTools == ["tool2"]
class TestMcpTool:
"""Tests for McpTool class."""
def test_mcp_tool_creation(self):
tool = McpTool(
name="mcp_tool",
description="An MCP tool",
kind="mcp",
serverName="test-server",
)
assert tool.name == "mcp_tool"
assert tool.kind == "mcp"
assert tool.serverName == "test-server"
def test_mcp_tool_from_dict(self):
data = {
"name": "mcp_tool",
"description": "An MCP tool",
"kind": "mcp",
"serverName": "test-server",
"approvalMode": {"kind": "always"},
}
tool = McpTool.from_dict(data)
assert tool.name == "mcp_tool"
assert tool.kind == "mcp"
assert isinstance(tool.approvalMode, McpServerApprovalMode)
def test_mcp_tool_with_simplified_approval_mode(self):
"""Test McpTool with simplified string format for approvalMode."""
# Test simplified string format: approvalMode: "always"
data = {
"name": "mcp_tool",
"description": "An MCP tool",
"kind": "mcp",
"serverName": "test-server",
"approvalMode": "always",
}
tool = McpTool.from_dict(data)
assert tool.name == "mcp_tool"
assert tool.kind == "mcp"
assert isinstance(tool.approvalMode, McpServerApprovalMode)
assert tool.approvalMode.kind == "always"
def test_mcp_tool_approval_mode_equivalence(self):
"""Test that simplified and full format produce equivalent results."""
# Simplified format
data_simplified = {
"name": "mcp_tool",
"kind": "mcp",
"approvalMode": "never",
}
tool_simplified = McpTool.from_dict(data_simplified)
# Full format
data_full = {
"name": "mcp_tool",
"kind": "mcp",
"approvalMode": {"kind": "never"},
}
tool_full = McpTool.from_dict(data_full)
# Both should produce the same result
assert tool_simplified.approvalMode.kind == tool_full.approvalMode.kind
assert tool_simplified.approvalMode.kind == "never"
class TestOpenApiTool:
"""Tests for OpenApiTool class."""
def test_openapi_tool_creation(self):
tool = OpenApiTool(
name="openapi_tool",
description="An OpenAPI tool",
kind="openapi",
specification="https://api.example.com/openapi.json",
)
assert tool.name == "openapi_tool"
assert tool.kind == "openapi"
assert tool.specification == "https://api.example.com/openapi.json"
def test_openapi_tool_from_dict(self):
data = {
"name": "openapi_tool",
"description": "An OpenAPI tool",
"kind": "openapi",
"specification": "https://api.example.com/openapi.json",
}
tool = OpenApiTool.from_dict(data)
assert tool.name == "openapi_tool"
assert tool.kind == "openapi"
class TestCodeInterpreterTool:
"""Tests for CodeInterpreterTool class."""
def test_code_interpreter_tool_creation(self):
tool = CodeInterpreterTool(
name="code_interpreter",
description="Execute code",
kind="code_interpreter",
fileIds=["file1", "file2"],
)
assert tool.name == "code_interpreter"
assert tool.kind == "code_interpreter"
assert tool.fileIds == ["file1", "file2"]
def test_code_interpreter_tool_from_dict(self):
data = {
"name": "code_interpreter",
"description": "Execute code",
"kind": "code_interpreter",
"fileIds": ["file1", "file2"],
}
tool = CodeInterpreterTool.from_dict(data)
assert tool.name == "code_interpreter"
assert tool.kind == "code_interpreter"
assert tool.fileIds == ["file1", "file2"]
class TestPromptAgent:
"""Tests for PromptAgent class."""
def test_prompt_agent_creation(self):
agent = PromptAgent(
name="prompt-agent",
description="A prompt-based agent",
instructions="You are a helpful assistant",
kind="Prompt",
)
assert agent.name == "prompt-agent"
assert agent.kind == "Prompt"
assert agent.instructions == "You are a helpful assistant"
def test_prompt_agent_from_dict(self):
data = {
"name": "prompt-agent",
"description": "A prompt-based agent",
"instructions": "You are a helpful assistant",
"kind": "Prompt",
"model": {"id": "gpt-4"},
}
agent = PromptAgent.from_dict(data)
assert agent.name == "prompt-agent"
assert isinstance(agent.model, Model)
assert isinstance(agent.model, Model)
def test_prompt_agent_with_tools(self):
data = {
"name": "prompt-agent",
"kind": "Prompt",
"tools": [
{"name": "search", "kind": "web_search"},
{"name": "calc", "kind": "function"},
],
}
agent = PromptAgent.from_dict(data)
assert len(agent.tools) == 2
# Tools are converted via Tool.from_dict, type depends on 'kind'
assert agent.tools[0].kind == "web_search"
assert agent.tools[1].kind == "function"
class TestResource:
"""Tests for Resource base class."""
def test_resource_creation(self):
resource = Resource(name="test-resource", kind="Resource")
assert resource.name == "test-resource"
assert resource.kind == "Resource"
def test_resource_from_dict(self):
data = {"name": "test-resource", "kind": "Resource"}
resource = Resource.from_dict(data)
assert resource.name == "test-resource"
class TestModelResource:
"""Tests for ModelResource class."""
def test_model_resource_creation(self):
resource = ModelResource(name="my-model", kind="model", id="gpt-4")
assert resource.name == "my-model"
assert resource.kind == "model"
assert resource.id == "gpt-4"
def test_model_resource_from_dict(self):
data = {
"name": "my-model",
"kind": "model",
"id": "gpt-4",
}
resource = ModelResource.from_dict(data)
assert resource.name == "my-model"
assert resource.kind == "model"
assert resource.id == "gpt-4"
class TestToolResource:
"""Tests for ToolResource class."""
def test_tool_resource_creation(self):
resource = ToolResource(name="my-tool", kind="tool", id="search-tool")
assert resource.name == "my-tool"
assert resource.kind == "tool"
assert resource.id == "search-tool"
def test_tool_resource_from_dict(self):
data = {
"name": "my-tool",
"kind": "tool",
"id": "search-tool",
}
resource = ToolResource.from_dict(data)
assert resource.name == "my-tool"
assert resource.kind == "tool"
assert resource.id == "search-tool"
class TestProtocolVersionRecord:
"""Tests for ProtocolVersionRecord class."""
def test_protocol_version_record_creation(self):
record = ProtocolVersionRecord(protocol="mcp", version="1.0.0")
assert record.protocol == "mcp"
assert record.version == "1.0.0"
def test_protocol_version_record_from_dict(self):
data = {"protocol": "mcp", "version": "1.0.0"}
record = ProtocolVersionRecord.from_dict(data)
assert record.protocol == "mcp"
assert record.version == "1.0.0"
class TestEnvironmentVariable:
"""Tests for EnvironmentVariable class."""
def test_environment_variable_creation(self):
env_var = EnvironmentVariable(name="API_KEY", value="secret123")
assert env_var.name == "API_KEY"
assert env_var.value == "secret123"
def test_environment_variable_from_dict(self):
data = {"name": "API_KEY", "value": "secret123"}
env_var = EnvironmentVariable.from_dict(data)
assert env_var.name == "API_KEY"
assert env_var.value == "secret123"
# Check if PowerFx is available
try:
from powerfx import Engine as _PfxEngine
_PfxEngine()
_powerfx_available = True
except (ImportError, RuntimeError):
_powerfx_available = False
class TestTryPowerfxEval:
"""Tests for _try_powerfx_eval function."""
def test_no_evaluation_without_equals_prefix(self):
"""Test that strings without '=' prefix are returned as-is."""
assert _try_powerfx_eval("hello") == "hello"
assert _try_powerfx_eval("test value") == "test value"
assert _try_powerfx_eval("123") == "123"
def test_none_value_returns_none(self):
"""Test that None values are returned as None."""
assert _try_powerfx_eval(None) is None
def test_empty_string_returns_empty(self):
"""Test that empty strings are returned as empty."""
assert _try_powerfx_eval("") == ""
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_simple_powerfx_expressions(self):
"""Test simple PowerFx expressions."""
from decimal import Decimal
# Simple math - returns Decimal
assert _try_powerfx_eval("=1 + 2") == Decimal("3")
assert _try_powerfx_eval("=10 * 5") == Decimal("50")
# String literals
assert _try_powerfx_eval('="hello"') == "hello"
assert _try_powerfx_eval('="test value"') == "test value"
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_env_variable_access(self, monkeypatch):
"""Test accessing environment variables using =Env.<name> pattern."""
# Set up test environment variables
monkeypatch.setenv("TEST_VAR", "test_value")
monkeypatch.setenv("API_KEY", "secret123")
monkeypatch.setenv("PORT", "8080")
# Set safe_mode=False to allow environment variable access
token = _safe_mode_context.set(False)
try:
# Test basic env access
assert _try_powerfx_eval("=Env.TEST_VAR") == "test_value"
assert _try_powerfx_eval("=Env.API_KEY") == "secret123"
assert _try_powerfx_eval("=Env.PORT") == "8080"
finally:
_safe_mode_context.reset(token)
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_env_variable_with_string_concatenation(self, monkeypatch):
"""Test env variables with string concatenation operator."""
monkeypatch.setenv("BASE_URL", "https://api.example.com")
monkeypatch.setenv("API_VERSION", "v1")
# Set safe_mode=False to allow environment variable access
token = _safe_mode_context.set(False)
try:
# Test concatenation with &
result = _try_powerfx_eval('=Env.BASE_URL & "/" & Env.API_VERSION')
assert result == "https://api.example.com/v1"
# Test concatenation with literals
result = _try_powerfx_eval('="API Key: " & Env.API_VERSION')
assert result == "API Key: v1"
finally:
_safe_mode_context.reset(token)
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_string_comparison_operators(self, monkeypatch):
"""Test PowerFx string comparison operators."""
monkeypatch.setenv("ENV_MODE", "production")
# Set safe_mode=False to allow environment variable access
token = _safe_mode_context.set(False)
try:
# Equal to - returns bool
assert _try_powerfx_eval('=Env.ENV_MODE = "production"') is True
assert _try_powerfx_eval('=Env.ENV_MODE = "development"') is False
# Not equal to - returns bool
assert _try_powerfx_eval('=Env.ENV_MODE <> "development"') is True
assert _try_powerfx_eval('=Env.ENV_MODE <> "production"') is False
finally:
_safe_mode_context.reset(token)
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_string_in_operator(self):
"""Test PowerFx 'in' operator for substring testing (case-insensitive)."""
# Substring test - case insensitive - returns bool
assert _try_powerfx_eval('="the" in "The keyboard and the monitor"') is True
assert _try_powerfx_eval('="THE" in "The keyboard and the monitor"') is True
assert _try_powerfx_eval('="xyz" in "The keyboard and the monitor"') is False
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_string_exactin_operator(self):
"""Test PowerFx 'exactin' operator for substring testing (case-sensitive)."""
# Substring test - case sensitive - returns bool
assert _try_powerfx_eval('="Windows" exactin "To display windows in the Windows operating system"') is True
assert _try_powerfx_eval('="windows" exactin "To display windows in the Windows operating system"') is True
assert _try_powerfx_eval('="WINDOWS" exactin "To display windows in the Windows operating system"') is False
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_logical_operators_with_strings(self):
"""Test PowerFx logical operators (And, Or, Not) with string comparisons."""
# And operator - returns bool
assert _try_powerfx_eval('="a" = "a" And "b" = "b"') is True
assert _try_powerfx_eval('="a" = "a" And "b" = "c"') is False
# && operator (alternative syntax) - returns bool
assert _try_powerfx_eval('="a" = "a" && "b" = "b"') is True
# Or operator - returns bool
assert _try_powerfx_eval('="a" = "b" Or "c" = "c"') is True
assert _try_powerfx_eval('="a" = "b" Or "c" = "d"') is False
# || operator (alternative syntax) - returns bool
assert _try_powerfx_eval('="a" = "b" || "c" = "c"') is True
# Not operator - returns bool
assert _try_powerfx_eval('=Not("a" = "b")') is True
assert _try_powerfx_eval('=Not("a" = "a")') is False
# ! operator (alternative syntax) - returns bool
assert _try_powerfx_eval('=!("a" = "b")') is True
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_parentheses_for_precedence(self):
"""Test using parentheses to control operator precedence."""
from decimal import Decimal
# Test arithmetic precedence - returns Decimal
assert _try_powerfx_eval("=(1 + 2) * 3") == Decimal("9")
assert _try_powerfx_eval("=1 + 2 * 3") == Decimal("7")
# Test logical precedence - returns bool
result = _try_powerfx_eval('=("a" = "a" Or "b" = "c") And "d" = "d"')
assert result is True
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_env_with_special_characters(self, monkeypatch):
"""Test env variables containing special characters in values."""
monkeypatch.setenv("URL_WITH_QUERY", "https://example.com?param=value")
monkeypatch.setenv("PATH_WITH_SPACES", "C:\\Program Files\\App")
# Set safe_mode=False to allow environment variable access
token = _safe_mode_context.set(False)
try:
result = _try_powerfx_eval("=Env.URL_WITH_QUERY")
assert result == "https://example.com?param=value"
result = _try_powerfx_eval("=Env.PATH_WITH_SPACES")
assert result == "C:\\Program Files\\App"
finally:
_safe_mode_context.reset(token)
def test_safe_mode_blocks_env_access(self, monkeypatch):
"""Test that safe_mode=True (default) blocks environment variable access."""
monkeypatch.setenv("SECRET_VAR", "secret_value")
# Set safe_mode=True (default)
token = _safe_mode_context.set(True)
try:
# When safe_mode=True, Env is not available and the expression fails,
# returning the original value
result = _try_powerfx_eval("=Env.SECRET_VAR")
assert result == "=Env.SECRET_VAR"
finally:
_safe_mode_context.reset(token)
@pytest.mark.skipif(not _powerfx_available, reason="PowerFx engine not available")
def test_safe_mode_context_isolation(self, monkeypatch):
"""Test that safe_mode context variable properly isolates env access."""
monkeypatch.setenv("TEST_VAR", "test_value")
# First, set safe_mode=True - should NOT allow env access
token = _safe_mode_context.set(True)
try:
result_safe = _try_powerfx_eval("=Env.TEST_VAR")
assert result_safe == "=Env.TEST_VAR"
# Then, set safe_mode=False - should allow env access
token2 = _safe_mode_context.set(False)
try:
result_unsafe = _try_powerfx_eval("=Env.TEST_VAR")
assert result_unsafe == "test_value"
finally:
_safe_mode_context.reset(token2)
# After reset, should block again
result_safe_again = _try_powerfx_eval("=Env.TEST_VAR")
assert result_safe_again == "=Env.TEST_VAR"
finally:
_safe_mode_context.reset(token)
class TestAgentManifest:
"""Tests for AgentManifest class."""
def test_agent_manifest_creation(self):
manifest = AgentManifest(name="my-agent-manifest", description="A test manifest")
assert manifest.name == "my-agent-manifest"
assert manifest.description == "A test manifest"
def test_agent_manifest_from_dict(self):
data = {
"name": "my-agent-manifest",
"description": "A test manifest",
}
manifest = AgentManifest.from_dict(data)
assert manifest.name == "my-agent-manifest"
def test_agent_manifest_with_resources(self):
data = {
"name": "my-agent-manifest",
"resources": [
{"name": "model1", "kind": "model", "id": "gpt-4"},
{
"name": "tool1",
"kind": "tool",
"id": "search-tool",
},
],
}
manifest = AgentManifest.from_dict(data)
assert manifest.name == "my-agent-manifest"
assert len(manifest.resources) == 2
# Resources are converted via Resource.from_dict based on their 'kind'
assert isinstance(manifest.resources[0], ModelResource)
assert isinstance(manifest.resources[1], ToolResource)
def test_agent_manifest_complete(self):
"""Test a complete agent manifest with all fields."""
data = {
"name": "complete-manifest",
"description": "A complete test manifest",
"template": {
"name": "assistant",
"kind": "Prompt",
"description": "A helpful assistant",
},
"resources": [
{"name": "model1", "kind": "model", "id": "gpt-4"},
],
}
manifest = AgentManifest.from_dict(data)
assert manifest.name == "complete-manifest"
assert isinstance(manifest.template, AgentDefinition)
assert len(manifest.resources) == 1
assert isinstance(manifest.resources[0], ModelResource)
def test_agent_manifest_with_dict_resources(self):
"""Test AgentManifest with dict format for resources (MAML YAML dict syntax)."""
data = {
"name": "manifest-with-dict-resources",
"description": "Test manifest with dict resources",
"resources": {
"gptModelDeployment": {"kind": "model", "id": "gpt-4o"},
"webSearchInstance": {"kind": "tool", "id": "web-search"},
"analyticsTool": {"kind": "tool", "id": "analytics"},
},
}
manifest = AgentManifest.from_dict(data)
assert manifest.name == "manifest-with-dict-resources"
assert len(manifest.resources) == 3
# Check that all resources were converted correctly
resource_names = {r.name for r in manifest.resources}
assert resource_names == {"gptModelDeployment", "webSearchInstance", "analyticsTool"}
# Check specific resource
gpt_resource = next(r for r in manifest.resources if r.name == "gptModelDeployment")
assert isinstance(gpt_resource, ModelResource)
assert gpt_resource.id == "gpt-4o"
web_resource = next(r for r in manifest.resources if r.name == "webSearchInstance")
assert isinstance(web_resource, ToolResource)
assert web_resource.id == "web-search"