Unverified Commit e0200cf3 authored by Axel Kohlmeyer's avatar Axel Kohlmeyer
Browse files

consistently skip death tests at runtime when using OpenMPI without exceptions

parent bf5c1dbc
Loading
Loading
Loading
Loading
+52 −62
Original line number Diff line number Diff line
@@ -28,6 +28,12 @@
// whether to print verbose output (i.e. not capturing LAMMPS screen output).
bool verbose = false;

#if defined(OMPI_MAJOR_VERSION)
const bool have_openmpi = true;
#else
const bool have_openmpi = false;
#endif

using LAMMPS_NS::utils::split_words;

namespace LAMMPS_NS {
@@ -35,11 +41,19 @@ using ::testing::MatchesRegex;

#define GETIDX(i) lmp->atom->map(i)

#define TEST_FAILURE(...)                \
#define TEST_FAILURE(errmsg, ...)                                 \
    if (Info::has_exceptions()) {                                 \
        ::testing::internal::CaptureStdout();                     \
        ASSERT_ANY_THROW({__VA_ARGS__});                          \
        auto mesg = ::testing::internal::GetCapturedStdout();     \
        ASSERT_THAT(mesg, MatchesRegex(errmsg));                  \
    } else {                                                      \
        if (!have_openmpi) {                                      \
            ::testing::internal::CaptureStdout();                 \
            ASSERT_DEATH({__VA_ARGS__}, "");                      \
            auto mesg = ::testing::internal::GetCapturedStdout(); \
            ASSERT_THAT(mesg, MatchesRegex(errmsg));              \
        }                                                         \
    }

#define STRINGIFY(val) XSTR(val)
@@ -454,51 +468,26 @@ TEST_F(ResetIDsTest, DeleteAdd)

TEST_F(ResetIDsTest, DeathTests)
{
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all offset 1 1"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all offset -2"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all offset xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR on proc 0: Expected integer.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all compress yes single no offset xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR on proc 0: Expected integer.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all offset"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all compress"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all compress xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all single"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all single xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_mol_ids command.*"));
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*", lmp->input->one("reset_mol_ids"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all offset 1 1"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all offset -2"););
    TEST_FAILURE(".*ERROR on proc 0: Expected integer.*",
                 lmp->input->one("reset_mol_ids all offset xxx"););
    TEST_FAILURE(".*ERROR on proc 0: Expected integer.*",
                 lmp->input->one("reset_mol_ids all compress yes single no offset xxx"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all offset"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all compress"););

    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all compress xxx"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all single"););
    TEST_FAILURE(".*ERROR: Illegal reset_mol_ids command.*",
                 lmp->input->one("reset_mol_ids all single xxx"););
}

