/*
+ * This file is part of the GROMACS molecular simulation package.
*
- * This source code is part of
+ * Copyright (c) 2010,2011,2012,2013,2014, 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.
*
- * G R O M A C S
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
*
- * GROningen MAchine for Chemical Simulations
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * 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.
+ * If you want to redistribute modifications to GROMACS, 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 http://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
+ * the research papers on the package. Check out http://www.gromacs.org.
*/
/*! \internal \file
* \brief
* Tests selection parsing and compilation.
*
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_selection
*/
-#include <gtest/gtest.h>
+#include "gmxpre.h"
+
+#include "gromacs/selection/selectioncollection.h"
-#include "gromacs/legacyheaders/smalloc.h"
-#include "gromacs/legacyheaders/statutil.h"
-#include "gromacs/legacyheaders/tpxio.h"
-#include "gromacs/legacyheaders/vec.h"
+#include <gtest/gtest.h>
+#include "gromacs/fileio/trx.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
-#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/indexutil.h"
#include "gromacs/selection/selection.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/flags.h"
#include "gromacs/utility/gmxregex.h"
#include "gromacs/utility/stringutil.h"
#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
#include "testutils/testfilemanager.h"
#include "testutils/testoptions.h"
+#include "toputils.h"
+
namespace
{
class SelectionCollectionTest : public ::testing::Test
{
public:
- static void SetUpTestCase();
-
static int s_debugLevel;
SelectionCollectionTest();
void setAtomCount(int natoms)
{
- ASSERT_NO_THROW(sc_.setTopology(NULL, natoms));
+ ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
}
void loadTopology(const char *filename);
-
- gmx::SelectionCollection sc_;
- gmx::SelectionList sel_;
- t_topology *top_;
- t_trxframe *frame_;
+ void setTopology();
+ void loadIndexGroups(const char *filename);
+
+ gmx::test::TopologyManager topManager_;
+ gmx::SelectionCollection sc_;
+ gmx::SelectionList sel_;
+ t_topology *top_;
+ t_trxframe *frame_;
+ gmx_ana_indexgrps_t *grps_;
};
int SelectionCollectionTest::s_debugLevel = 0;
-void SelectionCollectionTest::SetUpTestCase()
+// \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
+#ifndef DOXYGEN
+GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
{
- gmx::Options options(NULL, NULL);
- options.addOption(gmx::IntegerOption("seldebug").store(&s_debugLevel));
- gmx::test::parseTestOptions(&options);
+ options->addOption(gmx::IntegerOption("seldebug")
+ .store(&SelectionCollectionTest::s_debugLevel)
+ .description("Set selection debug level"));
}
-
+#endif
SelectionCollectionTest::SelectionCollectionTest()
- : top_(NULL), frame_(NULL)
+ : top_(NULL), frame_(NULL), grps_(NULL)
{
+ topManager_.requestFrame();
sc_.setDebugLevel(s_debugLevel);
sc_.setReferencePosType("atom");
sc_.setOutputPosType("atom");
}
-
SelectionCollectionTest::~SelectionCollectionTest()
{
- if (top_ != NULL)
- {
- free_t_atoms(&top_->atoms, TRUE);
- done_top(top_);
- sfree(top_);
- }
-
- if (frame_ != NULL)
+ if (grps_ != NULL)
{
- sfree(frame_->x);
- sfree(frame_);
+ gmx_ana_indexgrps_free(grps_);
}
}
-
void
SelectionCollectionTest::loadTopology(const char *filename)
{
- char title[STRLEN];
- int ePBC;
- rvec *xtop;
- matrix box;
-
- snew(top_, 1);
- read_tps_conf(gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
- title, top_, &ePBC, &xtop, NULL, box, FALSE);
+ topManager_.loadTopology(filename);
+ setTopology();
+}
- snew(frame_, 1);
- frame_->flags = TRX_NEED_X;
- frame_->natoms = top_->atoms.nr;
- frame_->bX = TRUE;
- snew(frame_->x, frame_->natoms);
- memcpy(frame_->x, xtop, sizeof(*frame_->x) * frame_->natoms);
- frame_->bBox = TRUE;
- copy_mat(box, frame_->box);
+void
+SelectionCollectionTest::setTopology()
+{
+ top_ = topManager_.topology();
+ frame_ = topManager_.frame();
- sfree(xtop);
+ ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
+}
- ASSERT_NO_THROW(sc_.setTopology(top_, -1));
+void
+SelectionCollectionTest::loadIndexGroups(const char *filename)
+{
+ GMX_RELEASE_ASSERT(grps_ == NULL,
+ "External groups can only be loaded once");
+ std::string fullpath =
+ gmx::test::TestFileManager::getInputFilePath(filename);
+ gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
+ sc_.setIndexGroups(grps_);
}
efTestPositionMapping = 1<<3,
efTestPositionMasses = 1<<4,
efTestPositionCharges = 1<<5,
+ efTestSelectionNames = 1<<6,
efDontTestCompiledAtoms = 1<<8
};
typedef gmx::FlagsTemplate<TestFlag> TestFlags;
void setFlags(TestFlags flags) { flags_ = flags; }
- template <size_t count>
- void runTest(int natoms, const char *const (&selections)[count])
- {
- runTest(natoms, selections, count);
- }
- template <size_t count>
- void runTest(const char *filename, const char *const (&selections)[count])
- {
- runTest(filename, selections, count);
- }
-
- template <size_t count>
- void runParser(const char *const (&selections)[count])
- {
- runParser(selections, count);
- }
-
+ void runParser(const gmx::ConstArrayRef<const char *> &selections);
void runCompiler();
void runEvaluate();
void runEvaluateFinal();
+ void runTest(int natoms,
+ const gmx::ConstArrayRef<const char *> &selections);
+ void runTest(const char *filename,
+ const gmx::ConstArrayRef<const char *> &selections);
+
private:
static void checkSelection(gmx::test::TestReferenceChecker *checker,
const gmx::Selection &sel, TestFlags flags);
- void runTest(int natoms, const char *const *selections, size_t count);
- void runTest(const char *filename, const char *const *selections,
- size_t count);
- void runParser(const char *const *selections, size_t count);
-
void checkCompiled();
gmx::test::TestReferenceData data_;
void
-SelectionCollectionDataTest::runParser(const char *const *selections,
- size_t count)
+SelectionCollectionDataTest::runParser(
+ const gmx::ConstArrayRef<const char *> &selections)
{
using gmx::test::TestReferenceChecker;
TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
size_t varcount = 0;
count_ = 0;
- for (size_t i = 0; i < count; ++i)
+ for (size_t i = 0; i < selections.size(); ++i)
{
SCOPED_TRACE(std::string("Parsing selection \"")
+ selections[i] + "\"");
gmx::SelectionList result;
- ASSERT_NO_THROW(result = sc_.parseFromString(selections[i]));
+ ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
sel_.insert(sel_.end(), result.begin(), result.end());
if (sel_.size() == count_)
{
TestReferenceChecker selcompound(
compound.checkCompound("ParsedSelection", id.c_str()));
selcompound.checkString(selections[i], "Input");
- selcompound.checkString(sel_[count_].name(), "Name");
+ if (flags_.test(efTestSelectionNames))
+ {
+ selcompound.checkString(sel_[count_].name(), "Name");
+ }
selcompound.checkString(sel_[count_].selectionText(), "Text");
selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
++count_;
void
SelectionCollectionDataTest::runCompiler()
{
- ASSERT_NO_THROW(sc_.compile());
+ ASSERT_NO_THROW_GMX(sc_.compile());
ASSERT_EQ(count_, sel_.size());
checkCompiled();
}
std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
TestReferenceChecker selcompound(
compound.checkCompound("Selection", id.c_str()));
+ if (flags_.test(efTestSelectionNames))
+ {
+ selcompound.checkString(sel_[i].name(), "Name");
+ }
if (!flags_.test(efDontTestCompiledAtoms))
{
checkSelection(&selcompound, sel_[i], flags_ & mask);
using gmx::test::TestReferenceChecker;
++framenr_;
- ASSERT_NO_THROW(sc_.evaluate(frame_, NULL));
+ ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
std::string frame = gmx::formatString("Frame%d", framenr_);
TestReferenceChecker compound(
checker_.checkCompound("EvaluatedSelections", frame.c_str()));
void
SelectionCollectionDataTest::runEvaluateFinal()
{
- ASSERT_NO_THROW(sc_.evaluateFinal(framenr_));
- if (!checker_.isWriteMode())
- {
- checkCompiled();
- }
+ ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
+ checkCompiled();
}
void
-SelectionCollectionDataTest::runTest(int natoms, const char * const *selections,
- size_t count)
+SelectionCollectionDataTest::runTest(
+ int natoms, const gmx::ConstArrayRef<const char *> &selections)
{
- ASSERT_NO_FATAL_FAILURE(runParser(selections, count));
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
void
-SelectionCollectionDataTest::runTest(const char *filename,
- const char * const *selections,
- size_t count)
+SelectionCollectionDataTest::runTest(
+ const char *filename, const gmx::ConstArrayRef<const char *> &selections)
{
- ASSERT_NO_FATAL_FAILURE(runParser(selections, count));
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
ASSERT_NO_FATAL_FAILURE(runCompiler());
if (flags_.test(efTestEvaluation))
TEST_F(SelectionCollectionTest, HandlesNoSelections)
{
EXPECT_FALSE(sc_.requiresTopology());
- EXPECT_NO_THROW(sc_.compile());
+ EXPECT_NO_THROW_GMX(sc_.compile());
}
TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
{
- ASSERT_NO_THROW(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
+ ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
ASSERT_EQ(2U, sel_.size());
- ASSERT_NO_THROW(sel_[0].setEvaluateVelocities(true));
- ASSERT_NO_THROW(sel_[1].setEvaluateVelocities(true));
- ASSERT_NO_THROW(sel_[0].setEvaluateForces(true));
- ASSERT_NO_THROW(sel_[1].setEvaluateForces(true));
- ASSERT_NO_THROW(sc_.compile());
+ ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
+ ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
+ ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
+ ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
+ ASSERT_NO_THROW_GMX(sc_.compile());
EXPECT_TRUE(sel_[0].hasVelocities());
EXPECT_TRUE(sel_[1].hasVelocities());
EXPECT_TRUE(sel_[0].hasForces());
TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
{
- ASSERT_NO_THROW(sel_ = sc_.parseFromFile(
- gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
+ ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
+ gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
// 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, HandlesAtypicalWhitespace)
+{
+ ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
+ ASSERT_EQ(2U, sel_.size());
+ EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
+ // TODO: Get rid of the trailing whitespace.
+ EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
+}
+
TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
{
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- EXPECT_THROW({
- sc_.parseFromString("resname ~ \"R[A\"");
- sc_.compile();
- }, gmx::InvalidInputError);
+ EXPECT_THROW_GMX({
+ sc_.parseFromString("resname ~ \"R[A\"");
+ sc_.compile();
+ }, gmx::InvalidInputError);
}
TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
if (!gmx::Regex::isSupported())
{
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- EXPECT_THROW({
- sc_.parseFromString("resname \"R[AD]\"");
- sc_.compile();
- }, gmx::InvalidInputError);
+ EXPECT_THROW_GMX({
+ sc_.parseFromString("resname \"R[AD]\"");
+ sc_.compile();
+ }, gmx::InvalidInputError);
}
}
TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
{
- EXPECT_THROW(sc_.parseFromString("mindist from atomnr 1 cutoff"),
- gmx::InvalidInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
+ gmx::InvalidInputError);
}
TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
{
- EXPECT_THROW(sc_.parseFromString("within 1 of"),
- gmx::InvalidInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
+ gmx::InvalidInputError);
}
TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
{
- EXPECT_THROW(sc_.parseFromString("within of atomnr 1"),
- gmx::InvalidInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
+ gmx::InvalidInputError);
}
-TEST_F(SelectionCollectionTest, HandlesHelpKeywordInInvalidContext)
+// TODO: Tests for more parser errors
+
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
{
- EXPECT_THROW(sc_.parseFromString("resname help"),
- gmx::InvalidInputError);
+ ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
+ EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
}
-// TODO: Tests for more parser errors
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
+{
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
+{
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
+ ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
+ EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
+}
-TEST_F(SelectionCollectionTest, RecoversFromUnknownGroupReference)
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
{
- ASSERT_NO_THROW(sc_.parseFromString("group \"foo\""));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
- EXPECT_THROW(sc_.setIndexGroups(NULL), gmx::InvalidInputError);
- EXPECT_THROW(sc_.compile(), gmx::APIError);
+ EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
+{
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
+ gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
+ gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
+ gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
+{
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
+ EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
+ // TODO: Add a separate check in the selection compiler for a safer API
+ // (makes sense in the future if the compiler needs the information for
+ // other purposes as well).
+ // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
+{
+ ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
+{
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
+ EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
+{
+ ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
+ EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
{
- ASSERT_NO_THROW(sc_.parseFromString("molindex 1 to 5"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- EXPECT_THROW(sc_.compile(), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
{
- ASSERT_NO_THROW(sc_.parseFromString("type CA"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- EXPECT_THROW(sc_.compile(), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
{
- ASSERT_NO_THROW(sc_.parseFromString("altloc A"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- EXPECT_THROW(sc_.compile(), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
{
- ASSERT_NO_THROW(sc_.parseFromString("all permute 1 1"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
- EXPECT_THROW(sc_.compile(), gmx::InvalidInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
{
- ASSERT_NO_THROW(sc_.parseFromString("all permute 3 2 1"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
- EXPECT_THROW(sc_.compile(), gmx::InconsistentInputError);
+ EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
{
- ASSERT_NO_THROW(sc_.parseFromString("x < 1.5 permute 3 2 1"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
+{
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ frame_->natoms = 8;
+ EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
+{
+ // Evaluating the positions will require atoms 1-9.
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 5 7"));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ frame_->natoms = 8;
+ EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
+{
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- ASSERT_NO_THROW(sc_.compile());
- EXPECT_THROW(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ frame_->natoms = 10;
+ EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
}
-// TODO: Tests for evaluation errors
+// TODO: Tests for more evaluation errors
/********************************************************************
runTest("simple.pdb", selections);
}
-// TODO: Add test for "molindex"
+TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
+{
+ static const char * const selections[] = {
+ "molindex 1 4",
+ "molecule 2 3 5"
+ };
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ topManager_.initUniformMolecules(3);
+ ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
TEST_F(SelectionCollectionDataTest, HandlesAtomname)
{
runTest("simple.pdb", selections);
}
-// TODO: Add test for atomtype
+
+TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
+{
+ static const char * const selections[] = {
+ "atomtype CA"
+ };
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ const char *const types[] = { "CA", "SA", "SB" };
+ topManager_.initAtomTypes(types);
+ ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
TEST_F(SelectionCollectionDataTest, HandlesChain)
{
* Tests for selection syntactic constructs
*/
+TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
+{
+ static const char * const selections[] = {
+ "\"GroupSelection\" group \"GrpA\"",
+ "\"DynamicSelection\" x < 5",
+ "y < 3"
+ };
+ setFlags(TestFlags() | efTestSelectionNames);
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ runTest(10, selections);
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
+{
+ static const char * const selections[] = {
+ "group \"GrpA\"",
+ "GrpB",
+ "1",
+ "group \"GrpB\" and resname RB"
+ };
+ setFlags(TestFlags() | efTestSelectionNames);
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ runTest("simple.gro", selections);
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
+{
+ static const char * const selections[] = {
+ "group \"GrpA\"",
+ "GrpB",
+ "1",
+ "group \"GrpB\" and resname RB"
+ };
+ setFlags(TestFlags() | efTestSelectionNames);
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
+{
+ static const char * const selections[] = {
+ "foo = group \"GrpUnsorted\"",
+ "group \"GrpUnsorted\"",
+ "GrpUnsorted",
+ "2",
+ "res_cog of group \"GrpUnsorted\"",
+ "group \"GrpUnsorted\" permute 2 1",
+ "foo"
+ };
+ setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
+ | efTestSelectionNames);
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ runTest("simple.gro", selections);
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
+{
+ static const char * const selections[] = {
+ "foo = group \"GrpUnsorted\"",
+ "group \"GrpUnsorted\"",
+ "GrpUnsorted",
+ "2",
+ "res_cog of group \"GrpUnsorted\"",
+ "group \"GrpUnsorted\" permute 2 1",
+ "foo"
+ };
+ ASSERT_NO_FATAL_FAILURE(runParser(selections));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+ ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
+
TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
{
static const char * const selections[] = {
}
+TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
+{
+ static const char * const selections[] = {
+ "same residue as (atomnr 3 5 13 or y > 5)",
+ "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
+ };
+ setFlags(TestFlags() | efTestEvaluation);
+ runTest("simple.gro", selections);
+}
+
+
+TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
+{
+ static const char * const selections[] = {
+ "none and x > 2",
+ "none and same resname as resnr 2"
+ };
+ runTest("simple.gro", selections);
+}
+
+
TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
{
static const char * const selections[] = {
}
+TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
+{
+ static const char * const selections[] = {
+ "foo = atomnr 1 to 8 and x < 10",
+ "atomnr 1 to 5 and y < 10 and foo",
+ "foo"
+ };
+ setFlags(TestFlags() | efTestEvaluation);
+ runTest("simple.gro", selections);
+}
+
+
} // namespace