YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_expect_abort.h File Reference

Macros for testing code paths that are expected to abort. More...

#include <setjmp.h>
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include "ppm/core.h"
#include "yac_assert.h"
Include dependency graph for test_expect_abort.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define YAC_TEST_ABORT_UNHAPPY_PATH_ENABLED   1
 
#define YAC_TEST_ABORT_RUN_(result_var, expected_substr, ...)
 
#define YAC_TEST_EXPECT_ABORT_SERIAL( test_failed, expected_result, expected_substr, ...)
 
#define YAC_TEST_EXPECT_ABORT_PAR_ANY( test_failed, expected_result, expected_substr, comm, ...)
 
#define YAC_TEST_EXPECT_ABORT_PAR_ALL( test_failed, expected_result, expected_substr, comm, ...)
 

Enumerations

enum  yac_test_abort_result { YAC_TEST_ABORT_NO_CALL = 1 << 0 , YAC_TEST_ABORT_EXPECTED = 1 << 1 , YAC_TEST_ABORT_UNEXPECTED = 1 << 2 }
 
enum  { YAC_TEST_ABORT_MSG_LEN = 1024 }
 

Functions

struct { 
 
   jmp_buf   jmp 
 
   char const *   substr_ 
 
   char   msg_ [YAC_TEST_ABORT_MSG_LEN] 
 
   int   active_ 
 
} __attribute__ ((unused)) 
 

Detailed Description

Macros for testing code paths that are expected to abort.

The YAC_TEST_EXPECT_ABORT_* macros install an abort handler that longjmps back to the macro instead of terminating the process. This allows to test several unhappy paths from within a single test program and to continue testing afterwards.

Each use states the expected outcome, which is compared to the actual one. The expected outcome also determines whether the statement is executed at all: in code coverage builds the internal asserts are compiled out, and since an assert is the precondition for the code following it, a statement that is expected to abort must not be executed in such builds. Statements that are expected to complete normally (expected outcome YAC_TEST_ABORT_NO_CALL) are always executed.

Jumping out of the aborting routine skips all of its remaining code, which puts a couple of restrictions on where these macros can be used. YAC does not support being called again after the abort handler was invoked (see the remark on yac_set_abort_handler), so each use has to be checked against the routine that is expected to abort:

  • MPI: the aborting process does not execute the MPI calls that follow the abort in the tested routine. The macros may only be used if this cannot lead to unmatched communication, either because the abort is raised by all processes at the same point (YAC_TEST_EXPECT_ABORT_PAR_ALL) or because the remaining processes stop communicating as well (this has to be checked for YAC_TEST_EXPECT_ABORT_PAR_ANY). Otherwise the remaining processes will block in a collective call or, worse, match the reduction of the macro itself.
  • MPI: the expected outcome passed to the parallel macros has to be identical on all processes of the communicator. Otherwise some processes would skip the statement in a code coverage build while the others reach the reduction of the macro and block.
  • Resources: everything the aborting routine had allocated locally is leaked. Do not use these macros in builds that check for memory leaks.
  • State: the abort has to be raised before the tested routine modified any object that the test continues to use afterwards.
  • Local variables: the macros are based on setjmp/longjmp, so any local variable of the calling function that is modified by the statement and read after the macro has to be declared volatile (C11 7.13.2.1). Otherwise the modification may be rolled back by the longjmp in optimized builds, because the variable may be kept in a register that is restored to its setjmp-time value.

Definition in file test_expect_abort.h.

Macro Definition Documentation

◆ YAC_TEST_ABORT_RUN_

#define YAC_TEST_ABORT_RUN_ ( result_var,
expected_substr,
... )

Internal execution of the statement under the test abort handler.

Definition at line 222 of file test_expect_abort.h.

◆ YAC_TEST_ABORT_UNHAPPY_PATH_ENABLED

#define YAC_TEST_ABORT_UNHAPPY_PATH_ENABLED   1

Is 0 if statements that are expected to abort are not executed at all (code coverage builds, see above) and 1 otherwise.

Definition at line 83 of file test_expect_abort.h.

◆ YAC_TEST_EXPECT_ABORT_PAR_ALL

#define YAC_TEST_EXPECT_ABORT_PAR_ALL ( test_failed,
expected_result,
expected_substr,
comm,
... )
Value:
do { \
enum yac_test_abort_result yac_test_expected_ = (expected_result); \
if (utest_abort_skip_(yac_test_expected_)) { \
(test_failed) = 0; \
} else { \
/* volatile because the value is set between setjmp and longjmp \
and read afterwards */ \
enum yac_test_abort_result volatile yac_test_result_; \
YAC_TEST_ABORT_RUN_( \
yac_test_result_, expected_substr, __VA_ARGS__); \
(test_failed) = \
utest_abort_failed_( \
utest_abort_reduce_(yac_test_result_, (comm), 1), \
yac_test_expected_, __FILE__, __LINE__); \
} \
} while (0)
static char const * expected_substr
yac_test_abort_result

YAC_TEST_EXPECT_ABORT_PAR_ALL( test_failed, expected_result, expected_substr, comm, call)

Like YAC_TEST_EXPECT_ABORT_PAR_ANY, but requires that every process in comm calls the abort handler:

  • YAC_TEST_ABORT_EXPECTED – every process called abort with the expected message
  • YAC_TEST_ABORT_NO_CALL – no process called abort
  • YAC_TEST_ABORT_UNEXPECTED – all other cases (mixed outcomes or unexpected message)

