fun:__cxa_throw
}
+{
+ _Unwind_RaiseException
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:_Unwind_RaiseException
+ fun:__cxa_throw
+}
+
# Intel compiler on MacOS
{
__cilkrts_os_mutex_create
#include "gromacs/options/filenameoptioninfo.h"
#include "gromacs/options/options.h"
#include "gromacs/options/optionsvisitor.h"
+#include "gromacs/selection/selectionfileoptioninfo.h"
#include "gromacs/selection/selectionoptioninfo.h"
#include "gromacs/utility/format.h"
void ParameterWriter::visitOption(const OptionInfo &option)
{
if (option.isType<FileNameOptionInfo>()
+ || option.isType<SelectionFileOptionInfo>()
|| option.isType<SelectionOptionInfo>()
|| (!bShowHidden_ && option.isHidden()))
{
*
* \ingroup module_commandline
*/
-class SelectionParameterWriter : public OptionsTypeVisitor<SelectionOptionInfo>
+class SelectionParameterWriter : public OptionsVisitor
{
public:
//! Creates a helper object for writing selection parameters.
bool didOutput() const { return formatter_.didOutput(); }
virtual void visitSubSection(const Options §ion);
- virtual void visitOptionType(const SelectionOptionInfo &option);
+ virtual void visitOption(const OptionInfo &option);
private:
FILE *fp_;
iterator.acceptOptions(this);
}
-void SelectionParameterWriter::visitOptionType(const SelectionOptionInfo &option)
+void SelectionParameterWriter::visitOption(const OptionInfo &option)
{
+ if (!option.isType<SelectionFileOptionInfo>()
+ && !option.isType<SelectionOptionInfo>())
+ {
+ return;
+ }
+
formatter_.clear();
std::string name(formatString("-%s", option.name().c_str()));
formatter_.addColumnLine(0, name);
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/filenameoption.h"
#include "gromacs/options/options.h"
+#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
#include "gromacs/selection/selectioncollection.h"
.description("Output file description")
.filetype(eftPlot).outputFile());
+ options.addOption(SelectionFileOption("sf"));
options.addOption(SelectionOption("sel").description("Selection option"));
CommandLineHelpWriter writer(options);
*/
TEST_F(CommandLineHelpWriterTest, HandlesSelectionOptions)
{
+ using gmx::SelectionFileOption;
using gmx::SelectionOption;
gmx::Options options(NULL, NULL);
+ options.addOption(SelectionFileOption("sf"));
options.addOption(SelectionOption("refsel").required()
.description("Reference selection option"));
options.addOption(SelectionOption("sel").required().valueCount(2)
Selection Description
-----------------------------------
+-sf Provide selections from files
-sel Selection option
]]></String>
<String Name="HelpText"><![CDATA[
Selection Description
-----------------------------------
+-sf Provide selections from files
-refsel Reference selection option
resname SOL
-sel Selection option
void requestSelections(const std::string &name,
const std::string &descr,
SelectionOptionStorage *storage);
+ /*! \brief
+ * Assign selections from a list to pending requests.
+ *
+ * \param[in] selections List of selections to assign.
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if the assignment cannot be done
+ * (see parseRequestedFromFile() for documented conditions).
+ *
+ * Loops through \p selections and the pending requests lists in order,
+ * and for each requests, assigns the first yet unassigned selections
+ * from the list.
+ *
+ * Used to implement parseRequestedFromFile() and
+ * parseRequestedFromStdin().
+ */
+ void placeSelectionsInRequests(const SelectionList &selections);
/*! \brief
* Replace group references by group contents.
*
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
+#include "gromacs/utility/format.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/messagestringcollector.h"
}
+void SelectionCollection::Impl::placeSelectionsInRequests(
+ const SelectionList &selections)
+{
+ RequestsClearer clearRequestsOnExit(&_requests);
+
+ SelectionList::const_iterator first = selections.begin();
+ SelectionList::const_iterator last = first;
+ RequestList::const_iterator i;
+ // TODO: Improve error messages.
+ for (i = _requests.begin(); i != _requests.end(); ++i)
+ {
+ const SelectionRequest &request = *i;
+ if (request.count() > 0)
+ {
+ if (selections.end() - first < request.count())
+ {
+ GMX_THROW(InvalidInputError("Too few selections provided"));
+ }
+ last = first + request.count();
+ }
+ else
+ {
+ if (i != _requests.end() - 1)
+ {
+ GMX_THROW(InvalidInputError(
+ formatString("Request for selection '%s' must "
+ "not be followed by others",
+ request.name.c_str())));
+ }
+ last = selections.end();
+ }
+ SelectionList curr(first, last);
+ request.storage->addSelections(curr, true);
+ first = last;
+ }
+ if (last != selections.end())
+ {
+ GMX_THROW(InvalidInputError("Too many selections provided"));
+ }
+}
+
+
void SelectionCollection::Impl::resolveExternalGroups(
t_selelem *root, MessageStringCollector *errors)
{
void
-SelectionCollection::parseRequestedFromString(const std::string &str)
+SelectionCollection::parseRequestedFromFile(const std::string &filename)
{
- Impl::RequestsClearer clearRequestsOnExit(&_impl->_requests);
+ SelectionList selections;
+ parseFromFile(filename, &selections);
+ _impl->placeSelectionsInRequests(selections);
+}
+
+void
+SelectionCollection::parseRequestedFromString(const std::string &str)
+{
SelectionList selections;
parseFromString(str, &selections);
-
- SelectionList::const_iterator first = selections.begin();
- SelectionList::const_iterator last = first;
- Impl::RequestList::const_iterator i;
- for (i = _impl->_requests.begin(); i != _impl->_requests.end(); ++i)
- {
- const Impl::SelectionRequest &request = *i;
- if (request.count() > 0)
- {
- if (selections.end() - first < request.count())
- {
- GMX_THROW(InvalidInputError("Too few selections provided"));
- }
- last = first + request.count();
- }
- else
- {
- if (i != _impl->_requests.end() - 1)
- {
- GMX_THROW(APIError("Request for all selections not the last option"));
- }
- last = selections.end();
- }
- SelectionList curr(first, last);
- request.storage->addSelections(curr, true);
- first = last;
- }
- if (last != selections.end())
- {
- GMX_THROW(InvalidInputError("Too many selections provided"));
- }
+ _impl->placeSelectionsInRequests(selections);
}
{
yyscan_t scanner;
+ File file(filename, "r");
+ // TODO: Exception-safe way of using the lexer.
_gmx_sel_init_lexer(&scanner, &_impl->_sc, false, -1,
_impl->_bExternalGroupsSet,
_impl->_grps);
- File file(filename, "r");
_gmx_sel_set_lex_input_file(scanner, file.handle());
_impl->runParser(scanner, -1, output);
file.close();
*/
void parseRequestedFromStdin(bool bInteractive);
/*! \brief
- * Parses selection(s) from a string for options not yet provided.
+ * Parses selection(s) from a file for options not yet provided.
*
- * \param[in] str String to parse.
+ * \param[in] filename Name of the file to parse selections from.
* \throws unspecified Can throw any exception thrown by
- * parseFromString().
+ * parseFromFile().
* \throws std::bad_alloc if out of memory.
* \throws InvalidInputError if
- * - the number of selections in \p str doesn't match the number
- * requested.
+ * - the number of selections in \p filename doesn't match the
+ * number requested.
* - any selection uses a feature that is not allowed for the
* corresponding option.
- * \throws APIError if there is a request for any number of
- * selections that is not the last (in which case it is not
- * possible to determine which selections belong to which
- * request).
+ * - if there is a request for any number of selections that is
+ * not the last (in which case it is not possible to determine
+ * which selections belong to which request).
*
* This method behaves as parseRequestedFromStdin(), but reads the
- * selections from a string instead of standard input.
- * This method is mainly used for testing.
+ * selections from a file instead of standard input.
+ * This is used to implement SelectionFileOption.
*
* \see parseRequestedFromStdin()
*/
+ void parseRequestedFromFile(const std::string &filename);
+ /*! \brief
+ * Parses selection(s) from a string for options not yet provided.
+ *
+ * \param[in] str String to parse.
+ * \throws unspecified Can throw any exception thrown by
+ * parseFromString().
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError in same conditions as
+ * parseRequestedFromFile().
+ *
+ * This method behaves as parseRequestedFromFile(), but reads the
+ * selections from a string instead of a file.
+ * This method is mainly used for testing.
+ *
+ * \see parseRequestedFromFile()
+ */
void parseRequestedFromString(const std::string &str);
/*! \brief
* Parses selection(s) from standard input.
--- /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
+ * Declares gmx::SelectionFileOption.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONFILEOPTION_H
+#define GMX_SELECTION_SELECTIONFILEOPTION_H
+
+#include "../options/abstractoption.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Specifies a special option that provides selections from a file.
+ *
+ * This option is used internally by the command-line framework to implement
+ * file input for selections. The option takes a file name, and reads it in
+ * using SelectionCollection::parseRequestedFromFile(). This means that
+ * selections from the file are assigned to selection options that have been
+ * explicitly provided without values earlier on the command line.
+ *
+ * Public methods in this class do not throw.
+ *
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+class SelectionFileOption : public AbstractOption
+{
+ public:
+ //! Initializes an option with the given name.
+ explicit SelectionFileOption(const char *name);
+
+ private:
+ virtual AbstractOptionStoragePointer createStorage() const;
+};
+
+} // namespace gmx
+
+#endif
--- /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
+ * Declares gmx::SelectionFileOptionInfo.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONFILEOPTIONINFO_H
+#define GMX_SELECTION_SELECTIONFILEOPTIONINFO_H
+
+#include "../options/optioninfo.h"
+
+namespace gmx
+{
+
+class SelectionCollection;
+class SelectionFileOptionStorage;
+
+/*! \libinternal \brief
+ * Wrapper class for accessing and modifying selection file option information.
+ *
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+class SelectionFileOptionInfo : public OptionInfo
+{
+ public:
+ /*! \brief
+ * Creates option info object for given storage object.
+ *
+ * Does not throw.
+ */
+ explicit SelectionFileOptionInfo(SelectionFileOptionStorage *option);
+
+ /*! \brief
+ * Set selection collection into which this option adds selections.
+ *
+ * \param selections Selection collection to set.
+ *
+ * This must be called before values are added.
+ *
+ * Typically it is called through setSelectionCollectionForOptions(),
+ * which recursively sets the collection for all selection options in
+ * an Options object.
+ *
+ * Does not throw.
+ */
+ void setSelectionCollection(SelectionCollection *selections);
+
+ private:
+ SelectionFileOptionStorage &option();
+ const SelectionFileOptionStorage &option() const;
+};
+
+} // namespace gmx
+
+#endif
--- /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
+ * Declares gmx::SelectionFileOptionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONFILEOPTIONSTORAGE_H
+#define GMX_SELECTION_SELECTIONFILEOPTIONSTORAGE_H
+
+#include "../options/abstractoptionstorage.h"
+#include "selectionfileoptioninfo.h"
+
+namespace gmx
+{
+
+class SelectionCollection;
+class SelectionFileOption;
+
+/*! \internal \brief
+ * Implementation for a special option for reading selections from files.
+ *
+ * \ingroup module_selection
+ */
+class SelectionFileOptionStorage : public AbstractOptionStorage
+{
+ public:
+ /*! \brief
+ * Initializes the storage from option settings.
+ *
+ * \param[in] settings Storage settings.
+ */
+ SelectionFileOptionStorage(const SelectionFileOption &settings);
+
+ virtual OptionInfo &optionInfo() { return info_; }
+ virtual const char *typeString() const { return "file"; }
+ virtual int valueCount() const { return 0; }
+ virtual std::string formatValue(int /*i*/) const { return ""; }
+
+ //! \copydoc SelectionFileOptionInfo::setSelectionCollection()
+ void setSelectionCollection(SelectionCollection *selections)
+ {
+ sc_ = selections;
+ }
+
+ private:
+ virtual void clearSet();
+ virtual void convertValue(const std::string &value);
+ virtual void processSet();
+ virtual void processAll() {}
+
+ SelectionFileOptionInfo info_;
+ SelectionCollection *sc_;
+ bool bValueParsed_;
+};
+
+} // namespace gmx
+
+#endif
#include "gromacs/options/optionsvisitor.h"
#include "gromacs/selection/selection.h"
#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/messagestringcollector.h"
#include "selectioncollection-impl.h"
+#include "selectionfileoptionstorage.h"
#include "selectionoptionstorage.h"
namespace gmx
: MyBase(settings, OptionFlags() | efNoDefaultValue | efDontCheckMinimumCount),
_info(this), _sc(NULL), _selectionFlags(settings._selectionFlags)
{
+ GMX_RELEASE_ASSERT(!hasFlag(efMulti),
+ "allowMultiple() is not supported for selection options");
if (settings._infoPtr != NULL)
{
*settings._infoPtr = &_info;
GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
SelectionList selections;
- // TODO: Implement reading from a file.
_sc->parseFromString(value, &selections);
addSelections(selections, false);
}
void SelectionOptionStorage::processSetValues(ValueList *values)
{
- if (values->size() > 0 && values->size() < static_cast<size_t>(minValueCount()))
+ GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
+
+ if (values->size() == 0)
+ {
+ _sc->_impl->requestSelections(name(), description(), this);
+ }
+ else if (values->size() < static_cast<size_t>(minValueCount()))
{
GMX_THROW(InvalidInputError("Too few (valid) values provided"));
}
void SelectionOptionStorage::processAll()
{
- if ((isRequired() || isSet()) && valueCount() == 0)
+ if (isRequired() && !isSet())
{
GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
}
+/********************************************************************
+ * SelectionFileOptionStorage
+ */
+
+SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
+ : AbstractOptionStorage(settings, OptionFlags() | efMulti | efDontCheckMinimumCount),
+ info_(this), sc_(NULL), bValueParsed_(false)
+{
+}
+
+void SelectionFileOptionStorage::clearSet()
+{
+ bValueParsed_ = false;
+}
+
+void SelectionFileOptionStorage::convertValue(const std::string &value)
+{
+ GMX_RELEASE_ASSERT(sc_ != NULL, "Selection collection is not set");
+
+ if (bValueParsed_)
+ {
+ GMX_THROW(InvalidInputError("More than one file name provided"));
+ }
+ bValueParsed_ = true;
+ // TODO: Should we throw an InvalidInputError if the file does not exist?
+ sc_->parseRequestedFromFile(value);
+}
+
+void SelectionFileOptionStorage::processSet()
+{
+ if (!bValueParsed_)
+ {
+ GMX_THROW(InvalidInputError("No file name provided"));
+ }
+}
+
+
+/********************************************************************
+ * SelectionFileOptionInfo
+ */
+
+SelectionFileOptionInfo::SelectionFileOptionInfo(SelectionFileOptionStorage *option)
+ : OptionInfo(option)
+{
+}
+
+SelectionFileOptionStorage &SelectionFileOptionInfo::option()
+{
+ return static_cast<SelectionFileOptionStorage &>(OptionInfo::option());
+}
+
+const SelectionFileOptionStorage &SelectionFileOptionInfo::option() const
+{
+ return static_cast<const SelectionFileOptionStorage &>(OptionInfo::option());
+}
+
+void SelectionFileOptionInfo::setSelectionCollection(SelectionCollection *selections)
+{
+ option().setSelectionCollection(selections);
+}
+
+
+/********************************************************************
+ * SelectionFileOption
+ */
+
+SelectionFileOption::SelectionFileOption(const char *name)
+ : AbstractOption(name)
+{
+ setDescription("Provide selections from files");
+}
+
+AbstractOptionStoragePointer SelectionFileOption::createStorage() const
+{
+ return AbstractOptionStoragePointer(new SelectionFileOptionStorage(*this));
+}
+
+
/********************************************************************
* Global functions
*/
*
* \ingroup module_selection
*/
-class SelectionCollectionSetter : public OptionsModifyingTypeVisitor<SelectionOptionInfo>
+class SelectionCollectionSetter : public OptionsModifyingVisitor
{
public:
//! Construct a visitor that sets given selection collection.
iterator.acceptOptions(this);
}
- void visitOptionType(SelectionOptionInfo *option)
+ void visitOption(OptionInfo *option)
{
- option->setSelectionCollection(selections_);
+ SelectionOptionInfo *selOption
+ = option->toType<SelectionOptionInfo>();
+ if (selOption != NULL)
+ {
+ selOption->setSelectionCollection(selections_);
+ }
+ SelectionFileOptionInfo *selFileOption
+ = option->toType<SelectionFileOptionInfo>();
+ if (selFileOption != NULL)
+ {
+ selFileOption->setSelectionCollection(selections_);
+ }
}
private:
{ _infoPtr = infoPtr; return me(); }
private:
+ // Disable possibility to allow multiple occurrences, since it isn't
+ // implemented.
+ using MyBase::allowMultiple;
// Disable default value because it is impossible to provide a
// Selection object.
using MyBase::defaultValue;
*/
void setSelectionCollectionForOptions(Options *options,
SelectionCollection *selections);
-//! \endcond
} // namespace gmx
EXPECT_NO_THROW(_sc.compile());
}
+TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
+{
+ ASSERT_NO_THROW(_sc.parseFromFile(gmx::test::getTestFilePath("selfile.dat"),
+ &_sel));
+ // These should match the contents of selfile.dat
+ ASSERT_EQ(2U, _sel.size());
+ EXPECT_STREQ("resname RA RB", _sel[0].selectionText());
+ EXPECT_STREQ("resname RB RC", _sel[1].selectionText());
+}
+
TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
{
EXPECT_THROW(_sc.parseFromString("mindist from atomnr 1 cutoff", &_sel),
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
+#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/utility/exceptions.h"
+#include "testutils/datapath.h"
+
namespace
{
-class SelectionOptionTest : public ::testing::Test
+/********************************************************************
+ * Base fixture for tests in this file.
+ */
+
+class SelectionOptionTestBase : public ::testing::Test
{
public:
- SelectionOptionTest();
+ SelectionOptionTestBase();
void setCollection();
gmx::Options _options;
};
-SelectionOptionTest::SelectionOptionTest()
+SelectionOptionTestBase::SelectionOptionTestBase()
: _options(NULL, NULL)
{
_sc.setReferencePosType("atom");
_sc.setOutputPosType("atom");
}
-void SelectionOptionTest::setCollection()
+void SelectionOptionTestBase::setCollection()
{
setSelectionCollectionForOptions(&_options, &_sc);
}
+/********************************************************************
+ * Tests for SelectionOption
+ */
+
+typedef SelectionOptionTestBase SelectionOptionTest;
+
TEST_F(SelectionOptionTest, ParsesSimpleSelection)
{
gmx::Selection sel;
EXPECT_NO_THROW(_sc.parseRequestedFromString("resname RA RB; resname RB RC"));
}
+
+/********************************************************************
+ * Tests for SelectionFileOption
+ */
+
+class SelectionFileOptionTest : public SelectionOptionTestBase
+{
+ public:
+ SelectionFileOptionTest();
+};
+
+SelectionFileOptionTest::SelectionFileOptionTest()
+{
+ _options.addOption(gmx::SelectionFileOption("sf"));
+}
+
+
+TEST_F(SelectionFileOptionTest, HandlesSingleSelectionOptionFromFile)
+{
+ gmx::SelectionList sel;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel").storeVector(&sel).multiValue()));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_NO_THROW(assigner.appendValue(gmx::test::getTestFilePath("selfile.dat")));
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+
+ // These should match the contents of selfile.dat
+ ASSERT_EQ(2U, sel.size());
+ EXPECT_STREQ("resname RA RB", sel[0].selectionText());
+ EXPECT_STREQ("resname RB RC", sel[1].selectionText());
+}
+
+
+TEST_F(SelectionFileOptionTest, HandlesTwoSeparateSelectionOptions)
+{
+ gmx::SelectionList sel1;
+ gmx::SelectionList sel2;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel1").storeVector(&sel1).multiValue()));
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel2").storeVector(&sel2).multiValue()));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ std::string value(gmx::test::getTestFilePath("selfile.dat"));
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel1"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_NO_THROW(assigner.appendValue(value));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sel2"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_NO_THROW(assigner.appendValue(value));
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+
+ // These should match the contents of selfile.dat
+ ASSERT_EQ(2U, sel1.size());
+ EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
+ EXPECT_STREQ("resname RB RC", sel1[1].selectionText());
+ ASSERT_EQ(2U, sel2.size());
+ EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
+ EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
+}
+
+
+TEST_F(SelectionFileOptionTest, HandlesTwoSelectionOptionsFromSingleFile)
+{
+ gmx::SelectionList sel1;
+ gmx::SelectionList sel2;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel1").storeVector(&sel1)));
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel2").storeVector(&sel2)));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ std::string value(gmx::test::getTestFilePath("selfile.dat"));
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel1"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sel2"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_NO_THROW(assigner.appendValue(value));
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+
+ // These should match the contents of selfile.dat
+ ASSERT_EQ(1U, sel1.size());
+ EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
+ ASSERT_EQ(1U, sel2.size());
+ EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
+}
+
+
+TEST_F(SelectionFileOptionTest, GivesErrorWithNoFile)
+{
+ gmx::SelectionList sel;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel").storeVector(&sel).multiValue()));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+}
+
+
+TEST_F(SelectionFileOptionTest, GivesErrorWithNonExistentFile)
+{
+ gmx::SelectionList sel;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel").storeVector(&sel).multiValue()));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ // TODO: Should this be changed to an InvalidInputError?
+ EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::FileIOError);
+ EXPECT_THROW(assigner.appendValue(gmx::test::getTestFilePath("selfile.dat")),
+ gmx::InvalidInputError);
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+}
+
+
+TEST_F(SelectionFileOptionTest, GivesErrorWithMultipleFiles)
+{
+ gmx::SelectionList sel;
+ using gmx::SelectionOption;
+ ASSERT_NO_THROW(_options.addOption(
+ SelectionOption("sel").storeVector(&sel).multiValue()));
+ setCollection();
+
+ gmx::OptionsAssigner assigner(&_options);
+ EXPECT_NO_THROW(assigner.start());
+ ASSERT_NO_THROW(assigner.startOption("sel"));
+ EXPECT_NO_THROW(assigner.finishOption());
+ ASSERT_NO_THROW(assigner.startOption("sf"));
+ EXPECT_NO_THROW(assigner.appendValue(gmx::test::getTestFilePath("selfile.dat")));
+ EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::InvalidInputError);
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(_options.finish());
+}
+
} // namespace
--- /dev/null
+resname RA RB;
+resname RB RC;
#include "gromacs/options/options.h"
#include "gromacs/selection/indexutil.h"
#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/trajectoryanalysis/analysissettings.h"
#include "gromacs/trajectoryanalysis/runnercommon.h"
#include "gromacs/utility/exceptions.h"
.filetype(eftIndex).inputFile()
.store(&_impl->_ndxfile)
.description("Extra index groups"));
+ options.addOption(SelectionFileOption("sf"));
// Add options for trajectory time control.
options.addOption(DoubleOption("b").store(&_impl->_startTime).timeValue()
_options.setDescription(concatenateStrings(desc));
_options.addOption(SelectionOption("select").storeVector(&_selections)
- .required().multiValue().allowMultiple()
+ .required().multiValue()
.description("Selections to test"));
_options.addOption(IntegerOption("pmax").store(&_nmaxind)
.description("Maximum number of indices to print in lists (-1 = print all)"));