Nedávno som sa začal hrať s písanímRozšírenia Perl (v5.8.8) používajúce XS. Jedna z metód, ktoré píšem, zhromažďuje množstvo údajov a posiela ich klientovi. Chcem napísať niekoľko jednotkových testov, ktoré urobia tvrdenia proti výstupu, ale narážam na problém: Nezdá sa, že metódy PerlIO prenášajú údaje cez rovnaké kanály ako print
volať v Perl robí. Normálne sa môžete pripojiť k obslužnému programu súboru STDOUT a zachytiť výsledok, ale zdá sa, že metódy PerlIO to úplne obchádzajú.
Prilepil som príklad nižšie, ale základný princíp môjho testu je tento: Tie
do STDOUT
, spustiť kód, untie
, vrátiť zozbieraný reťazec. Keď to robím, dokážem zachytiť print
vyhlásenia, ale nie PerlIO_*
hovory z môjho modulu. Skúsil som použiť PerlIO_write
, PerlIO_puts
, PerlIO_printf
, a viac. Žiadne kocky.
Od začiatku, tu je minimálna replika toho, čo robím:
h2xs -A -n IOTest
cd IOTest
Vložte toto do IOTest.xs
:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = IOTest PACKAGE = IOTest
void
oink ()
CODE:
PerlIO_puts(PerlIO_stdout(), "oink!n");
A toto prejde do súboru s názvom test.pl
(Zaujímavá časť je v spodnej časti, všetko ostatné je len na zachytenie stdout):
# Set up the include path to match the build directories
BEGIN {
push @INC, "./blib/lib/";
push @INC, "./blib/arch/auto/IOTest";
}
use IOTest;
# This package is just a set of hooks for tieing in to stdout
{
# Lifted from the Test::Output module found here:
# http://search.cpan.org/~bdfoy/Test-Output-1.01/lib/Test/Output.pm
package OutputTie;
sub TIEHANDLE {
my $class = shift;
my $scalar = "";
my $obj = shift || $scalar;
bless( $obj, $class);
}
sub PRINT {
my $self = shift;
$$self .= join(defined $, ? $, : "", @_);
$$self .= defined $ ? $ : "";
}
sub PRINTF {
my $self = shift;
my $fmt = shift;
$$self .= sprintf $fmt, @_;
}
sub read {
my $self = shift;
my $data = $$self;
$$self = "";
return $data;
}
}
# Runs a sub, intercepts stdout and returns it as a string
sub getStdOut (&) {
my $callback = shift;
select( ( select(STDOUT), $| = 1 )[0] );
my $out = tie *STDOUT, "OutputTie";
$callback->();
my $stdout = $out->read;
undef $out;
untie *STDOUT;
return $stdout;
}
# This is the interesting part, the actual test:
print "Pre-capturen";
my $output = getStdOut(sub {
print "before";
IOTest::oink();
print "after";
});
print "Captured StdOut:n" . $output . "nendn";
Budovanie a testovanie je potom len otázkou:
perl Makefile.PL
make
perl test.pl
Výstup, ktorý vidím, je:
Pre-capture
oink!
Captured StdOut:
beforeafter
end
Je zrejmé, že očakávam, že „oink!“ bude vložené medzi „pred“ a „po“, ale zdá sa, že sa to nedeje.
Nejaké nápady?
odpovede:
2 pre odpoveď č. 1Myslím, že snímanie je chybné. Porovnaj:
use IOTest;
use Capture::Tiny qw(capture);
print "Pre-capturen";
my $output = capture {
print "before";
IOTest::oink();
print "after";
};
print "Captured StdOut:n" . $output . "nendn";
Pre-capture
Captured StdOut:
beforeoink!
after
end