The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Test::UnixExit - test exit status words

SYNOPSIS

  # modules that exit status words could come from
  #use Expect;
  #use Test::Cmd;

  # probably necessary for other tests
  use Test::Most;

  use Test::UnixExit;

  # ... some code here that sets $? here or $expect->exitstatus ...
  exit_is( $?, 0, "exit success" );

  # ... some code here that sets $? here or $expect->exitstatus ...
  exit_is( $?, { code => 0, signal => 2, iscore => 0 }, "SIGINT" );

  # same, but with less typing (unset fields default to 0)
  exit_is( $?, { signal => 2 }, "SIGINT" );

  # turn all nonzero exit codes to 1
  exit_is( Test::UnixExit::exit_is_nonzero($?), 1, "dies okay" );

DESCRIPTION

NOTE Test2::Tools::Command should be used instead of this module.

This module provides a means to check that the exit status word of a unix process exactly matches a specific exit code, signal number, and whether a core was generated; the simple $? >> 8 == 0 test ignores two of these three attributes.

  # the incomplete test
  is( $? >> 8, 0 );

  # with this module becomes
  exit_is( $?, 0 );

This code is most useful when testing external commands via system, Test::Cmd, or Expect and details are required beyond a simple "was $? zero or not" boolean. Perl code itself may be tested with modules such as Test::Exit or Test::Trap.

FUNCTIONS

exit_is is exported by default.

exit_is status expected-value [ test-name ]

This function accepts a status (the 16-bit return value from the wait(2) call), an expected-value as either an 8-bit exit code or a hash reference with various fields set, and an optional name for the test.

The return value is whether or not the test passed.

The fields for the hash reference are:

  code   => 8-bit exit status number (WEXITSTATUS)
  iscore => 1 or 0 if a core file was created or not
  signal => what signal the process ate (WTERMSIG), if any

Unspecified fields default to 0.

exit_is_nonzero status

exit_is requires exact values. Use exit_is_nonzero to change the code of an exit status word to 1 if any non-zero value is present.

Returns the (possibly modified) exit status word.

  # expect failure, but do not know what exit code will be used
  # implicit: no core was generated and no signal was involved
  exit_is( exit_is_nonzero($?), 1 );

If you do not care about the signal or iscore portions of the exit status word then simpler tests such as

  is(   $?, 0, "expect exit without error" );
  isnt( $?, 0, "expect process to fail" );

may suffice. In that case there is no need for this module. On the other hand, a program could change from a non-zero exit status word (OK) to non-zero exit status word with corefile (NOT OK) and you might want to know about that.

BUGS

Reporting Bugs

Patches might best be applied towards:

https://github.com/thrig/Test-UnixExit

Known Issues

The expected-value to exit_is is not much checked whether the inputs are sane, e.g. that code is an 8-bit number, etc. This may be a problem if this input is being generated by something that is buggy.

SEE ALSO

Test::Cmd, Expect - these provide means to check external commands, either by running the commands under a shell, or simulating a terminal environment. Good ways to obtain a $? to pass to this code, in other words.

Test::Exit, Test::Trap - these check that Perl code behaves in a particular way, and may be more suitable for testing code in a module over running a wrapper via the complication of a shell or virtual terminal.

Test2::Suite and in particular Test2::Tools::Command.

sh(1) vs. wait(2) - note that the shell $? variable differs from the 16-bit exit status word in that the signal number and core boolean flag are translated--the verb "mangled" also works here--into an 8-bit value. The Perl $? variable instead contains the 16-bit exit status word, a difference that can and does cause confusion.

Perl code can adjust $? inside an END subroutine to (try to) mandate that particular exit codes are used when a process goes away. This only works if you control the code on that side of the fence.

AUTHOR

thrig - Jeremy Mates (cpan:JMATES) <jmates at cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2016 by Jeremy Mates

This program is distributed under the (Revised) BSD License: https://www.opensource.org/licenses/BSD-3-Clause