/ / Impression sur la sortie standard depuis une extension Perl XS - perl, perl-module, xs

Impression sur la sortie standard d’une extension Perl XS - perl, perl-module, xs

J'ai récemment commencé à jouer avec l'écriturePerl (v5.8.8) extensions utilisant XS. L'une des méthodes que j'écris collecte une série de données et les envoie au client. Je veux écrire des tests unitaires qui associent la sortie à des assertions, mais je rencontre un problème: il ne semble pas que les méthodes PerlIO transmettent des données par les mêmes canaux print appeler en Perl fait. Normalement, vous pouvez vous connecter au gestionnaire de fichiers STDOUT et intercepter le résultat, mais les méthodes PerlIO semblent les contourner complètement.

J'ai collé un exemple ci-dessous, mais le test de base de mon test est le suivant: Tie dans STDOUT, code d'exécution, untie, retourne la chaîne collectée. En faisant cela, je suis capable de capturer print déclarations, mais pas la PerlIO_* appels de mon module. J'ai essayé d'utiliser PerlIO_write, PerlIO_puts, PerlIO_printf, et plus. Pas de dé.

À partir de zéro, voici une réplique minimale de ce que je fais:

h2xs -A -n IOTest
cd IOTest

Mettez ceci dans 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");

Et cela va dans un fichier appelé test.pl (La partie intéressante est près du bas, tout le reste est juste pour capturer 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";

Construire et tester est alors juste une question de:

perl Makefile.PL
make
perl test.pl

La sortie que je vois est:

Pre-capture
oink!
Captured StdOut:
beforeafter
end

Évidemment, je m'attends à ce que "oink!" Soit pris en sandwich entre "avant" et "après", mais cela ne semble pas se produire.

Des idées?

Réponses:

2 pour la réponse № 1

Je pense que la capture est défectueuse. Comparer:

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