Acme-Claude-Shell

 view release on metacpan or  search on metacpan

t/02-hooks.t  view on Meta::CPAN

#!/usr/bin/env perl
use 5.020;
use strict;
use warnings;
use Test::More;

# Test the Hooks module functionality

use_ok('Acme::Claude::Shell::Hooks', 'safety_hooks');
use_ok('Claude::Agent::Hook::Matcher');
use_ok('Claude::Agent::Hook::Result');

# Create a mock session object for testing
package MockSession;
sub new {
    my ($class, %args) = @_;
    return bless {
        working_dir => $args{working_dir} // '.',
        colorful    => $args{colorful} // 0,
        safe_mode   => $args{safe_mode} // 1,
        verbose     => $args{verbose} // 0,
        audit_log   => $args{audit_log} // 0,
        _history    => [],
        _spinner    => undef,
    }, $class;
}
sub working_dir { $_[0]->{working_dir} }
sub colorful { $_[0]->{colorful} }
sub safe_mode { $_[0]->{safe_mode} }
sub _history { $_[0]->{_history} }
sub _spinner {
    my $self = shift;
    if (@_) { $self->{_spinner} = shift }
    return $self->{_spinner};
}
sub can {
    my ($self, $method) = @_;
    return $self->SUPER::can($method) || ($method eq '_spinner' ? 1 : 0);
}

package main;

# Create mock session
my $session = MockSession->new(
    colorful  => 0,
    safe_mode => 1,
    verbose   => 0,
);

# Get hooks
my $hooks = safety_hooks($session);
ok($hooks, 'safety_hooks returns hooks');
is(ref($hooks), 'HASH', 'safety_hooks returns hashref');

# Check expected hook types exist
ok(exists $hooks->{PreToolUse}, 'PreToolUse hooks exist');
ok(exists $hooks->{PostToolUse}, 'PostToolUse hooks exist');
ok(exists $hooks->{PostToolUseFailure}, 'PostToolUseFailure hooks exist');
ok(exists $hooks->{Stop}, 'Stop hooks exist');
ok(exists $hooks->{Notification}, 'Notification hooks exist');

# Check each hook type has matchers
for my $hook_type (qw(PreToolUse PostToolUse PostToolUseFailure Stop Notification)) {
    ok(ref($hooks->{$hook_type}) eq 'ARRAY', "$hook_type is arrayref");
    ok(scalar(@{$hooks->{$hook_type}}) > 0, "$hook_type has matchers");

    for my $matcher (@{$hooks->{$hook_type}}) {
        isa_ok($matcher, 'Claude::Agent::Hook::Matcher', "$hook_type matcher");
        ok($matcher->can('matches'), "Matcher has matches method");
        ok($matcher->can('run_hooks'), "Matcher has run_hooks method");
    }
}

# Test PreToolUse matcher pattern
subtest 'PreToolUse matcher' => sub {
    plan tests => 4;

    my $matcher = $hooks->{PreToolUse}[0];

    # Should match shell-tools tools
    ok($matcher->matches('mcp__shell-tools__execute_command'), 'Matches execute_command');
    ok($matcher->matches('mcp__shell-tools__read_file'), 'Matches read_file');
    ok($matcher->matches('mcp__shell-tools__list_directory'), 'Matches list_directory');

    # Should not match other tools
    ok(!$matcher->matches('some_other_tool'), 'Does not match other tools');
};

# Test PostToolUse matcher pattern (only execute_command)
subtest 'PostToolUse matcher' => sub {
    plan tests => 3;

    my $matcher = $hooks->{PostToolUse}[0];

    # Should match execute_command
    ok($matcher->matches('mcp__shell-tools__execute_command'), 'Matches execute_command');

    # Should not match other shell-tools



( run in 0.521 second using v1.01-cache-2.11-cpan-ceb78f64989 )