Test-MockModule
view release on metacpan or search on metacpan
lib/Test/MockModule.pm view on Meta::CPAN
: $orig_method;
$meta->add_method($name, $arg);
} else {
TRACE("Removing mocked $sub_name from meta (was inherited or absent)");
if ($meta->can('remove_method')) {
$meta->remove_method($name);
} else {
# Mouse::Meta::Class has no remove_method; purge the
# internal methods cache entry directly so that
# get_method() no longer finds the mocked entry.
delete $meta->{methods}{$name};
}
# remove_method does not always clear the symbol table.
# When the layer captured a symbol-table orig (e.g. an earlier
# layer pushed via the symbol table while meta was immutable,
# then make_mutable purged the cached meta entry), restore that
# coderef so the method continues to resolve. When orig is
# undef the slot is cleared, so direct calls fall through to
# AUTOLOAD/parent.
_replace_sub($sub_name, $entry->{orig});
}
} else {
# Either the layer was a symbol-table push, or meta became immutable
# between mock and unmock. Fall back to the captured orig coderef.
_replace_sub($sub_name, $entry->{orig});
}
}
sub noop {
my $self = shift;
croak "noop is not allowed in strict mode. Please use define or redefine" if $self->_strict_mode();
$self->_mock($_,1) for @_;
return;
}
sub mock_all {
my ($self, %opts) = @_;
croak "mock_all is not allowed in strict mode. Please use redefine" if $self->_strict_mode();
my $package = $self->{_package};
my @subs;
{
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
@subs = sort grep {
defined &{"${package}::$_"}
} keys %{"${package}::"};
}
my $make_handler = exists $opts{handler}
? sub { $opts{handler} }
: $opts{noop}
? sub { sub { 1 } }
: sub { my $n = shift; sub { croak "$n was not mocked" } };
# Skip special Perl subs that should never be blindly mocked:
# - Phase blocks (BEGIN, END, INIT, CHECK, UNITCHECK) run at compile/exit time
# - DESTROY is called during object cleanup
# - AUTOLOAD handles missing method dispatch
# - import handles use/import semantics
# - Overload subs start with '(' (e.g. '(""', '(+', '(==')
my %_skip = map { $_ => 1 } qw(
import DESTROY BEGIN END INIT CHECK UNITCHECK AUTOLOAD
);
my @to_mock;
for my $name (@subs) {
next if $_skip{$name};
next if $name =~ /^\(/; # overload subs
next if $self->{_mocked}{$name};
push @to_mock, $name, $make_handler->("${package}::${name}");
}
return $self->_mock(@to_mock) if @to_mock;
return $self;
}
sub original {
my ($self, $name) = @_;
carp 'Please provide a valid function name' unless _valid_subname($name);
unless ($self->{_mocked}{$name}) {
# GH #42: when not mocked, return the actual sub instead of warning
my $sub_name = _full_name($self, $name);
return \&$sub_name if defined &{$sub_name};
return $self->{_package}->super($name);
}
return defined $self->{_orig}{$name} ? $self->{_orig}{$name} : $self->{_package}->super($name);
}
# Class-method counterpart to $mock->original(). Takes strings, returns
# the truly-original coderef from the per-package registry (or the live
# sub if not mocked). Lets user closures reach the original sub without
# capturing $mock -- the closure-capture pattern that drives the GH #83
# DESTROY-leak under `distinct => 1` mode.
sub original_for {
my ($class, $package, $name) = @_;
croak "Invalid package name " . (defined $package ? $package : 'undef')
unless _valid_package($package);
croak 'Please provide a valid function name'
unless _valid_subname($name);
my $sub_name = "${package}::${name}";
my $stack = $mock_subs{$sub_name};
if ($stack && @$stack) {
# Bottom-of-stack orig is the truly-original. May be undef when
# the sub was created via define() -- that is expected. Falling
# through to \&$sub_name would hand back the active mock (an
# infinite-recursion footgun for closures wrapping their orig).
return $stack->[0]{orig};
}
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
return \&$sub_name if defined &{$sub_name};
return;
}
sub unmock {
my ( $self, @names ) = @_;
carp 'Nothing to unmock' unless @names;
for my $name (@names) {
croak "Invalid subroutine name: $name" unless _valid_subname($name);
( run in 1.089 second using v1.01-cache-2.11-cpan-9581c071862 )