3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
33 * Tests handling of selection options.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_selection
38 #include <gtest/gtest.h>
40 #include "gromacs/options/options.h"
41 #include "gromacs/options/optionsassigner.h"
42 #include "gromacs/selection/selection.h"
43 #include "gromacs/selection/selectioncollection.h"
44 #include "gromacs/selection/selectionfileoption.h"
45 #include "gromacs/selection/selectionoption.h"
46 #include "gromacs/selection/selectionoptioninfo.h"
47 #include "gromacs/selection/selectionoptionmanager.h"
48 #include "gromacs/utility/exceptions.h"
50 #include "testutils/datapath.h"
55 /********************************************************************
56 * Base fixture for tests in this file.
59 class SelectionOptionTestBase : public ::testing::Test
62 SelectionOptionTestBase();
66 gmx::SelectionCollection sc_;
67 gmx::SelectionOptionManager manager_;
68 gmx::Options options_;
71 SelectionOptionTestBase::SelectionOptionTestBase()
72 : manager_(&sc_), options_(NULL, NULL)
74 sc_.setReferencePosType("atom");
75 sc_.setOutputPosType("atom");
78 void SelectionOptionTestBase::setManager()
80 setManagerForSelectionOptions(&options_, &manager_);
84 /********************************************************************
85 * Tests for SelectionOption
88 typedef SelectionOptionTestBase SelectionOptionTest;
90 TEST_F(SelectionOptionTest, ParsesSimpleSelection)
93 using gmx::SelectionOption;
94 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
97 gmx::OptionsAssigner assigner(&options_);
98 EXPECT_NO_THROW(assigner.start());
99 ASSERT_NO_THROW(assigner.startOption("sel"));
100 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
101 EXPECT_NO_THROW(assigner.finishOption());
102 EXPECT_NO_THROW(assigner.finish());
103 EXPECT_NO_THROW(options_.finish());
105 ASSERT_FALSE(sel.isDynamic());
109 TEST_F(SelectionOptionTest, HandlesDynamicSelectionWhenStaticRequired)
112 using gmx::SelectionOption;
113 ASSERT_NO_THROW(options_.addOption(
114 SelectionOption("sel").store(&sel).onlyStatic()));
117 gmx::OptionsAssigner assigner(&options_);
118 EXPECT_NO_THROW(assigner.start());
119 ASSERT_NO_THROW(assigner.startOption("sel"));
120 EXPECT_THROW(assigner.appendValue("resname RA RB and x < 5"), gmx::InvalidInputError);
121 EXPECT_NO_THROW(assigner.finishOption());
122 EXPECT_NO_THROW(assigner.finish());
123 EXPECT_NO_THROW(options_.finish());
127 TEST_F(SelectionOptionTest, HandlesTooManySelections)
130 using gmx::SelectionOption;
131 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
134 gmx::OptionsAssigner assigner(&options_);
135 EXPECT_NO_THROW(assigner.start());
136 ASSERT_NO_THROW(assigner.startOption("sel"));
137 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
138 EXPECT_THROW(assigner.appendValue("resname RB RC"), gmx::InvalidInputError);
139 EXPECT_NO_THROW(assigner.finishOption());
140 EXPECT_NO_THROW(assigner.finish());
141 EXPECT_NO_THROW(options_.finish());
145 TEST_F(SelectionOptionTest, HandlesTooFewSelections)
147 gmx::Selection sel[2];
148 using gmx::SelectionOption;
149 ASSERT_NO_THROW(options_.addOption(
150 SelectionOption("sel").store(sel).valueCount(2)));
153 gmx::OptionsAssigner assigner(&options_);
154 EXPECT_NO_THROW(assigner.start());
155 ASSERT_NO_THROW(assigner.startOption("sel"));
156 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
157 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
158 EXPECT_NO_THROW(assigner.finish());
159 EXPECT_NO_THROW(options_.finish());
163 TEST_F(SelectionOptionTest, HandlesAdjuster)
165 gmx::SelectionList sel;
166 gmx::SelectionOptionInfo *info;
167 using gmx::SelectionOption;
168 ASSERT_NO_THROW(options_.addOption(
169 SelectionOption("sel").storeVector(&sel).multiValue()
170 .getAdjuster(&info)));
173 gmx::OptionsAssigner assigner(&options_);
174 EXPECT_NO_THROW(assigner.start());
175 ASSERT_NO_THROW(assigner.startOption("sel"));
176 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
177 EXPECT_NO_THROW(assigner.appendValue("resname RB RC"));
178 EXPECT_NO_THROW(assigner.finishOption());
179 EXPECT_NO_THROW(assigner.finish());
180 EXPECT_NO_THROW(options_.finish());
181 EXPECT_NO_THROW(info->setValueCount(2));
185 TEST_F(SelectionOptionTest, HandlesDynamicWhenStaticRequiredWithAdjuster)
188 gmx::SelectionOptionInfo *info;
189 using gmx::SelectionOption;
190 ASSERT_NO_THROW(options_.addOption(
191 SelectionOption("sel").store(&sel)
192 .getAdjuster(&info)));
195 gmx::OptionsAssigner assigner(&options_);
196 EXPECT_NO_THROW(assigner.start());
197 ASSERT_NO_THROW(assigner.startOption("sel"));
198 EXPECT_NO_THROW(assigner.appendValue("x < 5"));
199 EXPECT_NO_THROW(assigner.finishOption());
200 EXPECT_NO_THROW(assigner.finish());
201 EXPECT_NO_THROW(options_.finish());
202 EXPECT_THROW(info->setOnlyStatic(true), gmx::InvalidInputError);
206 TEST_F(SelectionOptionTest, HandlesTooManySelectionsWithAdjuster)
208 gmx::SelectionList sel;
209 gmx::SelectionOptionInfo *info;
210 using gmx::SelectionOption;
211 ASSERT_NO_THROW(options_.addOption(
212 SelectionOption("sel").storeVector(&sel).multiValue()
213 .getAdjuster(&info)));
216 gmx::OptionsAssigner assigner(&options_);
217 EXPECT_NO_THROW(assigner.start());
218 ASSERT_NO_THROW(assigner.startOption("sel"));
219 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
220 EXPECT_NO_THROW(assigner.appendValue("resname RB RC"));
221 EXPECT_NO_THROW(assigner.finishOption());
222 EXPECT_NO_THROW(assigner.finish());
223 EXPECT_NO_THROW(options_.finish());
224 EXPECT_THROW(info->setValueCount(1), gmx::InvalidInputError);
228 TEST_F(SelectionOptionTest, HandlesTooFewSelectionsWithAdjuster)
230 gmx::SelectionList sel;
231 gmx::SelectionOptionInfo *info;
232 using gmx::SelectionOption;
233 ASSERT_NO_THROW(options_.addOption(
234 SelectionOption("sel").storeVector(&sel).multiValue()
235 .getAdjuster(&info)));
238 gmx::OptionsAssigner assigner(&options_);
239 EXPECT_NO_THROW(assigner.start());
240 ASSERT_NO_THROW(assigner.startOption("sel"));
241 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
242 EXPECT_NO_THROW(assigner.finishOption());
243 EXPECT_NO_THROW(assigner.finish());
244 EXPECT_NO_THROW(options_.finish());
245 EXPECT_THROW(info->setValueCount(2), gmx::InvalidInputError);
249 TEST_F(SelectionOptionTest, HandlesDelayedRequiredSelection)
252 using gmx::SelectionOption;
253 ASSERT_NO_THROW(options_.addOption(
254 SelectionOption("sel").store(&sel).required()));
257 gmx::OptionsAssigner assigner(&options_);
258 EXPECT_NO_THROW(assigner.start());
259 EXPECT_NO_THROW(assigner.finish());
260 EXPECT_NO_THROW(options_.finish());
261 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
262 ASSERT_STREQ("resname RA RB", sel.selectionText());
266 TEST_F(SelectionOptionTest, HandlesTooFewDelayedRequiredSelections)
268 gmx::Selection sel[2];
269 using gmx::SelectionOption;
270 ASSERT_NO_THROW(options_.addOption(
271 SelectionOption("sel").store(sel).required()
275 gmx::OptionsAssigner assigner(&options_);
276 EXPECT_NO_THROW(assigner.start());
277 EXPECT_NO_THROW(assigner.finish());
278 EXPECT_NO_THROW(options_.finish());
279 EXPECT_THROW(manager_.parseRequestedFromString("resname RA RB"), gmx::InvalidInputError);
283 TEST_F(SelectionOptionTest, HandlesDelayedOptionalSelection)
286 using gmx::SelectionOption;
287 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
290 gmx::OptionsAssigner assigner(&options_);
291 EXPECT_NO_THROW(assigner.start());
292 ASSERT_NO_THROW(assigner.startOption("sel"));
293 EXPECT_NO_THROW(assigner.finishOption());
294 EXPECT_NO_THROW(assigner.finish());
295 EXPECT_NO_THROW(options_.finish());
296 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
297 ASSERT_STREQ("resname RA RB", sel.selectionText());
301 TEST_F(SelectionOptionTest, HandlesDelayedSelectionWithAdjuster)
303 gmx::SelectionList sel;
304 gmx::SelectionOptionInfo *info;
305 using gmx::SelectionOption;
306 ASSERT_NO_THROW(options_.addOption(
307 SelectionOption("sel").storeVector(&sel).valueCount(3)
308 .getAdjuster(&info)));
311 gmx::OptionsAssigner assigner(&options_);
312 EXPECT_NO_THROW(assigner.start());
313 ASSERT_NO_THROW(assigner.startOption("sel"));
314 EXPECT_NO_THROW(assigner.finishOption());
315 EXPECT_NO_THROW(assigner.finish());
316 EXPECT_NO_THROW(options_.finish());
317 EXPECT_NO_THROW(info->setValueCount(2));
318 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB; resname RB RC"));
322 /********************************************************************
323 * Tests for SelectionFileOption
326 class SelectionFileOptionTest : public SelectionOptionTestBase
329 SelectionFileOptionTest();
332 SelectionFileOptionTest::SelectionFileOptionTest()
334 options_.addOption(gmx::SelectionFileOption("sf"));
338 TEST_F(SelectionFileOptionTest, HandlesSingleSelectionOptionFromFile)
340 gmx::SelectionList sel;
341 gmx::SelectionList reqsel;
342 using gmx::SelectionOption;
343 ASSERT_NO_THROW(options_.addOption(
344 SelectionOption("sel").storeVector(&sel).multiValue()));
345 ASSERT_NO_THROW(options_.addOption(
346 SelectionOption("reqsel").storeVector(&reqsel)
347 .multiValue().required()));
350 gmx::OptionsAssigner assigner(&options_);
351 EXPECT_NO_THROW(assigner.start());
352 ASSERT_NO_THROW(assigner.startOption("sel"));
353 EXPECT_NO_THROW(assigner.finishOption());
354 ASSERT_NO_THROW(assigner.startOption("sf"));
355 EXPECT_NO_THROW(assigner.appendValue(gmx::test::TestFileManager::getTestFilePath("selfile.dat")));
356 EXPECT_NO_THROW(assigner.finishOption());
357 EXPECT_NO_THROW(assigner.finish());
358 EXPECT_NO_THROW(options_.finish());
360 // These should match the contents of selfile.dat
361 ASSERT_EQ(2U, sel.size());
362 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
363 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
364 ASSERT_EQ(0U, reqsel.size());
368 TEST_F(SelectionFileOptionTest, HandlesTwoSeparateSelectionOptions)
370 gmx::SelectionList sel1;
371 gmx::SelectionList sel2;
372 using gmx::SelectionOption;
373 ASSERT_NO_THROW(options_.addOption(
374 SelectionOption("sel1").storeVector(&sel1).multiValue()));
375 ASSERT_NO_THROW(options_.addOption(
376 SelectionOption("sel2").storeVector(&sel2).multiValue()));
379 gmx::OptionsAssigner assigner(&options_);
380 std::string value(gmx::test::TestFileManager::getTestFilePath("selfile.dat"));
381 EXPECT_NO_THROW(assigner.start());
382 ASSERT_NO_THROW(assigner.startOption("sel1"));
383 EXPECT_NO_THROW(assigner.finishOption());
384 ASSERT_NO_THROW(assigner.startOption("sf"));
385 EXPECT_NO_THROW(assigner.appendValue(value));
386 EXPECT_NO_THROW(assigner.finishOption());
387 ASSERT_NO_THROW(assigner.startOption("sel2"));
388 EXPECT_NO_THROW(assigner.finishOption());
389 ASSERT_NO_THROW(assigner.startOption("sf"));
390 EXPECT_NO_THROW(assigner.appendValue(value));
391 EXPECT_NO_THROW(assigner.finishOption());
392 EXPECT_NO_THROW(assigner.finish());
393 EXPECT_NO_THROW(options_.finish());
395 // These should match the contents of selfile.dat
396 ASSERT_EQ(2U, sel1.size());
397 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
398 EXPECT_STREQ("resname RB RC", sel1[1].selectionText());
399 ASSERT_EQ(2U, sel2.size());
400 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
401 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
405 TEST_F(SelectionFileOptionTest, HandlesTwoSelectionOptionsFromSingleFile)
407 gmx::SelectionList sel1;
408 gmx::SelectionList sel2;
409 using gmx::SelectionOption;
410 ASSERT_NO_THROW(options_.addOption(
411 SelectionOption("sel1").storeVector(&sel1)));
412 ASSERT_NO_THROW(options_.addOption(
413 SelectionOption("sel2").storeVector(&sel2)));
416 gmx::OptionsAssigner assigner(&options_);
417 std::string value(gmx::test::TestFileManager::getTestFilePath("selfile.dat"));
418 EXPECT_NO_THROW(assigner.start());
419 ASSERT_NO_THROW(assigner.startOption("sel1"));
420 EXPECT_NO_THROW(assigner.finishOption());
421 ASSERT_NO_THROW(assigner.startOption("sel2"));
422 EXPECT_NO_THROW(assigner.finishOption());
423 ASSERT_NO_THROW(assigner.startOption("sf"));
424 EXPECT_NO_THROW(assigner.appendValue(value));
425 EXPECT_NO_THROW(assigner.finishOption());
426 EXPECT_NO_THROW(assigner.finish());
427 EXPECT_NO_THROW(options_.finish());
429 // These should match the contents of selfile.dat
430 ASSERT_EQ(1U, sel1.size());
431 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
432 ASSERT_EQ(1U, sel2.size());
433 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
437 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFile)
439 gmx::SelectionList sel;
440 gmx::SelectionList optsel;
441 using gmx::SelectionOption;
442 ASSERT_NO_THROW(options_.addOption(
443 SelectionOption("sel").storeVector(&sel)
444 .multiValue().required()));
445 ASSERT_NO_THROW(options_.addOption(
446 SelectionOption("optsel").storeVector(&optsel)
450 gmx::OptionsAssigner assigner(&options_);
451 EXPECT_NO_THROW(assigner.start());
452 ASSERT_NO_THROW(assigner.startOption("sf"));
453 EXPECT_NO_THROW(assigner.appendValue(gmx::test::TestFileManager::getTestFilePath("selfile.dat")));
454 EXPECT_NO_THROW(assigner.finishOption());
455 EXPECT_NO_THROW(assigner.startOption("optsel"));
456 EXPECT_NO_THROW(assigner.finishOption());
457 EXPECT_NO_THROW(assigner.finish());
458 EXPECT_NO_THROW(options_.finish());
459 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RC RD"));
461 // These should match the contents of selfile.dat
462 ASSERT_EQ(2U, sel.size());
463 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
464 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
465 ASSERT_EQ(1U, optsel.size());
466 EXPECT_STREQ("resname RC RD", optsel[0].selectionText());
470 // TODO: Is this the best possible behavior, or should it error out?
471 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFileWithOtherOptionSet)
473 gmx::SelectionList sel1;
474 gmx::SelectionList sel2;
475 using gmx::SelectionOption;
476 ASSERT_NO_THROW(options_.addOption(
477 SelectionOption("sel1").storeVector(&sel1)
478 .multiValue().required()));
479 ASSERT_NO_THROW(options_.addOption(
480 SelectionOption("sel2").storeVector(&sel2)
481 .multiValue().required()));
484 gmx::OptionsAssigner assigner(&options_);
485 EXPECT_NO_THROW(assigner.start());
486 EXPECT_NO_THROW(assigner.startOption("sel1"));
487 EXPECT_NO_THROW(assigner.appendValue("resname RC RD"));
488 EXPECT_NO_THROW(assigner.finishOption());
489 ASSERT_NO_THROW(assigner.startOption("sf"));
490 EXPECT_NO_THROW(assigner.appendValue(gmx::test::TestFileManager::getTestFilePath("selfile.dat")));
491 EXPECT_NO_THROW(assigner.finishOption());
492 EXPECT_NO_THROW(assigner.finish());
493 EXPECT_NO_THROW(options_.finish());
495 // These should match the contents of selfile.dat
496 ASSERT_EQ(2U, sel2.size());
497 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
498 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
499 ASSERT_EQ(1U, sel1.size());
500 EXPECT_STREQ("resname RC RD", sel1[0].selectionText());
504 TEST_F(SelectionFileOptionTest, HandlesTwoRequiredOptionsFromSingleFile)
506 gmx::SelectionList sel1;
507 gmx::SelectionList sel2;
508 using gmx::SelectionOption;
509 ASSERT_NO_THROW(options_.addOption(
510 SelectionOption("sel1").storeVector(&sel1).required()));
511 ASSERT_NO_THROW(options_.addOption(
512 SelectionOption("sel2").storeVector(&sel2).required()));
515 gmx::OptionsAssigner assigner(&options_);
516 std::string value(gmx::test::TestFileManager::getTestFilePath("selfile.dat"));
517 EXPECT_NO_THROW(assigner.start());
518 ASSERT_NO_THROW(assigner.startOption("sf"));
519 EXPECT_NO_THROW(assigner.appendValue(value));
520 EXPECT_NO_THROW(assigner.finishOption());
521 EXPECT_NO_THROW(assigner.finish());
522 EXPECT_NO_THROW(options_.finish());
524 // These should match the contents of selfile.dat
525 ASSERT_EQ(1U, sel1.size());
526 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
527 ASSERT_EQ(1U, sel2.size());
528 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
532 TEST_F(SelectionFileOptionTest, GivesErrorWithNoFile)
534 gmx::SelectionList sel;
535 using gmx::SelectionOption;
536 ASSERT_NO_THROW(options_.addOption(
537 SelectionOption("sel").storeVector(&sel).multiValue()));
540 gmx::OptionsAssigner assigner(&options_);
541 EXPECT_NO_THROW(assigner.start());
542 ASSERT_NO_THROW(assigner.startOption("sel"));
543 EXPECT_NO_THROW(assigner.finishOption());
544 ASSERT_NO_THROW(assigner.startOption("sf"));
545 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
546 EXPECT_NO_THROW(assigner.finish());
547 EXPECT_NO_THROW(options_.finish());
551 TEST_F(SelectionFileOptionTest, GivesErrorWithNonExistentFile)
553 gmx::SelectionList sel;
554 using gmx::SelectionOption;
555 ASSERT_NO_THROW(options_.addOption(
556 SelectionOption("sel").storeVector(&sel).multiValue()));
559 gmx::OptionsAssigner assigner(&options_);
560 EXPECT_NO_THROW(assigner.start());
561 ASSERT_NO_THROW(assigner.startOption("sel"));
562 EXPECT_NO_THROW(assigner.finishOption());
563 ASSERT_NO_THROW(assigner.startOption("sf"));
564 // TODO: Should this be changed to an InvalidInputError?
565 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::FileIOError);
566 EXPECT_THROW(assigner.appendValue(gmx::test::TestFileManager::getTestFilePath("selfile.dat")),
567 gmx::InvalidInputError);
568 EXPECT_NO_THROW(assigner.finishOption());
569 EXPECT_NO_THROW(assigner.finish());
570 EXPECT_NO_THROW(options_.finish());
574 TEST_F(SelectionFileOptionTest, GivesErrorWithMultipleFiles)
576 gmx::SelectionList sel;
577 using gmx::SelectionOption;
578 ASSERT_NO_THROW(options_.addOption(
579 SelectionOption("sel").storeVector(&sel).multiValue()));
582 gmx::OptionsAssigner assigner(&options_);
583 EXPECT_NO_THROW(assigner.start());
584 ASSERT_NO_THROW(assigner.startOption("sel"));
585 EXPECT_NO_THROW(assigner.finishOption());
586 ASSERT_NO_THROW(assigner.startOption("sf"));
587 EXPECT_NO_THROW(assigner.appendValue(gmx::test::TestFileManager::getTestFilePath("selfile.dat")));
588 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::InvalidInputError);
589 EXPECT_NO_THROW(assigner.finishOption());
590 EXPECT_NO_THROW(assigner.finish());
591 EXPECT_NO_THROW(options_.finish());