2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Tests selection parsing and compilation.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
44 #include "gromacs/selection/selectioncollection.h"
46 #include <gtest/gtest.h>
48 #include "gromacs/options/basicoptions.h"
49 #include "gromacs/options/ioptionscontainer.h"
50 #include "gromacs/selection/indexutil.h"
51 #include "gromacs/selection/selection.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/trajectory/trajectoryframe.h"
54 #include "gromacs/utility/arrayref.h"
55 #include "gromacs/utility/exceptions.h"
56 #include "gromacs/utility/flags.h"
57 #include "gromacs/utility/gmxregex.h"
58 #include "gromacs/utility/stringutil.h"
60 #include "testutils/interactivetest.h"
61 #include "testutils/refdata.h"
62 #include "testutils/testasserts.h"
63 #include "testutils/testfilemanager.h"
64 #include "testutils/testoptions.h"
71 /********************************************************************
72 * Test fixture for selection testing
75 class SelectionCollectionTest : public ::testing::Test
78 static int s_debugLevel;
80 SelectionCollectionTest();
81 ~SelectionCollectionTest() override;
83 void setAtomCount(int natoms)
85 ASSERT_NO_THROW_GMX(sc_.setTopology(nullptr, natoms));
87 void loadTopology(const char *filename);
89 void loadIndexGroups(const char *filename);
91 gmx::test::TopologyManager topManager_;
92 gmx::SelectionCollection sc_;
93 gmx::SelectionList sel_;
94 gmx_ana_indexgrps_t *grps_;
97 int SelectionCollectionTest::s_debugLevel = 0;
99 // cond/endcond do not seem to work here with Doxygen 1.8.5 parser.
101 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
103 options->addOption(gmx::IntegerOption("seldebug")
104 .store(&SelectionCollectionTest::s_debugLevel)
105 .description("Set selection debug level"));
109 SelectionCollectionTest::SelectionCollectionTest()
112 topManager_.requestFrame();
113 sc_.setDebugLevel(s_debugLevel);
114 sc_.setReferencePosType("atom");
115 sc_.setOutputPosType("atom");
118 SelectionCollectionTest::~SelectionCollectionTest()
120 if (grps_ != nullptr)
122 gmx_ana_indexgrps_free(grps_);
127 SelectionCollectionTest::loadTopology(const char *filename)
129 topManager_.loadTopology(filename);
134 SelectionCollectionTest::setTopology()
136 ASSERT_NO_THROW_GMX(sc_.setTopology(topManager_.topology(), -1));
140 SelectionCollectionTest::loadIndexGroups(const char *filename)
142 GMX_RELEASE_ASSERT(grps_ == nullptr,
143 "External groups can only be loaded once");
144 std::string fullpath =
145 gmx::test::TestFileManager::getInputFilePath(filename);
146 gmx_ana_indexgrps_init(&grps_, nullptr, fullpath.c_str());
147 sc_.setIndexGroups(grps_);
151 /********************************************************************
152 * Test fixture for interactive SelectionCollection tests
155 class SelectionCollectionInteractiveTest : public SelectionCollectionTest
158 SelectionCollectionInteractiveTest()
159 : helper_(data_.rootChecker())
163 void runTest(int count, bool bInteractive,
164 const gmx::ArrayRef<const char *const> &input);
166 gmx::test::TestReferenceData data_;
167 gmx::test::InteractiveTestHelper helper_;
170 void SelectionCollectionInteractiveTest::runTest(
171 int count, bool bInteractive,
172 const gmx::ArrayRef<const char *const> &inputLines)
174 helper_.setInputLines(inputLines);
175 // TODO: Check something about the returned selections as well.
176 ASSERT_NO_THROW_GMX(sc_.parseInteractive(
177 count, &helper_.inputStream(),
178 bInteractive ? &helper_.outputStream() : nullptr,
179 "for test context"));
180 helper_.checkSession();
184 /********************************************************************
185 * Test fixture for selection testing with reference data
188 class SelectionCollectionDataTest : public SelectionCollectionTest
193 efTestEvaluation = 1<<0,
194 efTestPositionAtoms = 1<<1,
195 efTestPositionCoordinates = 1<<2,
196 efTestPositionMapping = 1<<3,
197 efTestPositionMasses = 1<<4,
198 efTestPositionCharges = 1<<5,
199 efTestSelectionNames = 1<<6,
200 efDontTestCompiledAtoms = 1<<8
202 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
204 SelectionCollectionDataTest()
205 : checker_(data_.rootChecker()), count_(0), framenr_(0)
209 void setFlags(TestFlags flags) { flags_ = flags; }
211 void runParser(const gmx::ArrayRef<const char *const> &selections);
214 void runEvaluateFinal();
216 void runTest(int natoms,
217 const gmx::ArrayRef<const char *const> &selections);
218 void runTest(const char *filename,
219 const gmx::ArrayRef<const char *const> &selections);
222 static void checkSelection(gmx::test::TestReferenceChecker *checker,
223 const gmx::Selection &sel, TestFlags flags);
225 void checkCompiled();
227 gmx::test::TestReferenceData data_;
228 gmx::test::TestReferenceChecker checker_;
236 SelectionCollectionDataTest::checkSelection(
237 gmx::test::TestReferenceChecker *checker,
238 const gmx::Selection &sel, TestFlags flags)
240 using gmx::test::TestReferenceChecker;
243 gmx::ArrayRef<const int> atoms = sel.atomIndices();
244 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
246 if (flags.test(efTestPositionAtoms)
247 || flags.test(efTestPositionCoordinates)
248 || flags.test(efTestPositionMapping)
249 || flags.test(efTestPositionMasses)
250 || flags.test(efTestPositionCharges))
252 TestReferenceChecker compound(
253 checker->checkSequenceCompound("Positions", sel.posCount()));
254 for (int i = 0; i < sel.posCount(); ++i)
256 TestReferenceChecker poscompound(compound.checkCompound("Position", nullptr));
257 const gmx::SelectionPosition &p = sel.position(i);
258 if (flags.test(efTestPositionAtoms))
260 gmx::ArrayRef<const int> atoms = p.atomIndices();
261 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
263 if (flags.test(efTestPositionCoordinates))
265 poscompound.checkVector(p.x(), "Coordinates");
267 if (flags.test(efTestPositionMapping))
269 poscompound.checkInteger(p.refId(), "RefId");
270 poscompound.checkInteger(p.mappedId(), "MappedId");
272 if (flags.test(efTestPositionMasses))
274 poscompound.checkReal(p.mass(), "Mass");
276 if (flags.test(efTestPositionCharges))
278 poscompound.checkReal(p.charge(), "Charge");
286 SelectionCollectionDataTest::runParser(
287 const gmx::ArrayRef<const char *const> &selections)
289 using gmx::test::TestReferenceChecker;
291 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
294 for (gmx::index i = 0; i < selections.ssize(); ++i)
296 SCOPED_TRACE(std::string("Parsing selection \"")
297 + selections[i] + "\"");
298 gmx::SelectionList result;
299 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
300 sel_.insert(sel_.end(), result.begin(), result.end());
301 if (sel_.size() == count_)
303 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
304 TestReferenceChecker varcompound(
305 compound.checkCompound("ParsedVariable", id.c_str()));
306 varcompound.checkString(selections[i], "Input");
311 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
312 TestReferenceChecker selcompound(
313 compound.checkCompound("ParsedSelection", id.c_str()));
314 selcompound.checkString(selections[i], "Input");
315 if (flags_.test(efTestSelectionNames))
317 selcompound.checkString(sel_[count_].name(), "Name");
319 selcompound.checkString(sel_[count_].selectionText(), "Text");
320 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
328 SelectionCollectionDataTest::runCompiler()
330 ASSERT_NO_THROW_GMX(sc_.compile());
331 ASSERT_EQ(count_, sel_.size());
337 SelectionCollectionDataTest::checkCompiled()
339 using gmx::test::TestReferenceChecker;
340 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
342 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
343 for (size_t i = 0; i < count_; ++i)
345 SCOPED_TRACE(std::string("Checking selection \"") +
346 sel_[i].selectionText() + "\"");
347 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
348 TestReferenceChecker selcompound(
349 compound.checkCompound("Selection", id.c_str()));
350 if (flags_.test(efTestSelectionNames))
352 selcompound.checkString(sel_[i].name(), "Name");
354 if (!flags_.test(efDontTestCompiledAtoms))
356 checkSelection(&selcompound, sel_[i], flags_ & mask);
363 SelectionCollectionDataTest::runEvaluate()
365 using gmx::test::TestReferenceChecker;
368 ASSERT_NO_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr));
369 std::string frame = gmx::formatString("Frame%d", framenr_);
370 TestReferenceChecker compound(
371 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
372 for (size_t i = 0; i < count_; ++i)
374 SCOPED_TRACE(std::string("Checking selection \"") +
375 sel_[i].selectionText() + "\"");
376 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
377 TestReferenceChecker selcompound(
378 compound.checkCompound("Selection", id.c_str()));
379 checkSelection(&selcompound, sel_[i], flags_);
385 SelectionCollectionDataTest::runEvaluateFinal()
387 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
393 SelectionCollectionDataTest::runTest(
394 int natoms, const gmx::ArrayRef<const char *const> &selections)
396 ASSERT_NO_FATAL_FAILURE(runParser(selections));
397 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
398 ASSERT_NO_FATAL_FAILURE(runCompiler());
403 SelectionCollectionDataTest::runTest(
404 const char *filename, const gmx::ArrayRef<const char *const> &selections)
406 ASSERT_NO_FATAL_FAILURE(runParser(selections));
407 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
408 ASSERT_NO_FATAL_FAILURE(runCompiler());
409 if (flags_.test(efTestEvaluation))
411 ASSERT_NO_FATAL_FAILURE(runEvaluate());
412 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
417 /********************************************************************
418 * Tests for SelectionCollection functionality without reference data
421 TEST_F(SelectionCollectionTest, HandlesNoSelections)
423 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
424 EXPECT_NO_THROW_GMX(sc_.compile());
425 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
428 TEST_F(SelectionCollectionTest, HandlesNoSelectionsWithDefaultPositionType)
430 EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_com"));
431 EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
432 EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
433 EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_cog"));
434 EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
435 EXPECT_FALSE(sc_.requiredTopologyProperties().needsMasses);
436 ASSERT_NO_THROW_GMX(sc_.parseFromString("atom of atomnr 1 to 10"));
437 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
438 ASSERT_NO_THROW_GMX(sc_.compile());
439 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
442 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
444 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
445 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
446 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
447 ASSERT_EQ(2U, sel_.size());
448 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
449 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
450 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
451 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
452 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
453 ASSERT_NO_THROW_GMX(sc_.compile());
454 EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
455 EXPECT_TRUE(sel_[0].hasVelocities());
456 EXPECT_TRUE(sel_[1].hasVelocities());
457 EXPECT_TRUE(sel_[0].hasForces());
458 EXPECT_TRUE(sel_[1].hasForces());
461 TEST_F(SelectionCollectionTest, HandlesForceRequestForCenterOfGeometry)
463 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("res_cog of atomnr 1 to 10"));
464 EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
465 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
466 ASSERT_EQ(1U, sel_.size());
467 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
468 // In principle, the code could know here that the masses are required, but
469 // currently it only knows this after compilation.
470 ASSERT_NO_THROW_GMX(sc_.compile());
471 EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
472 EXPECT_TRUE(sel_[0].hasForces());
475 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
477 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
478 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
479 // These should match the contents of selfile.dat
480 ASSERT_EQ(2U, sel_.size());
481 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
482 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
485 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
487 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
488 ASSERT_EQ(2U, sel_.size());
489 EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
490 // TODO: Get rid of the trailing whitespace.
491 EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
494 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
496 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
498 sc_.parseFromString("resname ~ \"R[A\"");
500 }, gmx::InvalidInputError);
503 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
505 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
506 gmx::InvalidInputError);
509 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
511 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
512 gmx::InvalidInputError);
515 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
517 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
518 gmx::InvalidInputError);
521 // TODO: Tests for more parser errors
523 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
525 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(nullptr));
526 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
527 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
530 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
532 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
533 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
534 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
537 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
539 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
540 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
541 EXPECT_THROW_GMX(sc_.setIndexGroups(nullptr), gmx::InconsistentInputError);
542 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
545 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
547 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
548 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
549 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
550 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
553 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
555 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
556 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
557 gmx::InconsistentInputError);
558 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
559 gmx::InconsistentInputError);
560 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
561 gmx::InconsistentInputError);
564 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
566 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
567 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
568 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
569 // TODO: Add a separate check in the selection compiler for a safer API
570 // (makes sense in the future if the compiler needs the information for
571 // other purposes as well).
572 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
575 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
577 ASSERT_NO_THROW_GMX(sc_.setTopology(nullptr, 5));
578 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
579 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
582 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
584 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
585 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
586 EXPECT_THROW_GMX(sc_.setTopology(nullptr, 5), gmx::InconsistentInputError);
589 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
591 ASSERT_NO_THROW_GMX(sc_.setTopology(nullptr, 5));
592 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
593 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
596 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
598 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
599 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
600 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
603 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
605 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
606 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
607 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
610 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
612 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
613 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
614 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
617 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
619 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
620 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
621 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
624 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
626 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
627 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
628 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
631 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
633 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
634 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
635 ASSERT_NO_THROW_GMX(sc_.compile());
636 EXPECT_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr), gmx::InconsistentInputError);
639 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
641 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
642 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
643 ASSERT_NO_THROW_GMX(sc_.compile());
644 topManager_.frame()->natoms = 8;
645 EXPECT_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr), gmx::InconsistentInputError);
648 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
650 const int index[] = { 1, 2, 3, 9 };
651 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 4 7 10"));
652 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
653 ASSERT_NO_THROW_GMX(sc_.compile());
654 topManager_.initFrameIndices(index);
655 EXPECT_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr), gmx::InconsistentInputError);
658 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
660 const int index[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11 };
661 // Evaluating the positions will require atoms 1-3, 7-12.
662 ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_cog of atomnr 2 7 11"));
663 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
664 ASSERT_NO_THROW_GMX(sc_.compile());
665 topManager_.initFrameIndices(index);
666 EXPECT_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr), gmx::InconsistentInputError);
669 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets4)
671 ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
672 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
673 ASSERT_NO_THROW_GMX(sc_.compile());
674 topManager_.frame()->natoms = 10;
675 EXPECT_THROW_GMX(sc_.evaluate(topManager_.frame(), nullptr), gmx::InconsistentInputError);
678 // TODO: Tests for more evaluation errors
680 /********************************************************************
681 * Tests for interactive selection input
684 TEST_F(SelectionCollectionInteractiveTest, HandlesBasicInput)
686 const char *const input[] = {
689 "\"Name\" resname RC"
691 runTest(-1, true, input);
694 TEST_F(SelectionCollectionInteractiveTest, HandlesContinuation)
696 const char *const input[] = {
700 runTest(-1, true, input);
703 TEST_F(SelectionCollectionInteractiveTest, HandlesSingleSelectionInput)
705 const char *const input[] = {
709 runTest(1, true, input);
712 TEST_F(SelectionCollectionInteractiveTest, HandlesTwoSelectionInput)
714 const char *const input[] = {
718 runTest(2, true, input);
721 TEST_F(SelectionCollectionInteractiveTest, HandlesStatusWithGroups)
723 const char *const input[] = {
727 loadIndexGroups("simple.ndx");
728 runTest(-1, true, input);
731 TEST_F(SelectionCollectionInteractiveTest, HandlesStatusWithExistingSelections)
733 const char *const input[] = {
739 ASSERT_NO_THROW_GMX(sc_.parseFromString("foo = resname RA"));
740 ASSERT_NO_THROW_GMX(sc_.parseFromString("resname RB"));
741 runTest(-1, true, input);
744 TEST_F(SelectionCollectionInteractiveTest, HandlesSingleSelectionInputStatus)
746 const char *const input[] = {
751 runTest(1, true, input);
754 TEST_F(SelectionCollectionInteractiveTest, HandlesTwoSelectionInputStatus)
756 const char *const input[] = {
757 "\"Sel\" resname RA",
761 runTest(2, true, input);
764 TEST_F(SelectionCollectionInteractiveTest, HandlesMultiSelectionInputStatus)
766 const char *const input[] = {
767 "\"Sel\" resname RA",
768 "\"Sel2\" resname RB",
771 runTest(-1, true, input);
774 TEST_F(SelectionCollectionInteractiveTest, HandlesNoFinalNewline)
776 // TODO: There is an extra prompt printed after the input is finished; it
777 // would be cleaner not to have it, but it's only a cosmetic issue.
778 const char *const input[] = {
781 helper_.setLastNewline(false);
782 runTest(-1, true, input);
785 TEST_F(SelectionCollectionInteractiveTest, HandlesEmptySelections)
787 const char *const input[] = {
793 runTest(-1, true, input);
796 TEST_F(SelectionCollectionInteractiveTest, HandlesMultipleSelectionsOnLine)
798 const char *const input[] = {
799 "resname RA; resname RB and \\",
802 runTest(2, true, input);
805 TEST_F(SelectionCollectionInteractiveTest, HandlesNoninteractiveInput)
807 const char *const input[] = {
810 "\"Name\" resname RC"
812 runTest(-1, false, input);
815 TEST_F(SelectionCollectionInteractiveTest, HandlesSingleSelectionInputNoninteractively)
817 const char *const input[] = {
821 runTest(1, false, input);
825 /********************************************************************
826 * Tests for selection keywords
829 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
831 static const char * const selections[] = {
835 runTest(10, selections);
838 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
840 static const char * const selections[] = {
841 "atomnr 1 to 3 6 to 8",
845 runTest(10, selections);
848 TEST_F(SelectionCollectionDataTest, HandlesResnr)
850 static const char * const selections[] = {
854 runTest("simple.gro", selections);
857 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
859 static const char * const selections[] = {
863 runTest("simple.pdb", selections);
866 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
868 static const char * const selections[] = {
872 ASSERT_NO_FATAL_FAILURE(runParser(selections));
873 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
874 topManager_.initUniformMolecules(3);
875 ASSERT_NO_FATAL_FAILURE(setTopology());
876 ASSERT_NO_FATAL_FAILURE(runCompiler());
879 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
881 static const char * const selections[] = {
885 runTest("simple.gro", selections);
888 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
890 static const char * const selections[] = {
896 runTest("simple.pdb", selections);
900 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
902 static const char * const selections[] = {
905 ASSERT_NO_FATAL_FAILURE(runParser(selections));
906 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
907 const char *const types[] = { "CA", "SA", "SB" };
908 topManager_.initAtomTypes(types);
909 ASSERT_NO_FATAL_FAILURE(setTopology());
910 ASSERT_NO_FATAL_FAILURE(runCompiler());
913 TEST_F(SelectionCollectionDataTest, HandlesChain)
915 static const char * const selections[] = {
919 runTest("simple.pdb", selections);
922 TEST_F(SelectionCollectionDataTest, HandlesMass)
924 static const char * const selections[] = {
927 ASSERT_NO_FATAL_FAILURE(runParser(selections));
928 EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
929 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
930 t_atoms &atoms = topManager_.atoms();
931 for (int i = 0; i < atoms.nr; ++i)
933 atoms.atom[i].m = 1.0 + i;
935 atoms.haveMass = TRUE;
936 ASSERT_NO_FATAL_FAILURE(setTopology());
937 ASSERT_NO_FATAL_FAILURE(runCompiler());
940 TEST_F(SelectionCollectionDataTest, HandlesCharge)
942 static const char * const selections[] = {
945 ASSERT_NO_FATAL_FAILURE(runParser(selections));
946 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
947 t_atoms &atoms = topManager_.atoms();
948 for (int i = 0; i < atoms.nr; ++i)
950 atoms.atom[i].q = i / 10.0;
952 // Ensure exact representation of 0.5 is used, so that the test is
954 atoms.atom[5].q = 0.5;
955 atoms.haveCharge = TRUE;
956 ASSERT_NO_FATAL_FAILURE(setTopology());
957 ASSERT_NO_FATAL_FAILURE(runCompiler());
960 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
962 static const char * const selections[] = {
966 runTest("simple.pdb", selections);
969 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
971 static const char * const selections[] = {
975 runTest("simple.pdb", selections);
978 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
980 static const char * const selections[] = {
984 runTest("simple.pdb", selections);
987 TEST_F(SelectionCollectionDataTest, HandlesBeta)
989 static const char * const selections[] = {
993 runTest("simple.pdb", selections);
996 TEST_F(SelectionCollectionDataTest, HandlesResname)
998 static const char * const selections[] = {
1002 runTest("simple.gro", selections);
1005 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
1007 static const char * const selections[] = {
1012 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1013 runTest("simple.gro", selections);
1017 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
1019 static const char * const selections[] = {
1020 "same residue as atomnr 1 4 12"
1022 runTest("simple.gro", selections);
1026 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
1028 static const char * const selections[] = {
1029 "same resname as atomnr 1 14"
1031 runTest("simple.gro", selections);
1035 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
1037 static const char * const selections[] = {
1039 "res_cog of name CB and resnr 1 3",
1040 "whole_res_cog of name CB and resnr 1 3",
1041 "part_res_cog of x < 3",
1042 "dyn_res_cog of x < 3"
1044 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1045 | efTestPositionAtoms);
1046 runTest("simple.gro", selections);
1050 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
1052 static const char * const selections[] = {
1053 "distance from cog of resnr 1 < 2"
1055 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1056 runTest("simple.gro", selections);
1060 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
1062 static const char * const selections[] = {
1063 "mindistance from resnr 1 < 2"
1065 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1066 runTest("simple.gro", selections);
1070 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
1072 static const char * const selections[] = {
1073 "within 1 of resnr 2"
1075 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1076 runTest("simple.gro", selections);
1080 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
1082 // Both of these should evaluate to empty on a correct implementation.
1083 static const char * const selections[] = {
1084 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
1085 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
1087 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
1088 runTest("sphere.gro", selections);
1092 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
1094 static const char * const selections[] = {
1095 "all permute 3 1 2",
1096 "res_cog of resnr 1 to 4 permute 2 1",
1097 "name CB S1 and res_cog x < 3 permute 2 1"
1099 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1100 | efTestPositionAtoms | efTestPositionMapping);
1101 runTest("simple.gro", selections);
1105 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
1107 static const char * const selections[] = {
1108 "name S2 plus name S1",
1109 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
1110 "name S1 and y < 3 plus res_cog of x < 2.5"
1112 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1113 | efTestPositionAtoms | efTestPositionMapping);
1114 runTest("simple.gro", selections);
1118 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
1120 static const char * const selections[] = {
1121 "name S2 merge name S1",
1122 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
1123 "name S1 and x < 2.5 merge res_cog of x < 2.5"
1125 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1126 | efTestPositionAtoms | efTestPositionMapping);
1127 runTest("simple.gro", selections);
1131 /********************************************************************
1132 * Tests for generic selection evaluation
1135 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
1137 static const char * const selections[] = {
1142 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
1143 | efTestPositionMasses | efTestPositionCharges);
1144 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1145 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
1146 t_atoms &atoms = topManager_.atoms();
1147 for (int i = 0; i < atoms.nr; ++i)
1149 atoms.atom[i].m = 1.0 + i / 100.0;
1150 atoms.atom[i].q = -(1.0 + i / 100.0);
1152 atoms.haveMass = TRUE;
1153 atoms.haveCharge = TRUE;
1154 ASSERT_NO_FATAL_FAILURE(setTopology());
1155 ASSERT_NO_FATAL_FAILURE(runCompiler());
1156 ASSERT_NO_FATAL_FAILURE(runEvaluate());
1157 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
1160 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
1162 static const char * const selections[] = {
1163 "atomnr 1 to 3 8 to 9",
1167 setFlags(TestFlags() | efTestPositionAtoms
1168 | efTestPositionMasses | efTestPositionCharges);
1169 runTest(10, selections);
1172 TEST_F(SelectionCollectionDataTest, HandlesFramesWithAtomSubsets)
1174 const int index[] = { 0, 1, 2, 3, 4, 5, 9, 10, 11 };
1175 const char * const selections[] = {
1177 "atomnr 1 2 5 11 and y > 2",
1178 "res_cog of atomnr 2 5 11"
1180 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms);
1181 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1182 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1183 ASSERT_NO_FATAL_FAILURE(runCompiler());
1184 topManager_.initFrameIndices(index);
1185 ASSERT_NO_FATAL_FAILURE(runEvaluate());
1186 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
1190 /********************************************************************
1191 * Tests for selection syntactic constructs
1194 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
1196 static const char * const selections[] = {
1197 "\"GroupSelection\" group \"GrpA\"",
1198 "\"DynamicSelection\" x < 5",
1201 setFlags(TestFlags() | efTestSelectionNames);
1202 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1203 runTest(10, selections);
1206 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
1208 static const char * const selections[] = {
1212 // These test that the name of the group is not too eagerly promoted to
1213 // the name of the selection.
1214 "group \"GrpB\" and resname RB",
1215 "group \"GrpA\" permute 5 3 2 1 4",
1216 "group \"GrpA\" plus group \"GrpB\"",
1217 "res_cog of group \"GrpA\""
1219 setFlags(TestFlags() | efTestSelectionNames);
1220 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1221 runTest("simple.gro", selections);
1224 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
1226 static const char * const selections[] = {
1230 "group \"GrpB\" and resname RB"
1232 setFlags(TestFlags() | efTestSelectionNames);
1233 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1234 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1235 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1236 ASSERT_NO_FATAL_FAILURE(runCompiler());
1239 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
1241 static const char * const selections[] = {
1242 "foo = group \"GrpUnsorted\"",
1243 "group \"GrpUnsorted\"",
1246 "res_cog of group \"GrpUnsorted\"",
1247 "group \"GrpUnsorted\" permute 2 1",
1250 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
1251 | efTestSelectionNames);
1252 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1253 runTest("simple.gro", selections);
1256 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
1258 static const char * const selections[] = {
1259 "foo = group \"GrpUnsorted\"",
1260 "group \"GrpUnsorted\"",
1263 "res_cog of group \"GrpUnsorted\"",
1264 "group \"GrpUnsorted\" permute 2 1",
1267 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1268 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1269 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1270 ASSERT_NO_FATAL_FAILURE(runCompiler());
1274 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1276 static const char * const selections[] = {
1279 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1280 | efTestPositionMapping);
1281 runTest("simple.gro", selections);
1285 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionsWithModifiers)
1287 static const char * const selections[] = {
1288 "[0, 0, 0] plus [0, 1, 0]"
1290 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1291 | efTestPositionMapping);
1292 runTest("simple.gro", selections);
1296 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1298 static const char * const selections[] = {
1299 "within 1 of [2, 1, 0]"
1301 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1302 runTest("simple.gro", selections);
1306 TEST_F(SelectionCollectionDataTest, HandlesOverlappingIntegerRanges)
1308 static const char * const selections[] = {
1309 "atomnr 2 to 4 5 to 8",
1310 "atomnr 2 to 5 4 to 7"
1312 ASSERT_NO_FATAL_FAILURE(runTest(10, selections));
1316 TEST_F(SelectionCollectionDataTest, HandlesOverlappingRealRanges)
1318 static const char * const selections[] = {
1319 "charge {-0.35 to -0.05 0.25 to 0.75}",
1320 "charge {0.05 to -0.3 -0.05 to 0.55}"
1322 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1323 ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
1324 t_atoms &atoms = topManager_.atoms();
1325 for (int i = 0; i < atoms.nr; ++i)
1327 atoms.atom[i].q = i / 10.0 - 0.5;
1329 atoms.haveCharge = TRUE;
1330 ASSERT_NO_FATAL_FAILURE(setTopology());
1331 ASSERT_NO_FATAL_FAILURE(runCompiler());
1335 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1337 static const char * const selections[] = {
1341 runTest("simple.gro", selections);
1345 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1347 static const char * const selections[] = {
1351 runTest("simple.gro", selections);
1355 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1357 static const char * const selections[] = {
1358 "resname \"R[BD]\"",
1359 "resname ~ \"R[BD]\""
1361 runTest("simple.gro", selections);
1365 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1367 static const char * const selections[] = {
1368 "atomnr 1 to 5 and atomnr 2 to 7",
1369 "atomnr 1 to 5 or not atomnr 3 to 8",
1370 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1371 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1372 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1374 runTest(10, selections);
1378 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1380 static const char * const selections[] = {
1381 "same residue as (atomnr 3 5 13 or y > 5)",
1382 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1384 setFlags(TestFlags() | efTestEvaluation);
1385 runTest("simple.gro", selections);
1389 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1391 static const char * const selections[] = {
1393 "none and same resname as resnr 2"
1395 runTest("simple.gro", selections);
1399 TEST_F(SelectionCollectionDataTest, HandlesEmptyReferenceForSame)
1401 static const char * const selections[] = {
1402 "same residue as none",
1403 "same resname as none"
1405 runTest("simple.gro", selections);
1409 TEST_F(SelectionCollectionDataTest, HandlesPositionModifiersForKeywords)
1411 static const char * const selections[] = {
1413 "name CB and res_cog y > 2.5"
1415 setFlags(TestFlags() | efTestEvaluation);
1416 runTest("simple.gro", selections);
1420 TEST_F(SelectionCollectionDataTest, HandlesPositionModifiersForMethods)
1422 static const char * const selections[] = {
1423 "res_cog distance from cog of resnr 1 < 2",
1424 "res_cog within 2 of cog of resnr 1"
1426 setFlags(TestFlags() | efTestEvaluation);
1427 runTest("simple.gro", selections);
1431 TEST_F(SelectionCollectionDataTest, HandlesKeywordOfPositions)
1433 static const char * const selections[] = {
1434 "x < y of cog of resnr 2"
1436 setFlags(TestFlags() | efTestEvaluation);
1437 runTest("simple.gro", selections);
1440 TEST_F(SelectionCollectionDataTest, HandlesKeywordOfPositionsInArithmetic)
1442 static const char * const selections[] = {
1443 "x - y of cog of resnr 2 < 0"
1445 setFlags(TestFlags() | efTestEvaluation);
1446 runTest("simple.gro", selections);
1450 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1452 static const char * const selections[] = {
1459 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1460 runTest("simple.gro", selections);
1464 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1466 static const char * const selections[] = {
1472 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1473 runTest("simple.gro", selections);
1477 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1479 static const char * const selections[] = {
1485 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1486 runTest("simple.gro", selections);
1490 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1492 static const char * const selections[] = {
1494 "resname RA and value <= 4",
1495 "resname RA RB and x < 3 and value <= 4",
1497 "resname RA and index < 3",
1498 "resname RB and y < 3 and index < 6"
1500 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1501 runTest("simple.gro", selections);
1505 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1507 static const char * const selections[] = {
1508 "foo = res_cog of resname RA",
1511 "bar = cog of resname RA",
1515 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1516 runTest("simple.gro", selections);
1520 TEST_F(SelectionCollectionDataTest, HandlesPositionVariableInModifier)
1522 static const char * const selections[] = {
1523 "foo = cog of resnr 1",
1524 "cog of resnr 2 plus foo",
1525 "cog of resnr 3 plus foo"
1527 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1528 runTest("simple.gro", selections);
1532 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1534 static const char * const selections[] = {
1535 "constpos = [1.0, 2.5, 0.5]",
1537 "within 2 of constpos"
1539 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1540 | efTestPositionAtoms);
1541 runTest("simple.gro", selections);
1545 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1547 static const char * const selections[] = {
1552 "x + constreal1 < constreal2"
1554 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1555 runTest("simple.gro", selections);
1559 /********************************************************************
1560 * Tests for complex boolean syntax
1563 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1565 static const char * const selections[] = {
1566 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1567 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1568 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1569 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1570 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1572 runTest(10, selections);
1576 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1578 static const char * const selections[] = {
1579 "foo = atomnr 4 to 7 or x < 2",
1580 "atomnr 1 to 4 and foo",
1581 "atomnr 2 to 6 and y < 3 and foo",
1582 "atomnr 6 to 10 and not foo"
1584 runTest(10, selections);
1588 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1590 static const char * const selections[] = {
1591 "foo = atomnr 4 to 7",
1592 "bar = foo and x < 2",
1593 "bar2 = foo and y < 2",
1594 "atomnr 1 to 4 and bar",
1595 "atomnr 2 to 6 and y < 3 and bar2",
1596 "atomnr 6 to 10 and not foo"
1598 runTest(10, selections);
1602 /********************************************************************
1603 * Tests for complex subexpression cases
1605 * These tests use some knowledge of the implementation to trigger different
1606 * paths in the code.
1609 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1611 static const char * const selections[] = {
1612 "unused1 = atomnr 1 to 3",
1613 "foo = atomnr 4 to 7",
1614 "atomnr 1 to 6 and foo",
1615 "unused2 = atomnr 3 to 5"
1617 runTest(10, selections);
1621 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1623 static const char * const selections[] = {
1624 "foo = atomnr 4 to 7 and x < 2",
1625 "atomnr 1 to 5 and foo",
1626 "atomnr 3 to 7 and foo"
1628 runTest(10, selections);
1632 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1634 static const char * const selections[] = {
1635 "foo = atomnr 4 to 7 and x < 2",
1636 "atomnr 1 to 6 and foo",
1640 runTest(10, selections);
1644 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1646 static const char * const selections[] = {
1647 "foo = atomnr 1 to 8 and x < 10",
1648 "atomnr 1 to 5 and y < 10 and foo",
1651 setFlags(TestFlags() | efTestEvaluation);
1652 runTest("simple.gro", selections);