*/
#include "gromacs/options/cmdlineparser.h"
+#include <cctype>
+
#include "gromacs/fatalerror/exceptions.h"
#include "gromacs/fatalerror/messagestringcollector.h"
#include "gromacs/options/optionsassigner.h"
}
void CommandLineParser::parse(int *argc, char *argv[])
+{
+ std::vector<std::string> commandLine;
+ for (int i = 0; i < *argc; ++i)
+ {
+ commandLine.push_back(argv[i]);
+ }
+ parse(&commandLine);
+}
+
+void CommandLineParser::parse(std::vector<std::string> *commandLine)
{
MessageStringCollector errors;
- int i = 1;
// Start in the discard phase to skip options that can't be understood.
bool bDiscard = true;
_impl->_assigner.start();
- while (i < *argc)
+ std::vector<std::string>::const_iterator arg;
+ for (arg = commandLine->begin() + 1; arg != commandLine->end(); ++arg)
{
- // Lone '-' is passed as a value.
- if (argv[i][0] == '-' && argv[i][1] != '\0')
+ // Lone '-' and numbers are passed as values.
+ if ((*arg)[0] == '-' && std::isalpha((*arg)[1]))
{
if (!bDiscard)
{
}
errors.finishContext();
}
- errors.startContext("In command-line option " + std::string(argv[i]));
+ errors.startContext("In command-line option " + *arg);
bDiscard = false;
try
{
- const char *name = &argv[i][1];
+ const char *name = arg->c_str() + 1;
_impl->_assigner.startOption(name);
}
catch (const UserInputError &ex)
{
try
{
- _impl->_assigner.appendValue(argv[i]);
+ _impl->_assigner.appendValue(*arg);
}
catch (const UserInputError &ex)
{
errors.append(ex.what());
}
}
- ++i;
}
if (!bDiscard)
{
#ifndef GMX_OPTIONS_CMDLINEPARSER_H
#define GMX_OPTIONS_CMDLINEPARSER_H
+#include <string>
+#include <vector>
+
#include "../utility/common.h"
namespace gmx
* Creates a command-line parser that sets values for options.
*
* \param[in] options Options object whose options should be set.
+ * \throws std::bad_alloc if out of memory.
*/
CommandLineParser(Options *options);
~CommandLineParser();
/*! \brief
- * Parses the command-line.
+ * Parses the command line.
*
- * \throws InvalidInputError if any errors were detected in the input.
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if any errors were detected in the input.
*
* All command-line arguments are parsed, and an aggregate exception
* with all the detected errors is thrown in the end.
+ *
+ * Currently, the input parameters are not modified, but this may
+ * change if/when support for parsing only part of the options is
+ * implemented.
*/
void parse(int *argc, char *argv[]);
+ /*! \brief
+ * Parses the command line from a std::vector.
+ *
+ * \param[in] commandLine Array of command-line strings.
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if any errors were detected in the input.
+ *
+ * \p commandLine should relate to the standard \c argv array
+ * one-to-one.
+ *
+ * This method is provided for convenience for cases where the command
+ * line needs to be stored before parsing.
+ *
+ * Currently, the input parameters are not modified, but this may
+ * change if/when support for parsing only part of the options is
+ * implemented.
+ *
+ * \see parse(int *, char *[])
+ */
+ void parse(std::vector<std::string> *commandLine);
private:
class Impl;
EXPECT_DOUBLE_EQ(2.7, _dvalues[0]);
}
+TEST_F(CommandLineParserTest, HandlesNegativeNumbers)
+{
+ const char *cmdline[] = {"-mvi", "1", "-2", "-mvd", "-2.7", NULL};
+ createArguments(cmdline);
+ ASSERT_NO_THROW(_parser.parse(&_argc, _argv));
+ ASSERT_NO_THROW(_options.finish());
+
+ ASSERT_EQ(2U, _ivalues.size());
+ EXPECT_EQ(1, _ivalues[0]);
+ EXPECT_EQ(-2, _ivalues[1]);
+ ASSERT_EQ(1U, _dvalues.size());
+ EXPECT_DOUBLE_EQ(-2.7, _dvalues[0]);
+}
+
} // namespace
#include "vec.h"
#include "gromacs/fatalerror/exceptions.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
#include "gromacs/selection/poscalc.h"
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selection.h"
#include "testutils/datapath.h"
#include "testutils/refdata.h"
+#include "testutils/testoptions.h"
namespace
{
class SelectionCollectionTest : public ::testing::Test
{
public:
+ static void SetUpTestCase();
+
+ static int s_debugLevel;
+
SelectionCollectionTest();
~SelectionCollectionTest();
t_trxframe *_frame;
};
+int SelectionCollectionTest::s_debugLevel = 0;
+
+void SelectionCollectionTest::SetUpTestCase()
+{
+ gmx::Options options(NULL, NULL);
+ options.addOption(gmx::IntegerOption("seldebug").store(&s_debugLevel));
+ gmx::test::parseTestOptions(&options);
+}
+
SelectionCollectionTest::SelectionCollectionTest()
: _top(NULL), _frame(NULL)
{
+ _sc.setDebugLevel(s_debugLevel);
_sc.setReferencePosType("atom");
_sc.setOutputPosType("atom");
}
set(TESTUTILS_HAVE_REFDATA FALSE)
-set(COMMON_SOURCES datapath.cpp refdata-common.cpp)
+set(COMMON_SOURCES datapath.cpp refdata-common.cpp testoptions.cpp)
if (GMX_USE_GTEST AND LIBXML2_FOUND)
include_directories(${GTEST_INCLUDE_DIRS})
list(APPEND COMMON_SOURCES refdata.cpp)
#include "refdata.h"
#include <cstring>
+#include <cstdio>
+
+#include <new>
#include "testutils/datapath.h"
}
-int initReferenceData(int *argc, char **argv)
+void initReferenceData(int *argc, char **argv)
{
int i, newi;
}
*argc = newi;
#ifdef TESTUTILS_HAVE_REFDATA
- internal::addGlobalReferenceDataEnvironment();
+ try
+ {
+ internal::addGlobalReferenceDataEnvironment();
+ }
+ catch (const std::bad_alloc &)
+ {
+ std::fprintf(stderr, "Out of memory\n");
+ std::exit(1);
+ }
#endif
-
- return 0;
}
} // namespace test
* can be used to change it.
* Recognized command-line arguments are removed from the list.
*
- * This function is automatically called by test_main_gtest.cpp and
- * test_main_gmock.cpp.
+ * Does not throw. Terminates the program with a non-zero error code if an
+ * error occurs.
+ *
+ * This function is automatically called by initTestUtils().
*/
-int initReferenceData(int *argc, char **argv);
+void initReferenceData(int *argc, char **argv);
/*! \cond internal */
/*! \internal \brief
* main() for unit tests that use Google C++ Mocking Framework.
*
* \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_testutils
*/
#include <gmock/gmock.h>
-#include "gromacs/fatalerror/errorcodes.h"
-#include "testutils/datapath.h"
-#include "testutils/refdata.h"
+#include "testutils/testoptions.h"
+
+#ifndef TEST_DATA_PATH
+//! Path to test input data directory (needs to be set by the build system).
+#define TEST_DATA_PATH 0
+#endif
/*! \brief
* Initializes unit testing with Google C++ Mocking Framework.
int main(int argc, char *argv[])
{
::testing::InitGoogleMock(&argc, argv);
-#ifdef TEST_DATA_PATH
- ::gmx::test::setTestDataPath(TEST_DATA_PATH);
- if (::gmx::test::initReferenceData(&argc, argv) != 0)
- {
- return 1;
- }
-#endif
- ::gmx::setFatalErrorHandler(NULL);
+ ::gmx::test::initTestUtils(TEST_DATA_PATH, &argc, argv);
return RUN_ALL_TESTS();
}
* main() for unit tests that use Google C++ Testing Framework.
*
* \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_testutils
*/
#include <gtest/gtest.h>
-#include "gromacs/fatalerror/errorcodes.h"
-#include "testutils/datapath.h"
-#include "testutils/refdata.h"
+#include "testutils/testoptions.h"
+
+#ifndef TEST_DATA_PATH
+//! Path to test input data directory (needs to be set by the build system).
+#define TEST_DATA_PATH 0
+#endif
/*! \brief
* Initializes unit testing with Google C++ Testing Framework.
int main(int argc, char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
-#ifdef TEST_DATA_PATH
- ::gmx::test::setTestDataPath(TEST_DATA_PATH);
- if (::gmx::test::initReferenceData(&argc, argv) != 0)
- {
- return 1;
- }
-#endif
- ::gmx::setFatalErrorHandler(NULL);
+ ::gmx::test::initTestUtils(TEST_DATA_PATH, &argc, argv);
return RUN_ALL_TESTS();
}
*/
explicit TestException(const std::string &reason)
: GromacsException(reason) {}
+ /*! \brief
+ * Creates a test exception based on another GromacsException object.
+ *
+ * \param[in] base Exception to wrap.
+ *
+ * \see GMX_THROW_WRAPPER_TESTEXCEPTION
+ */
+ explicit TestException(const GromacsException &base)
+ : GromacsException(base) {}
virtual int errorCode() const { return -1; }
};
+/*! \brief
+ * Macro for throwing a TestException that wraps another exception.
+ *
+ * \param[in] e Exception object to wrap.
+ *
+ * This macro is intended for wrapping exceptions thrown by Gromacs methods
+ * that are called from a test for the test's internal purposes. It wraps the
+ * exception in a TestException to make it possible to tell from the type of
+ * the exception whether the exception was thrown by the code under test, or by
+ * the test code itself.
+ *
+ * \p e should evaluate to an instance of an object derived from
+ * GromacsException.
+ *
+ * Typical usage in test code:
+ * \code
+try
+{
+ // some code that may throw a GromacsException
+}
+catch (const GromacsException &ex)
+{
+ GMX_THROW_WRAPPER_TESTEXCEPTION(ex);
+}
+ * \endcode
+ */
+#define GMX_THROW_WRAPPER_TESTEXCEPTION(e) \
+ throw ::boost::enable_current_exception(::gmx::test::TestException(e))
+
} // namespace test
} // namespace gmx
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in testoptions.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_testutils
+ */
+#include "testoptions.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include <new>
+#include <string>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+#include "gromacs/fatalerror/errorcodes.h"
+#include "gromacs/fatalerror/gmxassert.h"
+#include "gromacs/options/cmdlineparser.h"
+#include "gromacs/options/options.h"
+
+#include "datapath.h"
+#include "refdata.h"
+#include "testexceptions.h"
+
+static boost::scoped_ptr<std::vector<std::string> > s_commandLine;
+
+namespace gmx
+{
+namespace test
+{
+
+void initTestUtils(const char *dataPath, int *argc, char *argv[])
+{
+ if (dataPath != NULL)
+ {
+ setTestDataPath(dataPath);
+ }
+ initReferenceData(argc, argv);
+ try
+ {
+ boost::scoped_ptr<std::vector<std::string> > commandLine(
+ new std::vector<std::string>());
+ for (int i = 0; i < *argc; ++i)
+ {
+ commandLine->push_back(argv[i]);
+ }
+ swap(commandLine, s_commandLine);
+ }
+ catch (const std::bad_alloc &)
+ {
+ std::fprintf(stderr, "Out of memory\n");
+ std::exit(1);
+ }
+ ::gmx::setFatalErrorHandler(NULL);
+}
+
+void parseTestOptions(Options *options)
+{
+ GMX_RELEASE_ASSERT(s_commandLine.get() != NULL,
+ "Test options not initialized");
+ try
+ {
+ CommandLineParser(options).parse(s_commandLine.get());
+ options->finish();
+ }
+ catch (const GromacsException &ex)
+ {
+ GMX_THROW_WRAPPER_TESTEXCEPTION(ex);
+ }
+}
+
+} // namespace test
+} // namespace gmx
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Functions for accessing test command-line options.
+ *
+ * Functions in this header allow accessing command-line options passed to the
+ * test executable from tests. This can be used to, e.g., enable additional
+ * output for debugging purposes.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_TESTOPTIONS_H
+#define GMX_TESTUTILS_TESTOPTIONS_H
+
+namespace gmx
+{
+
+class Options;
+
+namespace test
+{
+
+/*! \libinternal \brief
+ * Initializes the test utilities library.
+ *
+ * Does not throw. Terminates the program with a non-zero error code if an
+ * error occurs.
+ *
+ * This function is automatically called by test_main_gtest.cpp and
+ * test_main_gmock.cpp.
+ */
+void initTestUtils(const char *dataPath, int *argc, char *argv[]);
+/*! \libinternal \brief
+ * Parses given options from the command line.
+ *
+ * \param[in] options Definition of options to parse.
+ * \throws std::bad_alloc if out of memory.
+ * \throws TestException if an error occurs in the parsing.
+ *
+ * This can be used from test or test fixture setup functions to initialize
+ * local variables. Although this means that the parameters are potentially
+ * parsed multiple times, the performance impact should not be significant.
+ *
+ * \inlibraryapi
+ */
+void parseTestOptions(Options *options);
+
+} // namespace test
+} // namespace gmx
+
+#endif