TEST(ResetMolIds, CMDFail)
@@ -511,26 +500,23 @@ TEST(ResetMolIds, CMDFail)
    lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
    if (!verbose) ::testing::internal::GetCapturedStdout();

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_mol_ids all"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Reset_mol_ids command before.*"));
    TEST_FAILURE(".*ERROR: Reset_mol_ids command before box is.*",
                 lmp->input->one("reset_mol_ids all"););

    ::testing::internal::CaptureStdout();
    if (!verbose) ::testing::internal::CaptureStdout();
    lmp->input->one("atom_modify id no");
    lmp->input->one("region box block 0 1 0 1 0 1");
    lmp->input->one("create_box 1 box");
    TEST_FAILURE(lmp->input->one("reset_mol_ids all"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Cannot use reset_mol_ids unl.*"));
    if (!verbose) ::testing::internal::GetCapturedStdout();
    TEST_FAILURE(".*ERROR: Cannot use reset_mol_ids unless.*",
                 lmp->input->one("reset_mol_ids all"););

    ::testing::internal::CaptureStdout();
    if (!verbose) ::testing::internal::CaptureStdout();
    lmp->input->one("clear");
    lmp->input->one("region box block 0 1 0 1 0 1");
    lmp->input->one("create_box 1 box");
    TEST_FAILURE(lmp->input->one("reset_mol_ids all"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Can only use reset_mol_ids.*"));
    if (!verbose) ::testing::internal::GetCapturedStdout();
    TEST_FAILURE(".*ERROR: Can only use reset_mol_ids.*", lmp->input->one("reset_mol_ids all"););

    if (!verbose) ::testing::internal::CaptureStdout();
    delete lmp;
@@ -544,6 +530,10 @@ int main(int argc, char **argv)
    MPI_Init(&argc, &argv);
    ::testing::InitGoogleMock(&argc, argv);

    if (have_openmpi && !LAMMPS_NS::Info::has_exceptions())
        std::cout << "Warning: using OpenMPI without exceptions. "
                     "Death tests will be skipped\n";

    // handle arguments passed via environment variable
    if (const char *var = getenv("TEST_ARGS")) {
        std::vector<std::string> env = split_words(var);
+46 −91
Original line number Diff line number Diff line
@@ -30,6 +30,12 @@
// whether to print verbose output (i.e. not capturing LAMMPS screen output).
bool verbose = false;

#if defined(OMPI_MAJOR_VERSION)
const bool have_openmpi = true;
#else
const bool have_openmpi = false;
#endif

using LAMMPS_NS::utils::split_words;

namespace LAMMPS_NS {
@@ -37,11 +43,19 @@ using ::testing::ExitedWithCode;
using ::testing::MatchesRegex;
using ::testing::StrEq;

#define TEST_FAILURE(...)                \
#define TEST_FAILURE(errmsg, ...)                                 \
    if (Info::has_exceptions()) {                                 \
        ::testing::internal::CaptureStdout();                     \
        ASSERT_ANY_THROW({__VA_ARGS__});                          \
        auto mesg = ::testing::internal::GetCapturedStdout();     \
        ASSERT_THAT(mesg, MatchesRegex(errmsg));                  \
    } else {                                                      \
        if (!have_openmpi) {                                      \
            ::testing::internal::CaptureStdout();                 \
            ASSERT_DEATH({__VA_ARGS__}, "");                      \
            auto mesg = ::testing::internal::GetCapturedStdout(); \
            ASSERT_THAT(mesg, MatchesRegex(errmsg));              \
        }                                                         \
    }

class SimpleCommandsTest : public ::testing::Test {
@@ -68,10 +82,7 @@ protected:

TEST_F(SimpleCommandsTest, UnknownCommand)
{
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("XXX one two three"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Unknown command.*"));
    TEST_FAILURE(".*ERROR: Unknown command.*", lmp->input->one("XXX one two"););
}

TEST_F(SimpleCommandsTest, Echo)
@@ -103,15 +114,8 @@ TEST_F(SimpleCommandsTest, Echo)
    ASSERT_EQ(lmp->input->echo_screen, 0);
    ASSERT_EQ(lmp->input->echo_log, 1);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("echo"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex("^ERROR: Illegal echo command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("echo xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex("^ERROR: Illegal echo command.*"));
    TEST_FAILURE(".*ERROR: Illegal echo command.*", lmp->input->one("echo"););
    TEST_FAILURE(".*ERROR: Illegal echo command.*", lmp->input->one("echo xxx"););
}

TEST_F(SimpleCommandsTest, Log)
@@ -154,24 +158,20 @@ TEST_F(SimpleCommandsTest, Log)
    in.close();
    remove("simple_command_test.log");

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("log"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal log command.*"));
    TEST_FAILURE(".*ERROR: Illegal log command.*", lmp->input->one("log"););
}

TEST_F(SimpleCommandsTest, Quit)
{
    ::testing::internal::CaptureStdout();
    lmp->input->one("echo none");
    TEST_FAILURE(lmp->input->one("quit xxx"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Expected integer .*"));
    ::testing::internal::GetCapturedStdout();
    TEST_FAILURE(".*ERROR: Expected integer .*", lmp->input->one("quit xxx"););

#if !defined(OMPI_MAJOR_VERSION) // this stalls with OpenMPI. skip.
    // the following tests must be skipped with OpenMPI due to using threads
    if (have_openmpi) GTEST_SKIP();
    ASSERT_EXIT(lmp->input->one("quit"), ExitedWithCode(0), "");
    ASSERT_EXIT(lmp->input->one("quit 9"), ExitedWithCode(9), "");
#endif
}

TEST_F(SimpleCommandsTest, ResetTimestep)
@@ -188,25 +188,10 @@ TEST_F(SimpleCommandsTest, ResetTimestep)
    if (!verbose) ::testing::internal::GetCapturedStdout();
    ASSERT_EQ(lmp->update->ntimestep, 0);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_timestep -10"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Timestep must be >= 0.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_timestep"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_timestep .*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_timestep 10 10"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal reset_timestep .*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("reset_timestep xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Expected integer .*"));
    TEST_FAILURE(".*ERROR: Timestep must be >= 0.*", lmp->input->one("reset_timestep -10"););
    TEST_FAILURE(".*ERROR: Illegal reset_timestep .*", lmp->input->one("reset_timestep"););
    TEST_FAILURE(".*ERROR: Illegal reset_timestep .*", lmp->input->one("reset_timestep 10 10"););
    TEST_FAILURE(".*ERROR: Expected integer .*", lmp->input->one("reset_timestep xxx"););
}

TEST_F(SimpleCommandsTest, Suffix)
@@ -215,10 +200,8 @@ TEST_F(SimpleCommandsTest, Suffix)
    ASSERT_EQ(lmp->suffix, nullptr);
    ASSERT_EQ(lmp->suffix2, nullptr);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("suffix on"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: May only enable suffixes after defining one.*"));
    TEST_FAILURE(".*ERROR: May only enable suffixes after defining one.*",
                 lmp->input->one("suffix on"););

    if (!verbose) ::testing::internal::CaptureStdout();
    lmp->input->one("suffix one");
@@ -247,20 +230,9 @@ TEST_F(SimpleCommandsTest, Suffix)
    if (!verbose) ::testing::internal::GetCapturedStdout();
    ASSERT_EQ(lmp->suffix_enable, 1);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("suffix"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal suffix command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("suffix hybrid"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal suffix command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("suffix hybrid one"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal suffix command.*"));
    TEST_FAILURE(".*ERROR: Illegal suffix command.*", lmp->input->one("suffix"););
    TEST_FAILURE(".*ERROR: Illegal suffix command.*", lmp->input->one("suffix hybrid"););
    TEST_FAILURE(".*ERROR: Illegal suffix command.*", lmp->input->one("suffix hybrid one"););
}

TEST_F(SimpleCommandsTest, Thermo)
@@ -284,20 +256,9 @@ TEST_F(SimpleCommandsTest, Thermo)
    ASSERT_EQ(lmp->output->thermo_every, 10);
    ASSERT_EQ(lmp->output->var_thermo, nullptr);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("thermo"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal thermo command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("thermo -1"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal thermo command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("thermo xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Expected integer.*"));
    TEST_FAILURE(".*ERROR: Illegal thermo command.*", lmp->input->one("thermo"););
    TEST_FAILURE(".*ERROR: Illegal thermo command.*", lmp->input->one("thermo -1"););
    TEST_FAILURE(".*ERROR: Expected integer.*", lmp->input->one("thermo xxx"););
}

TEST_F(SimpleCommandsTest, TimeStep)
@@ -324,15 +285,8 @@ TEST_F(SimpleCommandsTest, TimeStep)
    if (!verbose) ::testing::internal::GetCapturedStdout();
    ASSERT_EQ(lmp->update->dt, -0.1);

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("timestep"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal timestep command.*"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("timestep xxx"););
    mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Expected floating point.*"));
    TEST_FAILURE(".*ERROR: Illegal timestep command.*", lmp->input->one("timestep"););
    TEST_FAILURE(".*ERROR: Expected floating point.*", lmp->input->one("timestep xxx"););
}

TEST_F(SimpleCommandsTest, Units)
@@ -356,10 +310,7 @@ TEST_F(SimpleCommandsTest, Units)
    if (!verbose) ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(lmp->update->unit_style, StrEq("lj"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(lmp->input->one("units unknown"););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR: Illegal units command.*"));
    TEST_FAILURE(".*ERROR: Illegal units command.*", lmp->input->one("units unknown"););
}
} // namespace LAMMPS_NS

@@ -368,6 +319,10 @@ int main(int argc, char **argv)
    MPI_Init(&argc, &argv);
    ::testing::InitGoogleMock(&argc, argv);

    if (have_openmpi && !LAMMPS_NS::Info::has_exceptions())
        std::cout << "Warning: using OpenMPI without exceptions. "
                     "Death tests will be skipped\n";

    // handle arguments passed via environment variable
    if (const char *var = getenv("TEST_ARGS")) {
        std::vector<std::string> env = split_words(var);
+31 −16
Original line number Diff line number Diff line
@@ -23,17 +23,33 @@
#include <string>

using namespace LAMMPS_NS;
using testing::StartsWith;

using testing::MatchesRegex;
using testing::StrEq;

using utils::sfgets;
using utils::sfread;
using utils::split_words;

#define TEST_FAILURE(...)                \
#if defined(OMPI_MAJOR_VERSION)
const bool have_openmpi = true;
#else
const bool have_openmpi = false;
#endif

#define TEST_FAILURE(errmsg, ...)                                 \
    if (Info::has_exceptions()) {                                 \
        ::testing::internal::CaptureStdout();                     \
        ASSERT_ANY_THROW({__VA_ARGS__});                          \
        auto mesg = ::testing::internal::GetCapturedStdout();     \
        ASSERT_THAT(mesg, MatchesRegex(errmsg));                  \
    } else {                                                      \
        if (!have_openmpi) {                                      \
            ::testing::internal::CaptureStdout();                 \
            ASSERT_DEATH({__VA_ARGS__}, "");                      \
            auto mesg = ::testing::internal::GetCapturedStdout(); \
            ASSERT_THAT(mesg, MatchesRegex(errmsg));              \
        }                                                         \
    }

// whether to print verbose output (i.e. not capturing LAMMPS screen output).
@@ -99,13 +115,10 @@ TEST_F(FileOperationsTest, safe_fgets)
    ASSERT_THAT(buf, StrEq("newline"));

    memset(buf, 0, MAX_BUF_SIZE);
    ::testing::internal::CaptureStdout();
    TEST_FAILURE(
        ".*ERROR on proc 0: Unexpected end of file while "
        "reading file 'safe_file_read_test.txt'.*",
        utils::sfgets(FLERR, buf, MAX_BUF_SIZE, fp, "safe_file_read_test.txt", lmp->error););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, StartsWith("ERROR on proc 0: Unexpected end of file while "
                                 "reading file 'safe_file_read_test.txt'"));

    fclose(fp);
}

@@ -125,11 +138,9 @@ TEST_F(FileOperationsTest, safe_fread)
    utils::sfread(FLERR, buf, 1, 10, fp, "safe_file_read_test.txt", nullptr);
    ASSERT_THAT(buf, StrEq("two_lines\n"));

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(utils::sfread(FLERR, buf, 1, 100, fp, "safe_file_read_test.txt", lmp->error););
    auto mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, StartsWith("ERROR on proc 0: Unexpected end of file while "
                                 "reading file 'safe_file_read_test.txt'"));
    TEST_FAILURE(".*ERROR on proc 0: Unexpected end of file while "
                 "reading file 'safe_file_read_test.txt'.*",
                 utils::sfread(FLERR, buf, 1, 100, fp, "safe_file_read_test.txt", lmp->error););

    // short read but no error triggered due to passing a NULL pointer
    memset(buf, 0, MAX_BUF_SIZE);
@@ -166,6 +177,10 @@ int main(int argc, char **argv)
    MPI_Init(&argc, &argv);
    ::testing::InitGoogleMock(&argc, argv);

    if (have_openmpi && !LAMMPS_NS::Info::has_exceptions())
        std::cout << "Warning: using OpenMPI without exceptions. "
                     "Death tests will be skipped\n";

    // handle arguments passed via environment variable
    if (const char *var = getenv("TEST_ARGS")) {
        std::vector<std::string> env = split_words(var);
+25 −9
Original line number Diff line number Diff line
@@ -35,15 +35,29 @@
#include <cstring>
#include <mpi.h>

#if defined(OMPI_MAJOR_VERSION)
const bool have_openmpi = true;
#else
const bool have_openmpi = false;
#endif

using namespace LAMMPS_NS;
using ::testing::MatchesRegex;
using utils::split_words;

#define TEST_FAILURE(...)                \
#define TEST_FAILURE(errmsg, ...)                                 \
    if (Info::has_exceptions()) {                                 \
        ::testing::internal::CaptureStdout();                     \
        ASSERT_ANY_THROW({__VA_ARGS__});                          \
        auto mesg = ::testing::internal::GetCapturedStdout();     \
        ASSERT_THAT(mesg, MatchesRegex(errmsg));                  \
    } else {                                                      \
        if (!have_openmpi) {                                      \
            ::testing::internal::CaptureStdout();                 \
            ASSERT_DEATH({__VA_ARGS__}, "");                      \
            auto mesg = ::testing::internal::GetCapturedStdout(); \
            ASSERT_THAT(mesg, MatchesRegex(errmsg));              \
        }                                                         \
    }

// whether to print verbose output (i.e. not capturing LAMMPS screen output).
@@ -116,10 +130,8 @@ TEST_F(PotentialFileReaderTest, Sw_noconv)
    lmp->input->one("units real");
    if (!verbose) ::testing::internal::GetCapturedStdout();

    ::testing::internal::CaptureStdout();
    TEST_FAILURE(PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber", utils::REAL2METAL););
    std::string mesg = ::testing::internal::GetCapturedStdout();
    ASSERT_THAT(mesg, MatchesRegex(".*ERROR on proc.*potential.*requires metal units but real.*"));
    TEST_FAILURE(".*ERROR on proc.*potential.*requires metal units but real.*",
                 PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber", utils::REAL2METAL););
}

TEST_F(PotentialFileReaderTest, Comb)
@@ -291,6 +303,10 @@ int main(int argc, char **argv)
    MPI_Init(&argc, &argv);
    ::testing::InitGoogleMock(&argc, argv);

    if (have_openmpi && !LAMMPS_NS::Info::has_exceptions())
        std::cout << "Warning: using OpenMPI without exceptions. "
                     "Death tests will be skipped\n";

    // handle arguments passed via environment variable
    if (const char *var = getenv("TEST_ARGS")) {
        std::vector<std::string> env = split_words(var);