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