Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

How to test exit?

by andreas1234567 (Vicar)
on Jun 05, 2007 at 18:51 UTC ( [id://619479]=perlquestion: print w/replies, xml ) Need Help??

andreas1234567 has asked for the wisdom of the Perl Monks concerning the following question:

Honored monks,
This very question has been discussed 2 years ago in this node: How to test a module that exits? A interesting and related discussion on the perl.qa was titled Should TAP capture exit codes? If the module were to die instead of exit, I would use Test::Exception to catch a die like this:
$ cat test_exit.pl use strict; use warnings; sub killer { die "hasta la vista baby"; } sub exiter { exit(42); } 1; __END__
$ cat test_exit.t use warnings; use strict; use Test::More tests => 2; use Test::Exception; ok(require('test_exit.pl'), 'loaded'); throws_ok( sub { killer () }, qr/hasta la vista baby/, q{Expected kill +er to die}); __END__
$ prove test_exit.t test_exit....ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.04 cusr + 0.01 csys = 0.05 C +PU)
Now I wonder what kind of tricks I can use to test exit in the same way as die?
Update: Test::Trap is a brilliant solution. Thanks Sidhekin.
--
print map{chr}unpack(q{A3}x24,q{074117115116032097110111116104101114032080101114108032104097099107101114})

Replies are listed 'Best First'.
Re: How to test exit?
by Sidhekin (Priest) on Jun 05, 2007 at 21:22 UTC

    Test::Trap! Shameless plug, yes indeed. But it does what you want:

    $ cat trap_exit.t use warnings; use strict; use Test::More tests => 3; use Test::Trap; ok(require('test_exit.pl'), 'loaded'); trap{ killer() }; $trap->die_like( qr/hasta la vista baby/, q{Expected killer to die} ); trap{ exiter() }; $trap->exit_is( 42, q{Expected exiter to exit} );
    $ prove -v test_exit.t test_exit....1..3 ok 1 - loaded ok 2 - Expected killer to die ok 3 - Expected exiter to exit ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.09 cusr + 0.00 csys = 0.09 C +PU)

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

Re: How to test exit?
by Fletch (Bishop) on Jun 05, 2007 at 19:14 UTC

    CORE::exit can be overridden, so you might could play some games with that (making it instead die with a specific string containing the exit value passed and catch that inside an eval handler).

      Another option stemming from the core would be to look and see if perl itsself has any test.t's for exit and how those were done.
Re: How to test exit?
by Roy Johnson (Monsignor) on Jun 05, 2007 at 19:23 UTC
    My approach would be to fork and check the exit. You'd probably want to add a timeout feature to kill tenacious subs that fail to exit. Really stripped-down example:
    use strict; use warnings; sub test_exit { my ($subr, $exit_val) = @_; my $subp = fork; if ($subp) { my $done = waitpid($subp, 0); print "Process $done Exited with ".($?>>8).", expected $exit_val\n +"; } else { $subr->(); warn "Did not exit\n"; exit (~$exit_val); } } test_exit(sub{print "Process has run\n"; exit(42)}, 42);

    Caution: Contents may have been coded under pressure.
Re: How to test exit? - override CORE::GLOBAL::exit
by imp (Priest) on Jun 05, 2007 at 19:46 UTC
    You could override the core exit function with a thin wrapper that executes a callback with the logic you want to test. Something like this:
    use strict; use warnings; use Test::More (tests => 1); my $exit_callback = sub {}; BEGIN { *CORE::GLOBAL::exit = sub { $exit_callback->(@_) }; } my $exit_called = 0; $exit_callback = sub { $exit_called = 1}; exit; is($exit_called, 1, "exit was called");
    Or you could play with it a bit more and do something like this:
    use strict; use warnings; use Test::More (tests => 2); my $exit_callback = sub {}; BEGIN { *CORE::GLOBAL::exit = sub { $exit_callback->(@_) }; } sub exit_ok(&$) { my ($code, $message) = @_; my $exit_called = 0; $exit_callback = sub { $exit_called = 1}; $code->(); is($exit_called, 1, $message); } sub noexit_ok(&$) { my ($code, $message) = @_; my $exit_called = 0; $exit_callback = sub { $exit_called = 1}; $code->(); is($exit_called, 0, $message); } exit_ok { exit } "exit called"; noexit_ok { } "exit not called";
      I decided to play with this a little more and wrote a quick implementation of Test::Exit.

      Update - use Sidhekin 's Test::Trap instead

      Test/Exit.pm

      package Test::Exit; use strict; use warnings; use Test::Builder; use base qw( Exporter ); our @EXPORT = qw( exit_ok exit_nok exit_with ); my $test = Test::Builder->new; my $exit_callback = sub {}; BEGIN { *CORE::GLOBAL::exit = sub { $exit_callback->(@_) }; } sub exit_with(&$$) { my ($coderef, $expected_exit_code, $message) = @_; my $exit_called = 0; my $exit_code = 0; $exit_callback = sub { $exit_called = 1; $exit_code = shift }; $coderef->(); if ($exit_called) { if (! $test->ok( $expected_exit_code == $exit_code, $message)) + { $test->diag("expected $expected_exit_code but received $ex +it_code"); } } else { fail($message . " - exit not called"); } } sub exit_ok(&$) { my ($coderef, $message) = @_; my $exit_called = 0; $exit_callback = sub { $exit_called = 1}; $coderef->(); $test->ok($exit_called == 1, $message); } sub exit_nok(&$) { my ($coderef, $message) = @_; my $exit_called = 0; $exit_callback = sub { $exit_called = 1}; $coderef->(); $test->ok($exit_called == 0, $message); } 1; =head1 NAME Test::Exit - Tests whether exit was called =head2 exit_ok exit_ok { exit; }, 'assert that exit was called'; =head2 exit_nok exit_nok { }, 'assert that exit was not called'; =head2 exit_with exit_with { exit 2 }, 2, 'expect exit(2)'; =cut
      test.pl
      use strict; use warnings; use Test::More (tests => 3); use Test::Exit; exit_ok { exit } "exit called"; exit_nok { } "exit not called"; exit_with { exit 2; } 2, 'exit code = 2';
        You can use Test::Trap , to catch exitcode, stdout, stderr etc of a subroutine
Re: How to test exit?
by FunkyMonk (Chancellor) on Jun 05, 2007 at 19:25 UTC
    Not perfect, but how about:

    x.pm

    use strict; use warnings; sub killer { die "hasta la vista baby"; } sub exiter { exit(42); } 1;

    main

    use warnings; use strict; use Test::More tests => 3; use Test::Exception; ok(require('x.pm'), 'loaded'); throws_ok( sub { killer () }, qr/hasta la vista baby/, q{Expected kill +er to die}); BEGIN { no strict 'refs'; no warnings; *CORE::GLOBAL::exit = sub { die "exited with code ", $_[0] || 0; }; } throws_ok( sub { exiter () }, qr/exited with code 42/, q{killer exited +});

    Fletch suggested that CORE::exit could be redefined, but I had no success with that.

    Updated with the help from imp. Thanks (++)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://619479]
Approved by grep
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (7)
As of 2024-04-19 08:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found