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 )