expected_result has to be identical on all processes in comm.

The original abort handler is restored on every process before the reduce.

Parameters
test_failedint lvalue receiving the result of the comparison
expected_resultexpected outcome (enum yac_test_abort_result)
expected_substrsubstring expected in the error message, or NULL to accept any abort message
commMPI communicator
...statement to execute (last argument, so that it may contain commas at bracket level zero)

Definition at line 364 of file test_expect_abort.h.

◆ YAC_TEST_EXPECT_ABORT_PAR_ANY

#define YAC_TEST_EXPECT_ABORT_PAR_ANY ( test_failed,
expected_result,
expected_substr,
comm,
... )
Value:
do { \
enum yac_test_abort_result yac_test_expected_ = (expected_result); \
if (utest_abort_skip_(yac_test_expected_)) { \
(test_failed) = 0; \
} else { \
/* volatile because the value is set between setjmp and longjmp \
and read afterwards */ \
enum yac_test_abort_result volatile yac_test_result_; \
YAC_TEST_ABORT_RUN_( \
yac_test_result_, expected_substr, __VA_ARGS__); \
(test_failed) = \
utest_abort_failed_( \
utest_abort_reduce_(yac_test_result_, (comm), 0), \
yac_test_expected_, __FILE__, __LINE__); \
} \
} while (0)

YAC_TEST_EXPECT_ABORT_PAR_ANY( test_failed, expected_result, expected_substr, comm, call)

Like YAC_TEST_EXPECT_ABORT_SERIAL, but combines the per-process outcomes across all processes in comm before comparing them to expected_result:

  • YAC_TEST_ABORT_UNEXPECTED – at least one process got an unexpected message
  • YAC_TEST_ABORT_EXPECTED – at least one process called abort with the expected message (and none got unexpected)
  • YAC_TEST_ABORT_NO_CALL – no process called abort

expected_result has to be identical on all processes in comm.

The original abort handler is restored on every process before the reduce.

Parameters
test_failedint lvalue receiving the result of the comparison
expected_resultexpected outcome (enum yac_test_abort_result)
expected_substrsubstring expected in the error message, or NULL to accept any abort message
commMPI communicator
...statement to execute (last argument, so that it may contain commas at bracket level zero)

Definition at line 322 of file test_expect_abort.h.

◆ YAC_TEST_EXPECT_ABORT_SERIAL

#define YAC_TEST_EXPECT_ABORT_SERIAL ( test_failed,
expected_result,
expected_substr,
... )
Value:
do { \
enum yac_test_abort_result yac_test_expected_ = (expected_result); \
if (utest_abort_skip_(yac_test_expected_)) { \
(test_failed) = 0; \
} else { \
/* volatile because the value is set between setjmp and longjmp \
and read afterwards */ \
enum yac_test_abort_result volatile yac_test_result_; \
YAC_TEST_ABORT_RUN_( \
yac_test_result_, expected_substr, __VA_ARGS__); \
(test_failed) = \
utest_abort_failed_( \
yac_test_result_, yac_test_expected_, __FILE__, __LINE__); \
} \
} while (0)

YAC_TEST_EXPECT_ABORT_SERIAL( test_failed, expected_result, expected_substr, call)

Execute call under a custom abort handler and compare the outcome to expected_result:

  • YAC_TEST_ABORT_NO_CALL – call completes without triggering abort
  • YAC_TEST_ABORT_EXPECTED – abort is triggered with a message that contains expected_substr
  • YAC_TEST_ABORT_UNEXPECTED – abort is triggered with a message that does not contain expected_substr

test_failed is set to 0 if the outcome matches and to 1 otherwise, in which case the details of the mismatch are written to stderr. Counting the error is left to the caller.

If expected_result is not YAC_TEST_ABORT_NO_CALL and the internal asserts are compiled out, call is not executed and test_failed is set to 0.

The original abort handler is always restored afterwards.

Parameters
test_failedint lvalue receiving the result of the comparison
expected_resultexpected outcome (enum yac_test_abort_result)
expected_substrsubstring expected in the error message, or NULL to accept any abort message
...statement to execute (last argument, so that it may contain commas at bracket level zero)

Definition at line 282 of file test_expect_abort.h.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
YAC_TEST_ABORT_MSG_LEN 

Definition at line 88 of file test_expect_abort.h.

◆ yac_test_abort_result

Possible outcomes of a statement executed under the test abort handler. The parallel macros OR these values together to combine the per-process outcomes, hence each has to be a distinct single bit. The nonzero values are also passed to longjmp; YAC_TEST_ABORT_NO_CALL is never used with longjmp (it corresponds to the direct return from setjmp).

Enumerator
YAC_TEST_ABORT_NO_CALL 

abort handler was never invoked

YAC_TEST_ABORT_EXPECTED 

abort was called with expected message

YAC_TEST_ABORT_UNEXPECTED 

abort was called with unexpected message

Definition at line 70 of file test_expect_abort.h.

Function Documentation

◆ __attribute__()

static struct @77 __attribute__ ( (unused) )
static

Variable Documentation

◆ active_

int active_

Definition at line 94 of file test_expect_abort.h.

◆ jmp

jmp_buf jmp

Definition at line 91 of file test_expect_abort.h.

◆ msg_

char msg_

Definition at line 93 of file test_expect_abort.h.

◆ substr_

char const * substr_

Definition at line 92 of file test_expect_abort.h.