2011-05-24 19 views
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 

很顯然,我很期待「哼! 「夾在「之前」和「之後」之間,但似乎沒有發生。

任何想法?

回答

2

我認爲捕獲是錯誤的。比較:

use IOTest; 
use Capture::Tiny qw(capture); 

print "Pre-capture\n"; 
my $output = capture { 
    print "before"; 
    IOTest::oink(); 
    print "after"; 
}; 
print "Captured StdOut:\n" . $output . "\nend\n"; 

Pre-capture 
Captured StdOut: 
beforeoink! 
after 
end 
相關問題