views:

752

answers:

3

I am writing a Perl module, and I am using carp to throw a non-fatal warning back to the calling program.

The carp warning works fine - I am checking if an input parameter meets a certain condition - if it does not meet the condition, a warning is sent with carp and the module continues on using a default for the parameter instead of the one the calling program passed. The warning is just to notify that a default parameter is being used instead of the passed in parameter.

My problem is with my test script. My test script is sending in a bad parameter to the module, and I am trying to catch the warning message that comes back and make sure I got the correct warning message.

My module looks something like this:

else {
  carp "value must be numeric - using default value";
}

and my test script looks like this:

eval {
  #call to my module
};
like (
    $@,
    qr/value must be numeric/,
    "Should abort on non-numeric value"
);

When I run the test, I can see the warning (it must be going to STDERR) on the screen, but the contents of the $@ variable is '' - blank.

Here is the output from my test script:

t/04bad_method_calls....ok 10/12value must be numeric - using default value at ...
#   Failed test 'Should abort on non-numeric value'
#   at t/04bad_method_calls.t line 98.
t/04bad_method_calls....NOK 12
#                   '' doesn't match '(?-xism:value must be numeric)'
# Looks like you failed 1 test of 12.

If I change the carp to a croak, my test script works - it catches the error message (but I only want to warn, not abort).

To be honest, I don't have the best understanding of eval - maybe that is not the best way to catch the warning output from carp. I tried using $SIG{WARN}, but that was empty as well.

Is there any way to capture the output from carp? It's not the biggest deal since this is just in my test script, but I'd still like to get my test script to work properly.

Thanks in advance!

+10  A: 

From this page, http://perldoc.perl.org/perlvar.html, it looks like you want to set the local $SIG{__WARN__} to a subroutine that will turn warnings into fatal errors for your test script. The example they give is:

local $SIG{__WARN__} = sub { die $_[0] };
eval $proggie;
Tracy Hurley
Yep, that was the trick! I was misunderstanding what $SIG{__WARN__} was. This works perfectly - thanks so much!
BrianH
+4  A: 

Another way how to catch warnings and also all STERR output:

my $stderr = '';
{
 local *STDERR;
 open STDERR, '>', \$stderr;
 do_stuf_here();
}
like( $stderr, qr/my result/, 'test stderr output' );

One can make fancy test function:

sub stderr_test (&$$) {
 my ( $code, $pattern, $text ) = @_;
 my $result = '';
 {
  local *STDERR;
  open STDERR, '>', \$result;
  $code->();
 }
 if ( UNIVERSAL::isa( $pattern, 'Regexp' ) ) {
  like( $result, $pattern, $text );
 }
 else {
  is( $result, $pattern, $text );
 }
}

# usage
stderr_test {do_stuf_here} qr/my expected STDERR output/,
 'stderr is like';
stderr_test {do_stuf_here} 'my expected STDERR output',
 'stderr is exactly';
Hynek -Pichi- Vychodil
Wow - very interesting. That first example is pretty straight forward and would seem to work nicely as well.
BrianH
+4  A: 

If you're doing this from a test script, you can use of the Test::* modules that capture output for you. I tend to like Test::Output.

brian d foy
That looks like a pretty simple solution. Unfortunately I don't have Test::Output installed in our environment, and installing modules is pretty much discouraged here. Even though it doesn't fit my needs, +1 for a great solution.
BrianH

related questions