/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2012,2013,2014,2015,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
*/
#include "gmxpre.h"
-#include "testinit.h"
+#include "testutils/testinit.h"
#include <cstdio>
#include <cstdlib>
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/textwriter.h"
-#include "testutils/mpi-printer.h"
+#include "testutils/mpitest.h"
#include "testutils/refdata.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testfilemanager.h"
#include "testutils/testoptions.h"
+#include "mpi_printer.h"
+
namespace gmx
{
namespace test
*
* This context overrides the installationPrefix() implementation to always
* load data files from the source directory, as the test binaries are never
- * installed. It also support overriding the directory through a command-line
+ * installed. It also supports overriding the directory through a command-line
* option to the test binary.
*
* \ingroup module_testutils
*/
class TestProgramContext : public IProgramContext
{
- public:
- /*! \brief
- * Initializes a test program context.
- *
- * \param[in] context Current \Gromacs program context.
- */
- explicit TestProgramContext(const IProgramContext &context)
- : context_(context), dataPath_(CMAKE_SOURCE_DIR)
- {
- }
+public:
+ /*! \brief
+ * Initializes a test program context.
+ *
+ * \param[in] context Current \Gromacs program context.
+ */
+ explicit TestProgramContext(const IProgramContext& context) :
+ context_(context), dataPath_(CMAKE_SOURCE_DIR)
+ {
+ }
- /*! \brief
- * Sets the source directory root from which to look for data files.
- */
- void overrideSourceRoot(const std::string &sourceRoot)
- {
- dataPath_ = sourceRoot;
- }
+ /*! \brief
+ * Sets the source directory root from which to look for data files.
+ */
+ void overrideSourceRoot(const std::string& sourceRoot) { dataPath_ = sourceRoot; }
- virtual const char *programName() const
- {
- return context_.programName();
- }
- virtual const char *displayName() const
- {
- return context_.displayName();
- }
- virtual const char *fullBinaryPath() const
- {
- return context_.fullBinaryPath();
- }
- virtual InstallationPrefixInfo installationPrefix() const
- {
- return InstallationPrefixInfo(dataPath_.c_str(), true);
- }
- virtual const char *commandLine() const
- {
- return context_.commandLine();
- }
+ const char* programName() const override { return context_.programName(); }
+ const char* displayName() const override { return context_.displayName(); }
+ const char* fullBinaryPath() const override { return context_.fullBinaryPath(); }
+ InstallationPrefixInfo installationPrefix() const override
+ {
+ return InstallationPrefixInfo(dataPath_.c_str(), true);
+ }
+ const char* commandLine() const override { return context_.commandLine(); }
- private:
- const IProgramContext &context_;
- std::string dataPath_;
+private:
+ const IProgramContext& context_;
+ std::string dataPath_;
};
//! Prints the command-line options for the unit test binary.
-void printHelp(const Options &options)
+void printHelp(const Options& options)
{
- const std::string &program = getProgramContext().displayName();
+ const std::string& program = getProgramContext().displayName();
std::fprintf(stderr,
"\nYou can use the following GROMACS-specific command-line flags\n"
"to control the behavior of the tests:\n\n");
// Never releases ownership.
std::unique_ptr<TestProgramContext> g_testContext;
-} // namespace
+/*! \brief Makes GoogleTest non-failures more verbose
+ *
+ * By default, GoogleTest does not echo messages appended to explicit
+ * assertions of success with SUCCEEDED() e.g.
+ *
+ * GTEST_SKIP() << "reason why";
+ *
+ * produces no output. This test listener changes that behavior, so
+ * that the message is echoed.
+ *
+ * When run with multiple ranks, only the master rank should use this
+ * listener, else the output can be very noisy. */
+class SuccessListener : public testing::EmptyTestEventListener
+{
+ void OnTestPartResult(const testing::TestPartResult& result) override
+ {
+ if (result.type() == testing::TestPartResult::kSuccess)
+ {
+ printf("%s\n", result.message());
+ }
+ }
+};
+
+} // namespace
//! \cond internal
-void initTestUtils(const char *dataPath, const char *tempPath, bool usesMpi,
- bool usesHardwareDetection, int *argc, char ***argv)
+void initTestUtils(const char* dataPath,
+ const char* tempPath,
+ bool usesMpi,
+ bool usesHardwareDetection,
+ int* argc,
+ char*** argv)
{
-#ifndef NDEBUG
- gmx_feenableexcept();
-#endif
- const CommandLineProgramContext &context = initForCommandLine(argc, argv);
+ if (gmxShouldEnableFPExceptions())
+ {
+ gmx_feenableexcept();
+ }
+ const CommandLineProgramContext& context = initForCommandLine(argc, argv);
try
{
if (!usesMpi && gmx_node_num() > 1)
// continue with the master rank here.
if (gmx_node_rank() == 0)
{
- fprintf(stderr, "NOTE: You are running %s on %d MPI ranks, "
+ fprintf(stderr,
+ "NOTE: You are running %s on %d MPI ranks, "
"but it is does not contain MPI-enabled tests. "
"The test will now exit.\n",
- context.programName(), gmx_node_num());
+ context.programName(),
+ gmx_node_num());
}
finalizeForCommandLine();
std::exit(1);
{
callAddGlobalTestEnvironment();
}
- g_testContext.reset(new TestProgramContext(context));
+ g_testContext = std::make_unique<TestProgramContext>(context);
setProgramContext(g_testContext.get());
// Use the default finder that does not respect GMXLIB, since the tests
// generally can only get confused by a different set of data files.
::testing::InitGoogleMock(argc, *argv);
if (dataPath != nullptr)
{
- TestFileManager::setInputDataDirectory(
- Path::join(CMAKE_SOURCE_DIR, dataPath));
+ TestFileManager::setInputDataDirectory(Path::join(CMAKE_SOURCE_DIR, dataPath));
}
if (tempPath != nullptr)
{
TestFileManager::setGlobalOutputTempDirectory(tempPath);
}
+ TestFileManager::setTestSimulationDatabaseDirectory(GMX_TESTSIMULATIONDATABASE_DIR);
+
bool bHelp = false;
std::string sourceRoot;
+ bool echoReasons = false;
Options options;
// TODO: A single option that accepts multiple names would be nicer.
// Also, we recognize -help, but GTest doesn't, which leads to a bit
// unintuitive behavior.
- options.addOption(BooleanOption("h").store(&bHelp)
- .description("Print GROMACS-specific unit test options"));
+ options.addOption(BooleanOption("h").store(&bHelp).description(
+ "Print GROMACS-specific unit test options"));
options.addOption(BooleanOption("help").store(&bHelp).hidden());
options.addOption(BooleanOption("?").store(&bHelp).hidden());
// TODO: Make this into a FileNameOption (or a DirectoryNameOption).
- options.addOption(StringOption("src-root").store(&sourceRoot)
- .description("Override source tree location (for data files)"));
+ options.addOption(
+ StringOption("src-root").store(&sourceRoot).description("Override source tree location (for data files)"));
+ options.addOption(
+ BooleanOption("echo-reasons").store(&echoReasons).description("When succeeding or skipping a test, echo the reason"));
// The potential MPI test event listener must be initialized first,
// because it should appear in the start of the event listener list,
// before other event listeners that may generate test failures
CommandLineParser(&options).parse(argc, *argv);
options.finish();
}
- catch (const UserInputError &)
+ catch (const UserInputError&)
{
printHelp(options);
throw;
if (!sourceRoot.empty())
{
g_testContext->overrideSourceRoot(sourceRoot);
- TestFileManager::setInputDataDirectory(
- Path::join(sourceRoot, dataPath));
+ TestFileManager::setInputDataDirectory(Path::join(sourceRoot, dataPath));
+ }
+ // Echo success messages only from the master MPI rank
+ if (echoReasons && (gmx_node_rank() == 0))
+ {
+ testing::UnitTest::GetInstance()->listeners().Append(new SuccessListener);
}
}
- catch (const std::exception &ex)
+ catch (const std::exception& ex)
{
printFatalErrorMessage(stderr, ex);
int retcode = processExceptionAtExitForCommandLine(ex);