Claude-Agent
view release on metacpan or search on metacpan
t/11-extended-coverage.t view on Meta::CPAN
# Standard MCP tool
$tool = Claude::Agent::Content::ToolUse->new(
id => 'id-2',
name => 'mcp__filesystem__read_file',
input => { path => '/tmp/test' },
);
ok($tool->is_mcp_tool, 'mcp__filesystem__read_file is MCP tool');
is($tool->mcp_server, 'filesystem', 'mcp_server extracted');
is($tool->mcp_tool_name, 'read_file', 'mcp_tool_name extracted');
# MCP tool with dashes in names
$tool = Claude::Agent::Content::ToolUse->new(
id => 'id-3',
name => 'mcp__my-server__my-tool',
input => {},
);
ok($tool->is_mcp_tool, 'mcp__my-server__my-tool is MCP tool');
is($tool->mcp_server, 'my-server', 'mcp_server with dashes');
is($tool->mcp_tool_name, 'my-tool', 'mcp_tool_name with dashes');
# Edge case: tool name starts with mcp but not MCP format
$tool = Claude::Agent::Content::ToolUse->new(
id => 'id-4',
name => 'mcp_not_a_real_mcp_tool', # Single underscores
input => {},
);
ok(!$tool->is_mcp_tool, 'mcp_not_a_real_mcp_tool is not MCP (single underscores)');
# Edge case: partial mcp prefix
$tool = Claude::Agent::Content::ToolUse->new(
id => 'id-5',
name => 'mcprefix__server__tool',
input => {},
);
ok(!$tool->is_mcp_tool, 'mcprefix__ is not MCP prefix');
};
# =============================================================================
# Tests for Deny permission result
# =============================================================================
subtest 'Deny permission edge cases' => sub {
# Deny with minimal args
my $deny = Claude::Agent::Permission->deny(
message => 'Access denied',
);
is($deny->behavior, 'deny', 'deny behavior');
is($deny->message, 'Access denied', 'deny message');
ok(!$deny->interrupt, 'deny without interrupt defaults to false');
# Deny with explicit false interrupt
$deny = Claude::Agent::Permission->deny(
message => 'Denied but continue',
interrupt => 0,
);
ok(!$deny->interrupt, 'deny with interrupt => 0');
# Deny with true interrupt
$deny = Claude::Agent::Permission->deny(
message => 'Blocked!',
interrupt => 1,
);
ok($deny->interrupt, 'deny with interrupt => 1');
# Test to_hash JSON boolean encoding
my $hash = $deny->to_hash;
ok(ref($hash->{interrupt}), 'interrupt is a reference (JSON boolean)');
ok(${$hash->{interrupt}}, 'interrupt JSON true value');
$deny = Claude::Agent::Permission->deny(
message => 'No interrupt',
interrupt => 0,
);
$hash = $deny->to_hash;
ok(ref($hash->{interrupt}), 'interrupt false is still a reference');
ok(!${$hash->{interrupt}}, 'interrupt JSON false value');
};
# =============================================================================
# Tests for MCP ToolDefinition execution
# =============================================================================
subtest 'ToolDefinition error handling' => sub {
use Claude::Agent::MCP;
# Tool that throws exception
my $err_tool = Claude::Agent::MCP::ToolDefinition->new(
name => 'error_tool',
description => 'Always throws',
input_schema => {},
handler => sub { die "Intentional test error\n" },
);
# execute() now returns a Future
my $future = $err_tool->execute({});
isa_ok($future, 'Future', 'execute returns a Future');
my $result = $future->get;
ok($result->{is_error}, 'error tool sets is_error');
like($result->{content}[0]{text}, qr/Error executing tool/, 'error message present');
like($result->{content}[0]{text}, qr/error_tool/, 'error message includes tool name');
# Tool returning explicit is_error
my $explicit_err = Claude::Agent::MCP::ToolDefinition->new(
name => 'explicit_error',
description => 'Returns explicit error',
input_schema => {},
handler => sub {
return {
content => [{ type => 'text', text => 'Custom error message' }],
is_error => 1,
};
},
);
$future = $explicit_err->execute({});
$result = $future->get;
ok($result->{is_error}, 'explicit is_error preserved');
is($result->{content}[0]{text}, 'Custom error message', 'custom error message preserved');
# Tool returning success
( run in 0.765 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )