开发者

Perl: mocking -d -f and friends. How to put them into CORE::GLOBAL

The CORE documentation has shown me how to merrily mock various built Perl functions. However, I'm not really sure how to replace '-d' &c. with my methods. So this is really just a question on how do i replace a function with a dash in it in CORE::GLOBAL.

A manual reference would be nice.

package Testing::MockDir;

use strict;
use warnings;
use Exporter();
use Symbol 'qualify_to_ref';

*import = \&Exporter::import;

our @EXPORT_OK = qw(SetMockDir UnsetMockDir);

our %EXPORT_TAGS = (
    'all' => \@EXPORT_OK,
);

my %path2List = ();
my %handle2List = ();

BEGIN {
    *CORE::GLOBAL::opendir = \&Testing::MockDir::opendir;
    *CORE::GLOBAL::readdir = \&Testing::MockDir::readdir;
    *CORE::GLOBAL::closedir = \&Testing::MockDir::closedir;

    ######################### the "-" is really the problem here
    *CORE::GLOBAL::-d = \&Testing::MockDir::mock_d; # This does not work <<<<<
}

sub mock_d ($) {
    die 'It worked';
}

sub SetMockDir {
    my ($path, @files) = @_;
    $path2List{$path} = [@files];
}

sub UnsetMockDir {
    my ($path) = @_;
    delete $path2List{$path};
}

sub opendir (*$) {
    my $handle = qualify_to_ref(shift, caller);
    my ($path) = @_;
    return CORE::opendir($handle, $path) unless defined $path2List{$path};
    $handle2List{$handle} = $path2List{$path};
    return 1;
}

sub readdir (*) {
    my $handle = qualify_to_ref(shift, caller);
    return CORE::readdir($handle) unless defined $handle2List{$handle};
    return shift @{$handle2List{$handle}} unless wantarray;

    my @files = @{$handle2List{$handle}};
    $handle2List{$handle} = [];
    re开发者_如何学Cturn @files;
}

sub closedir (*) {
    my $handle = qualify_to_ref(shift, caller);
    return CORE::closedir($handle) unless defined $handle2List{$handle};
    delete $handle2List{$handle};
    return 1;
}

1;


CORE::GLOBAL doesn't work on things without prototypes. The only way I can think to do it is rewrite the opcode tree... which is not for the faint of heart. You could pull it off with a combination of B::Utils and B::Generate and a lot of experimentation.

Simplest thing to do would be to use File::Temp to make a temporary directory structure to your liking.


It may not be possible. The perlsub section on Overriding Built-in Functions is vague about which functions can be overridden. "Many" can, "some" can't, but aside from a handful of examples there's no definitive list.

Normally, I'd try this:

{
    no strict 'refs';
    *{'CORE::GLOBAL::-d'} = \&Testing::MockDir::mock_d;
}

which isn't a syntax error, but doesn't have the effect of overriding -d.


Thanks all for your answers.

What I wound up doing is, on a per module/test target basis, I factored out the code with the "-d" into it into it's own function. Like so...

# Because I cannot mock -d directly
sub dirExists {
    return -d shift;
}

Then I can replace this function in the test module with like

my $doesDirExist = 1;
*MyModule::dirExists   = \&main::mock_dirExists;

sub mock_dirExists {
    return $doesDirExist;
}

It's pretty ugly but i didn't want to get hung up on this too long and it works well enuf for my purposes


The problem is that your app is dependent on hard-coded file specifications. You should parameterize the file specifications; then you don't have to mock anymore, you can just use Directory::Scratch or something.


You could go the source filter route:

package Testing::MockDir;
use Filter::Simple;
FILTER {   s/\s+\-d (\S+)/ Testing::MockDir::filetest 'd',$1/g };
sub filetest {
  my ($test, $file) = @_;
  print "Mocking  -$test $file\n";
  return 1;
}

(This sample code isn't very robust. For example it won't translate -d$dir or -d "dirname with spaces", but you can beef it up until it meets the needs of your target code).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