openがまだ2引数でベアワードを織り交ぜていた頃のメール送信プログラムがあります。 このメールのメッセージをテストするスクリプトを書こうとしています。

一部だけ抜粋するとこのような感じになります:

require 'jcode.pl';
require 'mimew.pl';

open(FH, '| sendmail -t -oi');
print FH &mimeencode("From: $from") . "\n";
print FH &mimeencode("To: $to") . "\n";
print FH qq{Content-Type: text/plain; charset="iso-2022-jp"\n};
print FH &mimeencode("Subject: $subject") . "\n";
print FH "\n";
foreach $line (@lines) {
    print FH &jcode::jis($line, 'sjis') . "\n";
}
close(FH);

とりあえずざっくりと、テストスクリプトが対象のコードを舐めた時に実際にメールを送ってしまわないように、openにsendmailらしきコマンドが渡されたら黙って1を返すよう以下のようなコードをテストに含めました。

しかし、そこから一歩進んでファイルハンドルに書き込まれた内容を評価する方法が分かりません。

BEGIN {
    use Symbol ();
    *CORE::GLOBAL::open = sub : prototype(*;$@) {
        no strict 'refs';
        $_[0] = defined $_[0] ? $_[0] : Symbol::qualify($_[0], scalar caller);
        return CORE::open($_[0]) if @_ == 1;
        return 1 if $_[1] =~ /sendmail/;
        return CORE::open($_[0], $_[1]) if @_ == 2;
        return 1 if $_[2] =~ /sendmail/;
        return CORE::open($_[0], $_[1], $_[2]) if @_ == 3 && defined $_[2];
        return CORE::open($_[0], $_[1], undef) if @_ == 3;
        return CORE::open($_[0], $_[1], @_[2..$#_]);
    };
}

以下の条件を満たしつつファイルハンドルに書き出された文字列をテストスクリプトの中で変数に代入することは可能でしょうか? また、可能であればどのように実現できますか?

  • テスト実行時に実際にメールを送信させてしまわないこと。
  • スクリプトが他で使っているsendmailと関係のないopenを壊さないこと。
  • テスト対象のスクリプトをいじらない事。