Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / selection / tests / selectioncollection.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Tests selection parsing and compilation.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include "gmxpre.h"
43
44 #include "gromacs/selection/selectioncollection.h"
45
46 #include <gtest/gtest.h>
47
48 #include "gromacs/fileio/trx.h"
49 #include "gromacs/options/basicoptions.h"
50 #include "gromacs/options/options.h"
51 #include "gromacs/selection/indexutil.h"
52 #include "gromacs/selection/selection.h"
53 #include "gromacs/topology/topology.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"
59
60 #include "testutils/refdata.h"
61 #include "testutils/testasserts.h"
62 #include "testutils/testfilemanager.h"
63 #include "testutils/testoptions.h"
64
65 #include "toputils.h"
66
67 namespace
68 {
69
70 /********************************************************************
71  * Test fixture for selection testing
72  */
73
74 class SelectionCollectionTest : public ::testing::Test
75 {
76     public:
77         static int               s_debugLevel;
78
79         SelectionCollectionTest();
80         ~SelectionCollectionTest();
81
82         void setAtomCount(int natoms)
83         {
84             ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
85         }
86         void loadTopology(const char *filename);
87         void setTopology();
88         void loadIndexGroups(const char *filename);
89
90         gmx::test::TopologyManager  topManager_;
91         gmx::SelectionCollection    sc_;
92         gmx::SelectionList          sel_;
93         t_topology                 *top_;
94         t_trxframe                 *frame_;
95         gmx_ana_indexgrps_t        *grps_;
96 };
97
98 int SelectionCollectionTest::s_debugLevel = 0;
99
100 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
101 #ifndef DOXYGEN
102 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
103 {
104     options->addOption(gmx::IntegerOption("seldebug")
105                            .store(&SelectionCollectionTest::s_debugLevel)
106                            .description("Set selection debug level"));
107 }
108 #endif
109
110 SelectionCollectionTest::SelectionCollectionTest()
111     : top_(NULL), frame_(NULL), grps_(NULL)
112 {
113     topManager_.requestFrame();
114     sc_.setDebugLevel(s_debugLevel);
115     sc_.setReferencePosType("atom");
116     sc_.setOutputPosType("atom");
117 }
118
119 SelectionCollectionTest::~SelectionCollectionTest()
120 {
121     if (grps_ != NULL)
122     {
123         gmx_ana_indexgrps_free(grps_);
124     }
125 }
126
127 void
128 SelectionCollectionTest::loadTopology(const char *filename)
129 {
130     topManager_.loadTopology(filename);
131     setTopology();
132 }
133
134 void
135 SelectionCollectionTest::setTopology()
136 {
137     top_   = topManager_.topology();
138     frame_ = topManager_.frame();
139
140     ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
141 }
142
143 void
144 SelectionCollectionTest::loadIndexGroups(const char *filename)
145 {
146     GMX_RELEASE_ASSERT(grps_ == NULL,
147                        "External groups can only be loaded once");
148     std::string fullpath =
149         gmx::test::TestFileManager::getInputFilePath(filename);
150     gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
151     sc_.setIndexGroups(grps_);
152 }
153
154
155 /********************************************************************
156  * Test fixture for selection testing with reference data
157  */
158
159 class SelectionCollectionDataTest : public SelectionCollectionTest
160 {
161     public:
162         enum TestFlag
163         {
164             efTestEvaluation            = 1<<0,
165             efTestPositionAtoms         = 1<<1,
166             efTestPositionCoordinates   = 1<<2,
167             efTestPositionMapping       = 1<<3,
168             efTestPositionMasses        = 1<<4,
169             efTestPositionCharges       = 1<<5,
170             efTestSelectionNames        = 1<<6,
171             efDontTestCompiledAtoms     = 1<<8
172         };
173         typedef gmx::FlagsTemplate<TestFlag> TestFlags;
174
175         SelectionCollectionDataTest()
176             : checker_(data_.rootChecker()), count_(0), framenr_(0)
177         {
178         }
179
180         void setFlags(TestFlags flags) { flags_ = flags; }
181
182         void runParser(const gmx::ConstArrayRef<const char *> &selections);
183         void runCompiler();
184         void runEvaluate();
185         void runEvaluateFinal();
186
187         void runTest(int                                     natoms,
188                      const gmx::ConstArrayRef<const char *> &selections);
189         void runTest(const char                             *filename,
190                      const gmx::ConstArrayRef<const char *> &selections);
191
192     private:
193         static void checkSelection(gmx::test::TestReferenceChecker *checker,
194                                    const gmx::Selection &sel, TestFlags flags);
195
196         void checkCompiled();
197
198         gmx::test::TestReferenceData    data_;
199         gmx::test::TestReferenceChecker checker_;
200         size_t                          count_;
201         int                             framenr_;
202         TestFlags                       flags_;
203 };
204
205
206 void
207 SelectionCollectionDataTest::checkSelection(
208         gmx::test::TestReferenceChecker *checker,
209         const gmx::Selection &sel, TestFlags flags)
210 {
211     using gmx::test::TestReferenceChecker;
212
213     {
214         gmx::ConstArrayRef<int> atoms = sel.atomIndices();
215         checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
216     }
217     if (flags.test(efTestPositionAtoms)
218         || flags.test(efTestPositionCoordinates)
219         || flags.test(efTestPositionMapping)
220         || flags.test(efTestPositionMasses)
221         || flags.test(efTestPositionCharges))
222     {
223         TestReferenceChecker compound(
224                 checker->checkSequenceCompound("Positions", sel.posCount()));
225         for (int i = 0; i < sel.posCount(); ++i)
226         {
227             TestReferenceChecker          poscompound(compound.checkCompound("Position", NULL));
228             const gmx::SelectionPosition &p = sel.position(i);
229             if (flags.test(efTestPositionAtoms))
230             {
231                 gmx::ConstArrayRef<int> atoms = p.atomIndices();
232                 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
233             }
234             if (flags.test(efTestPositionCoordinates))
235             {
236                 poscompound.checkVector(p.x(), "Coordinates");
237             }
238             if (flags.test(efTestPositionMapping))
239             {
240                 poscompound.checkInteger(p.refId(), "RefId");
241                 poscompound.checkInteger(p.mappedId(), "MappedId");
242             }
243             if (flags.test(efTestPositionMasses))
244             {
245                 poscompound.checkReal(p.mass(), "Mass");
246             }
247             if (flags.test(efTestPositionCharges))
248             {
249                 poscompound.checkReal(p.charge(), "Charge");
250             }
251         }
252     }
253 }
254
255
256 void
257 SelectionCollectionDataTest::runParser(
258         const gmx::ConstArrayRef<const char *> &selections)
259 {
260     using gmx::test::TestReferenceChecker;
261
262     TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
263     size_t               varcount = 0;
264     count_ = 0;
265     for (size_t i = 0; i < selections.size(); ++i)
266     {
267         SCOPED_TRACE(std::string("Parsing selection \"")
268                      + selections[i] + "\"");
269         gmx::SelectionList result;
270         ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
271         sel_.insert(sel_.end(), result.begin(), result.end());
272         if (sel_.size() == count_)
273         {
274             std::string          id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
275             TestReferenceChecker varcompound(
276                     compound.checkCompound("ParsedVariable", id.c_str()));
277             varcompound.checkString(selections[i], "Input");
278             ++varcount;
279         }
280         else
281         {
282             std::string          id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
283             TestReferenceChecker selcompound(
284                     compound.checkCompound("ParsedSelection", id.c_str()));
285             selcompound.checkString(selections[i], "Input");
286             if (flags_.test(efTestSelectionNames))
287             {
288                 selcompound.checkString(sel_[count_].name(), "Name");
289             }
290             selcompound.checkString(sel_[count_].selectionText(), "Text");
291             selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
292             ++count_;
293         }
294     }
295 }
296
297
298 void
299 SelectionCollectionDataTest::runCompiler()
300 {
301     ASSERT_NO_THROW_GMX(sc_.compile());
302     ASSERT_EQ(count_, sel_.size());
303     checkCompiled();
304 }
305
306
307 void
308 SelectionCollectionDataTest::checkCompiled()
309 {
310     using gmx::test::TestReferenceChecker;
311     const TestFlags      mask = ~TestFlags(efTestPositionCoordinates);
312
313     TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
314     for (size_t i = 0; i < count_; ++i)
315     {
316         SCOPED_TRACE(std::string("Checking selection \"") +
317                      sel_[i].selectionText() + "\"");
318         std::string          id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
319         TestReferenceChecker selcompound(
320                 compound.checkCompound("Selection", id.c_str()));
321         if (flags_.test(efTestSelectionNames))
322         {
323             selcompound.checkString(sel_[i].name(), "Name");
324         }
325         if (!flags_.test(efDontTestCompiledAtoms))
326         {
327             checkSelection(&selcompound, sel_[i], flags_ & mask);
328         }
329     }
330 }
331
332
333 void
334 SelectionCollectionDataTest::runEvaluate()
335 {
336     using gmx::test::TestReferenceChecker;
337
338     ++framenr_;
339     ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
340     std::string          frame = gmx::formatString("Frame%d", framenr_);
341     TestReferenceChecker compound(
342             checker_.checkCompound("EvaluatedSelections", frame.c_str()));
343     for (size_t i = 0; i < count_; ++i)
344     {
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         checkSelection(&selcompound, sel_[i], flags_);
351     }
352 }
353
354
355 void
356 SelectionCollectionDataTest::runEvaluateFinal()
357 {
358     ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
359     checkCompiled();
360 }
361
362
363 void
364 SelectionCollectionDataTest::runTest(
365         int natoms, const gmx::ConstArrayRef<const char *> &selections)
366 {
367     ASSERT_NO_FATAL_FAILURE(runParser(selections));
368     ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
369     ASSERT_NO_FATAL_FAILURE(runCompiler());
370 }
371
372
373 void
374 SelectionCollectionDataTest::runTest(
375         const char *filename, const gmx::ConstArrayRef<const char *> &selections)
376 {
377     ASSERT_NO_FATAL_FAILURE(runParser(selections));
378     ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
379     ASSERT_NO_FATAL_FAILURE(runCompiler());
380     if (flags_.test(efTestEvaluation))
381     {
382         ASSERT_NO_FATAL_FAILURE(runEvaluate());
383         ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
384     }
385 }
386
387
388 /********************************************************************
389  * Tests for SelectionCollection functionality without reference data
390  */
391
392 TEST_F(SelectionCollectionTest, HandlesNoSelections)
393 {
394     EXPECT_FALSE(sc_.requiresTopology());
395     EXPECT_NO_THROW_GMX(sc_.compile());
396 }
397
398 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
399 {
400     ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
401     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
402     ASSERT_EQ(2U, sel_.size());
403     ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
404     ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
405     ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
406     ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
407     ASSERT_NO_THROW_GMX(sc_.compile());
408     EXPECT_TRUE(sel_[0].hasVelocities());
409     EXPECT_TRUE(sel_[1].hasVelocities());
410     EXPECT_TRUE(sel_[0].hasForces());
411     EXPECT_TRUE(sel_[1].hasForces());
412 }
413
414 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
415 {
416     ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
417                                     gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
418     // These should match the contents of selfile.dat
419     ASSERT_EQ(2U, sel_.size());
420     EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
421     EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
422 }
423
424 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
425 {
426     ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
427     ASSERT_EQ(2U, sel_.size());
428     EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
429     // TODO: Get rid of the trailing whitespace.
430     EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
431 }
432
433 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
434 {
435     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
436     EXPECT_THROW_GMX({
437                          sc_.parseFromString("resname ~ \"R[A\"");
438                          sc_.compile();
439                      }, gmx::InvalidInputError);
440 }
441
442 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
443 {
444     if (!gmx::Regex::isSupported())
445     {
446         ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
447         EXPECT_THROW_GMX({
448                              sc_.parseFromString("resname \"R[AD]\"");
449                              sc_.compile();
450                          }, gmx::InvalidInputError);
451     }
452 }
453
454 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
455 {
456     EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
457                      gmx::InvalidInputError);
458 }
459
460 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
461 {
462     EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
463                      gmx::InvalidInputError);
464 }
465
466 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
467 {
468     EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
469                      gmx::InvalidInputError);
470 }
471
472 // TODO: Tests for more parser errors
473
474 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
475 {
476     ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
477     EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
478     EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
479 }
480
481 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
482 {
483     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
484     EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
485     EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
486 }
487
488 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
489 {
490     ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
491     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
492     EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
493     EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
494 }
495
496 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
497 {
498     ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
499     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
500     EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
501     EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
502 }
503
504 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
505 {
506     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
507     EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
508                      gmx::InconsistentInputError);
509     EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
510                      gmx::InconsistentInputError);
511     EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
512                      gmx::InconsistentInputError);
513 }
514
515 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
516 {
517     ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
518     ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
519     EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
520     // TODO: Add a separate check in the selection compiler for a safer API
521     // (makes sense in the future if the compiler needs the information for
522     // other purposes as well).
523     // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
524 }
525
526 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
527 {
528     ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
529     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
530     EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
531 }
532
533 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
534 {
535     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
536     ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
537     EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
538 }
539
540 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
541 {
542     ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
543     ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
544     EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
545 }
546
547 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
548 {
549     ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
550     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
551     EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
552 }
553
554 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
555 {
556     ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
557     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
558     EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
559 }
560
561 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
562 {
563     ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
564     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
565     EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
566 }
567
568 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
569 {
570     ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
571     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
572     EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
573 }
574
575 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
576 {
577     ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
578     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
579     EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
580 }
581
582 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
583 {
584     ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
585     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
586     ASSERT_NO_THROW_GMX(sc_.compile());
587     EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
588 }
589
590 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
591 {
592     ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
593     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
594     ASSERT_NO_THROW_GMX(sc_.compile());
595     frame_->natoms = 8;
596     EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
597 }
598
599 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
600 {
601     // Evaluating the positions will require atoms 1-9.
602     ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 5 7"));
603     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
604     ASSERT_NO_THROW_GMX(sc_.compile());
605     frame_->natoms = 8;
606     EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
607 }
608
609 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
610 {
611     ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
612     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
613     ASSERT_NO_THROW_GMX(sc_.compile());
614     frame_->natoms = 10;
615     EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
616 }
617
618 // TODO: Tests for more evaluation errors
619
620
621 /********************************************************************
622  * Tests for selection keywords
623  */
624
625 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
626 {
627     static const char * const selections[] = {
628         "all",
629         "none"
630     };
631     runTest(10, selections);
632 }
633
634 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
635 {
636     static const char * const selections[] = {
637         "atomnr 1 to 3 6 to 8",
638         "atomnr 4 2 5 to 7",
639         "atomnr <= 5"
640     };
641     runTest(10, selections);
642 }
643
644 TEST_F(SelectionCollectionDataTest, HandlesResnr)
645 {
646     static const char * const selections[] = {
647         "resnr 1 2 5",
648         "resid 4 to 3"
649     };
650     runTest("simple.gro", selections);
651 }
652
653 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
654 {
655     static const char * const selections[] = {
656         "resindex 1 4",
657         "residue 1 3"
658     };
659     runTest("simple.pdb", selections);
660 }
661
662 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
663 {
664     static const char * const selections[] = {
665         "molindex 1 4",
666         "molecule 2 3 5"
667     };
668     ASSERT_NO_FATAL_FAILURE(runParser(selections));
669     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
670     topManager_.initUniformMolecules(3);
671     ASSERT_NO_FATAL_FAILURE(runCompiler());
672 }
673
674 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
675 {
676     static const char * const selections[] = {
677         "name CB",
678         "atomname S1 S2"
679     };
680     runTest("simple.gro", selections);
681 }
682
683 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
684 {
685     static const char * const selections[] = {
686         "name HG21",
687         "name 1HG2",
688         "pdbname HG21 CB",
689         "pdbatomname 1HG2"
690     };
691     runTest("simple.pdb", selections);
692 }
693
694
695 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
696 {
697     static const char * const selections[] = {
698         "atomtype CA"
699     };
700     ASSERT_NO_FATAL_FAILURE(runParser(selections));
701     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
702     const char *const types[] = { "CA", "SA", "SB" };
703     topManager_.initAtomTypes(types);
704     ASSERT_NO_FATAL_FAILURE(runCompiler());
705 }
706
707 TEST_F(SelectionCollectionDataTest, HandlesChain)
708 {
709     static const char * const selections[] = {
710         "chain A",
711         "chain B"
712     };
713     runTest("simple.pdb", selections);
714 }
715
716 TEST_F(SelectionCollectionDataTest, HandlesMass)
717 {
718     static const char * const selections[] = {
719         "mass > 5"
720     };
721     ASSERT_NO_FATAL_FAILURE(runParser(selections));
722     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
723     for (int i = 0; i < top_->atoms.nr; ++i)
724     {
725         top_->atoms.atom[i].m = 1.0 + i;
726     }
727     ASSERT_NO_FATAL_FAILURE(runCompiler());
728 }
729
730 TEST_F(SelectionCollectionDataTest, HandlesCharge)
731 {
732     static const char * const selections[] = {
733         "charge < 0.5"
734     };
735     ASSERT_NO_FATAL_FAILURE(runParser(selections));
736     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
737     for (int i = 0; i < top_->atoms.nr; ++i)
738     {
739         top_->atoms.atom[i].q = i / 10.0;
740     }
741     ASSERT_NO_FATAL_FAILURE(runCompiler());
742 }
743
744 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
745 {
746     static const char * const selections[] = {
747         "altloc \" \"",
748         "altloc A"
749     };
750     runTest("simple.pdb", selections);
751 }
752
753 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
754 {
755     static const char * const selections[] = {
756         "insertcode \" \"",
757         "insertcode A"
758     };
759     runTest("simple.pdb", selections);
760 }
761
762 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
763 {
764     static const char * const selections[] = {
765         "occupancy 1",
766         "occupancy < .5"
767     };
768     runTest("simple.pdb", selections);
769 }
770
771 TEST_F(SelectionCollectionDataTest, HandlesBeta)
772 {
773     static const char * const selections[] = {
774         "beta 0",
775         "beta >= 0.3"
776     };
777     runTest("simple.pdb", selections);
778 }
779
780 TEST_F(SelectionCollectionDataTest, HandlesResname)
781 {
782     static const char * const selections[] = {
783         "resname RA",
784         "resname RB RC"
785     };
786     runTest("simple.gro", selections);
787 }
788
789 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
790 {
791     static const char * const selections[] = {
792         "x < 3",
793         "y >= 3",
794         "x {-1 to 2}"
795     };
796     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
797     runTest("simple.gro", selections);
798 }
799
800
801 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
802 {
803     static const char * const selections[] = {
804         "same residue as atomnr 1 4 12"
805     };
806     runTest("simple.gro", selections);
807 }
808
809
810 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
811 {
812     static const char * const selections[] = {
813         "same resname as atomnr 1 14"
814     };
815     runTest("simple.gro", selections);
816 }
817
818
819 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
820 {
821     static const char * const selections[] = {
822         "cog of resnr 1 3",
823         "res_cog of name CB and resnr 1 3",
824         "whole_res_cog of name CB and resnr 1 3",
825         "part_res_cog of x < 3",
826         "dyn_res_cog of x < 3"
827     };
828     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
829              | efTestPositionAtoms);
830     runTest("simple.gro", selections);
831 }
832
833
834 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
835 {
836     static const char * const selections[] = {
837         "distance from cog of resnr 1 < 2"
838     };
839     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
840     runTest("simple.gro", selections);
841 }
842
843
844 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
845 {
846     static const char * const selections[] = {
847         "mindistance from resnr 1 < 2"
848     };
849     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
850     runTest("simple.gro", selections);
851 }
852
853
854 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
855 {
856     static const char * const selections[] = {
857         "within 1 of resnr 2"
858     };
859     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
860     runTest("simple.gro", selections);
861 }
862
863
864 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
865 {
866     // Both of these should evaluate to empty on a correct implementation.
867     static const char * const selections[] = {
868         "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
869         "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
870     };
871     setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
872     runTest("sphere.gro", selections);
873 }
874
875
876 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
877 {
878     static const char * const selections[] = {
879         "all permute 3 1 2",
880         "res_cog of resnr 1 to 4 permute 2 1",
881         "name CB S1 and res_cog x < 3 permute 2 1"
882     };
883     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
884              | efTestPositionAtoms | efTestPositionMapping);
885     runTest("simple.gro", selections);
886 }
887
888
889 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
890 {
891     static const char * const selections[] = {
892         "name S2 plus name S1",
893         "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
894         "name S1 and y < 3 plus res_cog of x < 2.5"
895     };
896     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
897              | efTestPositionAtoms | efTestPositionMapping);
898     runTest("simple.gro", selections);
899 }
900
901
902 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
903 {
904     static const char * const selections[] = {
905         "name S2 merge name S1",
906         "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
907         "name S1 and x < 2.5 merge res_cog of x < 2.5"
908     };
909     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
910              | efTestPositionAtoms | efTestPositionMapping);
911     runTest("simple.gro", selections);
912 }
913
914
915 /********************************************************************
916  * Tests for generic selection evaluation
917  */
918
919 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
920 {
921     static const char * const selections[] = {
922         "name CB",
923         "y > 2",
924         "res_cog of y > 2"
925     };
926     setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
927              | efTestPositionMasses | efTestPositionCharges);
928     ASSERT_NO_FATAL_FAILURE(runParser(selections));
929     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
930     for (int i = 0; i < top_->atoms.nr; ++i)
931     {
932         top_->atoms.atom[i].m =   1.0 + i / 100.0;
933         top_->atoms.atom[i].q = -(1.0 + i / 100.0);
934     }
935     ASSERT_NO_FATAL_FAILURE(runCompiler());
936     ASSERT_NO_FATAL_FAILURE(runEvaluate());
937     ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
938 }
939
940 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
941 {
942     static const char * const selections[] = {
943         "atomnr 1 to 3 8 to 9",
944         "y > 2",
945         "cog of (y > 2)"
946     };
947     setFlags(TestFlags() | efTestPositionAtoms
948              | efTestPositionMasses | efTestPositionCharges);
949     runTest(10, selections);
950 }
951
952
953 /********************************************************************
954  * Tests for selection syntactic constructs
955  */
956
957 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
958 {
959     static const char * const selections[] = {
960         "\"GroupSelection\" group \"GrpA\"",
961         "\"DynamicSelection\" x < 5",
962         "y < 3"
963     };
964     setFlags(TestFlags() | efTestSelectionNames);
965     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
966     runTest(10, selections);
967 }
968
969 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
970 {
971     static const char * const selections[] = {
972         "group \"GrpA\"",
973         "GrpB",
974         "1",
975         "group \"GrpB\" and resname RB"
976     };
977     setFlags(TestFlags() | efTestSelectionNames);
978     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
979     runTest("simple.gro", selections);
980 }
981
982 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
983 {
984     static const char * const selections[] = {
985         "group \"GrpA\"",
986         "GrpB",
987         "1",
988         "group \"GrpB\" and resname RB"
989     };
990     setFlags(TestFlags() | efTestSelectionNames);
991     ASSERT_NO_FATAL_FAILURE(runParser(selections));
992     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
993     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
994     ASSERT_NO_FATAL_FAILURE(runCompiler());
995 }
996
997 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
998 {
999     static const char * const selections[] = {
1000         "foo = group \"GrpUnsorted\"",
1001         "group \"GrpUnsorted\"",
1002         "GrpUnsorted",
1003         "2",
1004         "res_cog of group \"GrpUnsorted\"",
1005         "group \"GrpUnsorted\" permute 2 1",
1006         "foo"
1007     };
1008     setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
1009              | efTestSelectionNames);
1010     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1011     runTest("simple.gro", selections);
1012 }
1013
1014 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
1015 {
1016     static const char * const selections[] = {
1017         "foo = group \"GrpUnsorted\"",
1018         "group \"GrpUnsorted\"",
1019         "GrpUnsorted",
1020         "2",
1021         "res_cog of group \"GrpUnsorted\"",
1022         "group \"GrpUnsorted\" permute 2 1",
1023         "foo"
1024     };
1025     ASSERT_NO_FATAL_FAILURE(runParser(selections));
1026     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1027     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1028     ASSERT_NO_FATAL_FAILURE(runCompiler());
1029 }
1030
1031 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1032 {
1033     static const char * const selections[] = {
1034         "[1, -2, 3.5]"
1035     };
1036     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1037     runTest("simple.gro", selections);
1038 }
1039
1040
1041 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1042 {
1043     static const char * const selections[] = {
1044         "within 1 of [2, 1, 0]"
1045     };
1046     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1047     runTest("simple.gro", selections);
1048 }
1049
1050
1051 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1052 {
1053     static const char * const selections[] = {
1054         "name = S1 \"C?\"",
1055         "name ? S1 \"C?\""
1056     };
1057     runTest("simple.gro", selections);
1058 }
1059
1060
1061 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1062 {
1063     static const char * const selections[] = {
1064         "name \"S?\"",
1065         "name ? \"S?\""
1066     };
1067     runTest("simple.gro", selections);
1068 }
1069
1070
1071 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1072 {
1073     static const char * const selections[] = {
1074         "resname \"R[BD]\"",
1075         "resname ~ \"R[BD]\""
1076     };
1077     if (gmx::Regex::isSupported())
1078     {
1079         runTest("simple.gro", selections);
1080     }
1081 }
1082
1083
1084 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1085 {
1086     static const char * const selections[] = {
1087         "atomnr 1 to 5 and atomnr 2 to 7",
1088         "atomnr 1 to 5 or not atomnr 3 to 8",
1089         "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1090         "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1091         "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1092     };
1093     runTest(10, selections);
1094 }
1095
1096
1097 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1098 {
1099     static const char * const selections[] = {
1100         "same residue as (atomnr 3 5 13 or y > 5)",
1101         "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1102     };
1103     setFlags(TestFlags() | efTestEvaluation);
1104     runTest("simple.gro", selections);
1105 }
1106
1107
1108 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1109 {
1110     static const char * const selections[] = {
1111         "none and x > 2",
1112         "none and same resname as resnr 2"
1113     };
1114     runTest("simple.gro", selections);
1115 }
1116
1117
1118 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1119 {
1120     static const char * const selections[] = {
1121         "x > 2",
1122         "2 < x",
1123         "y > resnr",
1124         "resnr < 2.5",
1125         "2.5 > resnr"
1126     };
1127     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1128     runTest("simple.gro", selections);
1129 }
1130
1131
1132 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1133 {
1134     static const char * const selections[] = {
1135         "x+1 > 3",
1136         "(y-1)^2 <= 1",
1137         "x+--1 > 3",
1138         "-x+-1 < -3"
1139     };
1140     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1141     runTest("simple.gro", selections);
1142 }
1143
1144
1145 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1146 {
1147     static const char * const selections[] = {
1148         "value = x + y",
1149         "value <= 4",
1150         "index = resnr",
1151         "index < 3"
1152     };
1153     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1154     runTest("simple.gro", selections);
1155 }
1156
1157
1158 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1159 {
1160     static const char * const selections[] = {
1161         "value = x + y",
1162         "resname RA and value <= 4",
1163         "resname RA RB and x < 3 and value <= 4",
1164         "index = atomnr",
1165         "resname RA and index < 3",
1166         "resname RB and y < 3 and index < 6"
1167     };
1168     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1169     runTest("simple.gro", selections);
1170 }
1171
1172
1173 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1174 {
1175     static const char * const selections[] = {
1176         "foo = res_cog of resname RA",
1177         "foo",
1178         "within 1 of foo",
1179         "bar = cog of resname RA",
1180         "bar",
1181         "within 1 of bar"
1182     };
1183     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1184     runTest("simple.gro", selections);
1185 }
1186
1187
1188 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1189 {
1190     static const char * const selections[] = {
1191         "constpos = [1.0, 2.5, 0.5]",
1192         "constpos",
1193         "within 2 of constpos"
1194     };
1195     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1196              | efTestPositionAtoms);
1197     runTest("simple.gro", selections);
1198 }
1199
1200
1201 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1202 {
1203     static const char * const selections[] = {
1204         "constint = 4",
1205         "constreal1 = 0.5",
1206         "constreal2 = 2.7",
1207         "resnr < constint",
1208         "x + constreal1 < constreal2"
1209     };
1210     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1211     runTest("simple.gro", selections);
1212 }
1213
1214
1215 /********************************************************************
1216  * Tests for complex boolean syntax
1217  */
1218
1219 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1220 {
1221     static const char * const selections[] = {
1222         "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1223         "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1224         "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1225         "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1226         "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1227     };
1228     runTest(10, selections);
1229 }
1230
1231
1232 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1233 {
1234     static const char * const selections[] = {
1235         "foo = atomnr 4 to 7 or x < 2",
1236         "atomnr 1 to 4 and foo",
1237         "atomnr 2 to 6 and y < 3 and foo",
1238         "atomnr 6 to 10 and not foo"
1239     };
1240     runTest(10, selections);
1241 }
1242
1243
1244 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1245 {
1246     static const char * const selections[] = {
1247         "foo = atomnr 4 to 7",
1248         "bar = foo and x < 2",
1249         "bar2 = foo and y < 2",
1250         "atomnr 1 to 4 and bar",
1251         "atomnr 2 to 6 and y < 3 and bar2",
1252         "atomnr 6 to 10 and not foo"
1253     };
1254     runTest(10, selections);
1255 }
1256
1257
1258 /********************************************************************
1259  * Tests for complex subexpression cases
1260  *
1261  * These tests use some knowledge of the implementation to trigger different
1262  * paths in the code.
1263  */
1264
1265 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1266 {
1267     static const char * const selections[] = {
1268         "unused1 = atomnr 1 to 3",
1269         "foo = atomnr 4 to 7",
1270         "atomnr 1 to 6 and foo",
1271         "unused2 = atomnr 3 to 5"
1272     };
1273     runTest(10, selections);
1274 }
1275
1276
1277 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1278 {
1279     static const char * const selections[] = {
1280         "foo = atomnr 4 to 7 and x < 2",
1281         "atomnr 1 to 5 and foo",
1282         "atomnr 3 to 7 and foo"
1283     };
1284     runTest(10, selections);
1285 }
1286
1287
1288 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1289 {
1290     static const char * const selections[] = {
1291         "foo = atomnr 4 to 7 and x < 2",
1292         "atomnr 1 to 6 and foo",
1293         "within 1 of foo",
1294         "foo"
1295     };
1296     runTest(10, selections);
1297 }
1298
1299
1300 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1301 {
1302     static const char * const selections[] = {
1303         "foo = atomnr 1 to 8 and x < 10",
1304         "atomnr 1 to 5 and y < 10 and foo",
1305         "foo"
1306     };
1307     setFlags(TestFlags() | efTestEvaluation);
1308     runTest("simple.gro", selections);
1309 }
1310
1311
1312 } // namespace