2
我最近開始使用XS編寫Perl(v5.8.8)擴展。我正在寫的一種方法是收集大量數據並將其呈現給客戶端。我想寫一些單元測試來對輸出進行斷言,但是我遇到了一個問題:PerlIO方法不像Perl中的調用那樣通過相同的通道傳遞數據。通常情況下,您可以綁定到STDOUT文件處理程序並攔截結果,但PerlIO方法似乎完全繞過了這一點。從Perl XS擴展打印到標準輸出
我已經在下面貼了一個例子,但我測試的基本問題是這樣的:Tie
in到STDOUT
,運行代碼untie
,返回收集到的字符串。這樣做,我能夠捕獲print
聲明,但不能從我的模塊調用PerlIO_*
。我試過使用PerlIO_write
,PerlIO_puts
,PerlIO_printf
,等等。沒有骰子。
從無到有,這裏是我在做什麼最小的攝製:
h2xs -A -n IOTest
cd IOTest
將這個中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");
而這正好到一個文件稱爲test.pl
(有趣的部分接近底部,其他所有內容僅用於捕獲標準輸出):
# 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-capture\n";
my $output = getStdOut(sub {
print "before";
IOTest::oink();
print "after";
});
print "Captured StdOut:\n" . $output . "\nend\n";
建設和測試,不只是一個物質:
perl Makefile.PL
make
perl test.pl
我看到的輸出是:
Pre-capture
oink!
Captured StdOut:
beforeafter
end
很顯然,我很期待「哼! 「夾在「之前」和「之後」之間,但似乎沒有發生。
任何想法?