/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
- * David van der Spoel, Berk Hess, Erik Lindahl, and including many
- * others, as listed in the AUTHORS file in the top-level source
- * directory and at http://www.gromacs.org.
+ * 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.
*
* GROMACS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_selection
*/
+#include "gmxpre.h"
+
+#include "gromacs/selection/selectioncollection.h"
+
#include <gtest/gtest.h>
+#include "gromacs/fileio/trx.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
#include "gromacs/selection/indexutil.h"
-#include "gromacs/selection/selectioncollection.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"
int SelectionCollectionTest::s_debugLevel = 0;
+// \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
+#ifndef DOXYGEN
GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
{
options->addOption(gmx::IntegerOption("seldebug")
.store(&SelectionCollectionTest::s_debugLevel)
.description("Set selection debug level"));
}
+#endif
SelectionCollectionTest::SelectionCollectionTest()
: top_(NULL), frame_(NULL), grps_(NULL)
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] + "\"");
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))
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"));
gmx::InvalidInputError);
}
-TEST_F(SelectionCollectionTest, HandlesHelpKeywordInInvalidContext)
-{
- EXPECT_THROW_GMX(sc_.parseFromString("resname help"),
- gmx::InvalidInputError);
-}
-
// TODO: Tests for more parser errors
TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
{
ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
- EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpUnsorted\""),
+ 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);
- EXPECT_THROW_GMX(sc_.parseFromString("2"), gmx::InconsistentInputError);
}
TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
{
- ASSERT_NO_THROW_GMX(sc_.parseFromString("group 2; group \"GrpUnsorted\""));
+ 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);
- EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
}
TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
}
-// TODO: Tests for evaluation errors
+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_GMX(sc_.compile());
+ frame_->natoms = 10;
+ EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
+}
+
+// TODO: Tests for more evaluation errors
/********************************************************************
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[] = {