2009-12-23 4 views
11

La documentazione di CORE mi ha mostrato come deridere allegramente varie funzioni Perl create. Tuttavia, non sono veramente sicuro di come sostituire '-d' & c. con i miei metodi. Quindi questa è solo una domanda su come sostituire una funzione con un trattino in CORE :: GLOBAL.Perl: mocking -d -f e amici. Come inserirli in CORE :: GLOBAL

Un riferimento manuale sarebbe bello.

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} = []; 
    return @files; 
} 

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

1; 
+0

Perchè '* import = \ & Exporter :: import;' piuttosto che usare 'importatore' import '; '? – Ether

risposta

6

Potrebbe non essere possibile. La sezione perlsub su Overriding Built-in Functions è vaga su quali funzioni possono essere sovrascritte. "Molti" possono, "alcuni" non possono, ma a parte una manciata di esempi non c'è un elenco definitivo.

Normalmente, mi piacerebbe provare questo:

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

che non è un errore di sintassi, ma non ha l'effetto di override -d.

+0

Se è così, dovrò rendere il test del codice più testabile. grazie – telesphore4

+6

Overriding CORE :: GLOBAL deve accadere in BEGIN time o Perl non lo vedrà. È un hack delle prestazioni. In ogni caso, CORE :: GLOBAL funziona solo con le cose con i prototipi. -d non ha un prototipo. – Schwern

11

CORE :: GLOBAL non funziona su cose senza prototipi. L'unico modo in cui posso pensare di farlo è riscrivere l'albero del codice d'accesso ... che non è per i deboli di cuore. Potresti estrarlo con una combinazione di B::Utils e B::Generate e molti esperimenti.

La cosa più semplice da fare sarebbe utilizzare File::Temp per creare una struttura di directory temporanea a proprio piacimento.

1

Si potrebbe andare via il filtro di origine:.

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; 
} 

(Questo codice di esempio non è molto robusto Ad esempio, non si tradurrà -d$dir o -d "dirname with spaces", ma è possibile rinforzare l'alto fino ad incontrare la esigenze del tuo codice di destinazione).

+0

Questa è un'idea intrigante ... trasformazioni del codice sorgente ... molto grazie Lispish! – telesphore4

2

Il problema è che l'app dipende dalle specifiche dei file codificate. È necessario parametrizzare le specifiche del file; allora non devi più prendere in giro, puoi semplicemente usare Directory :: Scratch o qualcosa del genere.

+0

concordato. Tuttavia, aggiungo il codice di test a un'app legacy. – telesphore4

3

Grazie a tutti per le vostre risposte.

Quello che ho finito di fare è, su una base per modulo/obiettivo di test, ho scomposto il codice con la "-d" nella sua funzione. In questo modo ...

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

Poi mi può sostituire questa funzione nel modulo di test con il simile

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

sub mock_dirExists { 
    return $doesDirExist; 
} 

E 'abbastanza brutto ma non voleva essere appeso su questo troppo a lungo ed è funziona bene enuf per i miei scopi