2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
5 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6 * others, as listed in the AUTHORS file in the top-level source
7 * directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Tests handling of selection options.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
42 #include <gtest/gtest.h>
44 #include "gromacs/options/options.h"
45 #include "gromacs/options/optionsassigner.h"
46 #include "gromacs/selection/selection.h"
47 #include "gromacs/selection/selectioncollection.h"
48 #include "gromacs/selection/selectionfileoption.h"
49 #include "gromacs/selection/selectionoption.h"
50 #include "gromacs/selection/selectionoptionmanager.h"
51 #include "gromacs/utility/exceptions.h"
53 #include "testutils/testfilemanager.h"
55 using gmx::test::TestFileManager;
60 /********************************************************************
61 * Base fixture for tests in this file.
64 class SelectionOptionTestBase : public ::testing::Test
67 SelectionOptionTestBase();
71 gmx::SelectionCollection sc_;
72 gmx::SelectionOptionManager manager_;
73 gmx::Options options_;
76 SelectionOptionTestBase::SelectionOptionTestBase()
77 : manager_(&sc_), options_(NULL, NULL)
79 sc_.setReferencePosType("atom");
80 sc_.setOutputPosType("atom");
83 void SelectionOptionTestBase::setManager()
85 setManagerForSelectionOptions(&options_, &manager_);
89 /********************************************************************
90 * Tests for SelectionOption
93 //! Test fixture for gmx::SelectionOption.
94 typedef SelectionOptionTestBase SelectionOptionTest;
96 TEST_F(SelectionOptionTest, ParsesSimpleSelection)
99 using gmx::SelectionOption;
100 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
103 gmx::OptionsAssigner assigner(&options_);
104 EXPECT_NO_THROW(assigner.start());
105 ASSERT_NO_THROW(assigner.startOption("sel"));
106 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
107 EXPECT_NO_THROW(assigner.finishOption());
108 EXPECT_NO_THROW(assigner.finish());
109 EXPECT_NO_THROW(options_.finish());
113 TEST_F(SelectionOptionTest, HandlesDynamicSelectionWhenStaticRequired)
116 using gmx::SelectionOption;
117 ASSERT_NO_THROW(options_.addOption(
118 SelectionOption("sel").store(&sel).onlyStatic()));
121 gmx::OptionsAssigner assigner(&options_);
122 EXPECT_NO_THROW(assigner.start());
123 ASSERT_NO_THROW(assigner.startOption("sel"));
124 EXPECT_THROW(assigner.appendValue("resname RA RB and x < 5"), gmx::InvalidInputError);
125 EXPECT_NO_THROW(assigner.finishOption());
126 EXPECT_NO_THROW(assigner.finish());
127 EXPECT_NO_THROW(options_.finish());
131 TEST_F(SelectionOptionTest, HandlesTooManySelections)
134 using gmx::SelectionOption;
135 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
138 gmx::OptionsAssigner assigner(&options_);
139 EXPECT_NO_THROW(assigner.start());
140 ASSERT_NO_THROW(assigner.startOption("sel"));
141 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
142 EXPECT_THROW(assigner.appendValue("resname RB RC"), gmx::InvalidInputError);
143 EXPECT_NO_THROW(assigner.finishOption());
144 EXPECT_NO_THROW(assigner.finish());
145 EXPECT_NO_THROW(options_.finish());
149 TEST_F(SelectionOptionTest, HandlesTooFewSelections)
151 gmx::Selection sel[2];
152 using gmx::SelectionOption;
153 ASSERT_NO_THROW(options_.addOption(
154 SelectionOption("sel").store(sel).valueCount(2)));
157 gmx::OptionsAssigner assigner(&options_);
158 EXPECT_NO_THROW(assigner.start());
159 ASSERT_NO_THROW(assigner.startOption("sel"));
160 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
161 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
162 EXPECT_NO_THROW(assigner.finish());
163 EXPECT_NO_THROW(options_.finish());
167 TEST_F(SelectionOptionTest, HandlesAdjuster)
169 gmx::SelectionList sel;
170 using gmx::SelectionOption;
171 gmx::SelectionOptionInfo *info = options_.addOption(
172 SelectionOption("sel").storeVector(&sel).multiValue());
175 gmx::OptionsAssigner assigner(&options_);
176 EXPECT_NO_THROW(assigner.start());
177 ASSERT_NO_THROW(assigner.startOption("sel"));
178 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
179 EXPECT_NO_THROW(assigner.appendValue("resname RB RC"));
180 EXPECT_NO_THROW(assigner.finishOption());
181 EXPECT_NO_THROW(assigner.finish());
182 EXPECT_NO_THROW(options_.finish());
183 EXPECT_NO_THROW(info->setValueCount(2));
187 TEST_F(SelectionOptionTest, HandlesDynamicWhenStaticRequiredWithAdjuster)
190 using gmx::SelectionOption;
191 gmx::SelectionOptionInfo *info = options_.addOption(
192 SelectionOption("sel").store(&sel));
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 using gmx::SelectionOption;
210 gmx::SelectionOptionInfo *info = options_.addOption(
211 SelectionOption("sel").storeVector(&sel).multiValue());
214 gmx::OptionsAssigner assigner(&options_);
215 EXPECT_NO_THROW(assigner.start());
216 ASSERT_NO_THROW(assigner.startOption("sel"));
217 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
218 EXPECT_NO_THROW(assigner.appendValue("resname RB RC"));
219 EXPECT_NO_THROW(assigner.finishOption());
220 EXPECT_NO_THROW(assigner.finish());
221 EXPECT_NO_THROW(options_.finish());
222 EXPECT_THROW(info->setValueCount(1), gmx::InvalidInputError);
226 TEST_F(SelectionOptionTest, HandlesTooFewSelectionsWithAdjuster)
228 gmx::SelectionList sel;
229 using gmx::SelectionOption;
230 gmx::SelectionOptionInfo *info = options_.addOption(
231 SelectionOption("sel").storeVector(&sel).multiValue());
234 gmx::OptionsAssigner assigner(&options_);
235 EXPECT_NO_THROW(assigner.start());
236 ASSERT_NO_THROW(assigner.startOption("sel"));
237 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
238 EXPECT_NO_THROW(assigner.finishOption());
239 EXPECT_NO_THROW(assigner.finish());
240 EXPECT_NO_THROW(options_.finish());
241 EXPECT_THROW(info->setValueCount(2), gmx::InvalidInputError);
245 TEST_F(SelectionOptionTest, HandlesDelayedRequiredSelection)
248 using gmx::SelectionOption;
249 ASSERT_NO_THROW(options_.addOption(
250 SelectionOption("sel").store(&sel).required()));
253 gmx::OptionsAssigner assigner(&options_);
254 EXPECT_NO_THROW(assigner.start());
255 EXPECT_NO_THROW(assigner.finish());
256 EXPECT_NO_THROW(options_.finish());
257 ASSERT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
258 ASSERT_STREQ("resname RA RB", sel.selectionText());
262 TEST_F(SelectionOptionTest, HandlesTooFewDelayedRequiredSelections)
264 gmx::Selection sel[2];
265 using gmx::SelectionOption;
266 ASSERT_NO_THROW(options_.addOption(
267 SelectionOption("sel").store(sel).required()
271 gmx::OptionsAssigner assigner(&options_);
272 EXPECT_NO_THROW(assigner.start());
273 EXPECT_NO_THROW(assigner.finish());
274 EXPECT_NO_THROW(options_.finish());
275 EXPECT_THROW(manager_.parseRequestedFromString("resname RA RB"), gmx::InvalidInputError);
279 TEST_F(SelectionOptionTest, HandlesDelayedOptionalSelection)
282 using gmx::SelectionOption;
283 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
286 gmx::OptionsAssigner assigner(&options_);
287 EXPECT_NO_THROW(assigner.start());
288 ASSERT_NO_THROW(assigner.startOption("sel"));
289 EXPECT_NO_THROW(assigner.finishOption());
290 EXPECT_NO_THROW(assigner.finish());
291 EXPECT_NO_THROW(options_.finish());
292 ASSERT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
293 ASSERT_STREQ("resname RA RB", sel.selectionText());
297 TEST_F(SelectionOptionTest, HandlesDelayedSelectionWithAdjuster)
299 gmx::SelectionList sel;
300 using gmx::SelectionOption;
301 gmx::SelectionOptionInfo *info = options_.addOption(
302 SelectionOption("sel").storeVector(&sel).valueCount(3));
305 gmx::OptionsAssigner assigner(&options_);
306 EXPECT_NO_THROW(assigner.start());
307 ASSERT_NO_THROW(assigner.startOption("sel"));
308 EXPECT_NO_THROW(assigner.finishOption());
309 EXPECT_NO_THROW(assigner.finish());
310 EXPECT_NO_THROW(options_.finish());
311 EXPECT_NO_THROW(info->setValueCount(2));
312 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB; resname RB RC"));
316 /********************************************************************
317 * Tests for SelectionFileOption
320 class SelectionFileOptionTest : public SelectionOptionTestBase
323 SelectionFileOptionTest();
326 SelectionFileOptionTest::SelectionFileOptionTest()
328 options_.addOption(gmx::SelectionFileOption("sf"));
332 TEST_F(SelectionFileOptionTest, HandlesSingleSelectionOptionFromFile)
334 gmx::SelectionList sel;
335 gmx::SelectionList reqsel;
336 using gmx::SelectionOption;
337 ASSERT_NO_THROW(options_.addOption(
338 SelectionOption("sel").storeVector(&sel).multiValue()));
339 ASSERT_NO_THROW(options_.addOption(
340 SelectionOption("reqsel").storeVector(&reqsel)
341 .multiValue().required()));
344 gmx::OptionsAssigner assigner(&options_);
345 EXPECT_NO_THROW(assigner.start());
346 ASSERT_NO_THROW(assigner.startOption("sel"));
347 EXPECT_NO_THROW(assigner.finishOption());
348 ASSERT_NO_THROW(assigner.startOption("sf"));
349 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
350 EXPECT_NO_THROW(assigner.finishOption());
351 EXPECT_NO_THROW(assigner.finish());
352 EXPECT_NO_THROW(options_.finish());
354 // These should match the contents of selfile.dat
355 ASSERT_EQ(2U, sel.size());
356 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
357 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
358 ASSERT_EQ(0U, reqsel.size());
362 TEST_F(SelectionFileOptionTest, HandlesTwoSeparateSelectionOptions)
364 gmx::SelectionList sel1;
365 gmx::SelectionList sel2;
366 using gmx::SelectionOption;
367 ASSERT_NO_THROW(options_.addOption(
368 SelectionOption("sel1").storeVector(&sel1).multiValue()));
369 ASSERT_NO_THROW(options_.addOption(
370 SelectionOption("sel2").storeVector(&sel2).multiValue()));
373 gmx::OptionsAssigner assigner(&options_);
374 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
375 EXPECT_NO_THROW(assigner.start());
376 ASSERT_NO_THROW(assigner.startOption("sel1"));
377 EXPECT_NO_THROW(assigner.finishOption());
378 ASSERT_NO_THROW(assigner.startOption("sf"));
379 EXPECT_NO_THROW(assigner.appendValue(value));
380 EXPECT_NO_THROW(assigner.finishOption());
381 ASSERT_NO_THROW(assigner.startOption("sel2"));
382 EXPECT_NO_THROW(assigner.finishOption());
383 ASSERT_NO_THROW(assigner.startOption("sf"));
384 EXPECT_NO_THROW(assigner.appendValue(value));
385 EXPECT_NO_THROW(assigner.finishOption());
386 EXPECT_NO_THROW(assigner.finish());
387 EXPECT_NO_THROW(options_.finish());
389 // These should match the contents of selfile.dat
390 ASSERT_EQ(2U, sel1.size());
391 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
392 EXPECT_STREQ("resname RB RC", sel1[1].selectionText());
393 ASSERT_EQ(2U, sel2.size());
394 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
395 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
399 TEST_F(SelectionFileOptionTest, HandlesTwoSelectionOptionsFromSingleFile)
401 gmx::SelectionList sel1;
402 gmx::SelectionList sel2;
403 using gmx::SelectionOption;
404 ASSERT_NO_THROW(options_.addOption(
405 SelectionOption("sel1").storeVector(&sel1)));
406 ASSERT_NO_THROW(options_.addOption(
407 SelectionOption("sel2").storeVector(&sel2)));
410 gmx::OptionsAssigner assigner(&options_);
411 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
412 EXPECT_NO_THROW(assigner.start());
413 ASSERT_NO_THROW(assigner.startOption("sel1"));
414 EXPECT_NO_THROW(assigner.finishOption());
415 ASSERT_NO_THROW(assigner.startOption("sel2"));
416 EXPECT_NO_THROW(assigner.finishOption());
417 ASSERT_NO_THROW(assigner.startOption("sf"));
418 EXPECT_NO_THROW(assigner.appendValue(value));
419 EXPECT_NO_THROW(assigner.finishOption());
420 EXPECT_NO_THROW(assigner.finish());
421 EXPECT_NO_THROW(options_.finish());
423 // These should match the contents of selfile.dat
424 ASSERT_EQ(1U, sel1.size());
425 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
426 ASSERT_EQ(1U, sel2.size());
427 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
431 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFile)
433 gmx::SelectionList sel;
434 gmx::SelectionList optsel;
435 using gmx::SelectionOption;
436 ASSERT_NO_THROW(options_.addOption(
437 SelectionOption("sel").storeVector(&sel)
438 .multiValue().required()));
439 ASSERT_NO_THROW(options_.addOption(
440 SelectionOption("optsel").storeVector(&optsel)
444 gmx::OptionsAssigner assigner(&options_);
445 EXPECT_NO_THROW(assigner.start());
446 ASSERT_NO_THROW(assigner.startOption("sf"));
447 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
448 EXPECT_NO_THROW(assigner.finishOption());
449 EXPECT_NO_THROW(assigner.startOption("optsel"));
450 EXPECT_NO_THROW(assigner.finishOption());
451 EXPECT_NO_THROW(assigner.finish());
452 EXPECT_NO_THROW(options_.finish());
453 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RC RD"));
455 // These should match the contents of selfile.dat
456 ASSERT_EQ(2U, sel.size());
457 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
458 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
459 ASSERT_EQ(1U, optsel.size());
460 EXPECT_STREQ("resname RC RD", optsel[0].selectionText());
464 // TODO: Is this the best possible behavior, or should it error out?
465 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFileWithOtherOptionSet)
467 gmx::SelectionList sel1;
468 gmx::SelectionList sel2;
469 using gmx::SelectionOption;
470 ASSERT_NO_THROW(options_.addOption(
471 SelectionOption("sel1").storeVector(&sel1)
472 .multiValue().required()));
473 ASSERT_NO_THROW(options_.addOption(
474 SelectionOption("sel2").storeVector(&sel2)
475 .multiValue().required()));
478 gmx::OptionsAssigner assigner(&options_);
479 EXPECT_NO_THROW(assigner.start());
480 EXPECT_NO_THROW(assigner.startOption("sel1"));
481 EXPECT_NO_THROW(assigner.appendValue("resname RC RD"));
482 EXPECT_NO_THROW(assigner.finishOption());
483 ASSERT_NO_THROW(assigner.startOption("sf"));
484 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
485 EXPECT_NO_THROW(assigner.finishOption());
486 EXPECT_NO_THROW(assigner.finish());
487 EXPECT_NO_THROW(options_.finish());
489 // These should match the contents of selfile.dat
490 ASSERT_EQ(2U, sel2.size());
491 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
492 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
493 ASSERT_EQ(1U, sel1.size());
494 EXPECT_STREQ("resname RC RD", sel1[0].selectionText());
498 TEST_F(SelectionFileOptionTest, HandlesTwoRequiredOptionsFromSingleFile)
500 gmx::SelectionList sel1;
501 gmx::SelectionList sel2;
502 using gmx::SelectionOption;
503 ASSERT_NO_THROW(options_.addOption(
504 SelectionOption("sel1").storeVector(&sel1).required()));
505 ASSERT_NO_THROW(options_.addOption(
506 SelectionOption("sel2").storeVector(&sel2).required()));
509 gmx::OptionsAssigner assigner(&options_);
510 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
511 EXPECT_NO_THROW(assigner.start());
512 ASSERT_NO_THROW(assigner.startOption("sf"));
513 EXPECT_NO_THROW(assigner.appendValue(value));
514 EXPECT_NO_THROW(assigner.finishOption());
515 EXPECT_NO_THROW(assigner.finish());
516 EXPECT_NO_THROW(options_.finish());
518 // These should match the contents of selfile.dat
519 ASSERT_EQ(1U, sel1.size());
520 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
521 ASSERT_EQ(1U, sel2.size());
522 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
526 TEST_F(SelectionFileOptionTest, GivesErrorWithNoFile)
528 gmx::SelectionList sel;
529 using gmx::SelectionOption;
530 ASSERT_NO_THROW(options_.addOption(
531 SelectionOption("sel").storeVector(&sel).multiValue()));
534 gmx::OptionsAssigner assigner(&options_);
535 EXPECT_NO_THROW(assigner.start());
536 ASSERT_NO_THROW(assigner.startOption("sel"));
537 EXPECT_NO_THROW(assigner.finishOption());
538 ASSERT_NO_THROW(assigner.startOption("sf"));
539 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
540 EXPECT_NO_THROW(assigner.finish());
541 EXPECT_NO_THROW(options_.finish());
545 TEST_F(SelectionFileOptionTest, GivesErrorWithNonExistentFile)
547 gmx::SelectionList sel;
548 using gmx::SelectionOption;
549 ASSERT_NO_THROW(options_.addOption(
550 SelectionOption("sel").storeVector(&sel).multiValue()));
553 gmx::OptionsAssigner assigner(&options_);
554 EXPECT_NO_THROW(assigner.start());
555 ASSERT_NO_THROW(assigner.startOption("sel"));
556 EXPECT_NO_THROW(assigner.finishOption());
557 ASSERT_NO_THROW(assigner.startOption("sf"));
558 // TODO: Should this be changed to an InvalidInputError?
559 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::FileIOError);
560 EXPECT_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")),
561 gmx::InvalidInputError);
562 EXPECT_NO_THROW(assigner.finishOption());
563 EXPECT_NO_THROW(assigner.finish());
564 EXPECT_NO_THROW(options_.finish());
568 TEST_F(SelectionFileOptionTest, GivesErrorWithMultipleFiles)
570 gmx::SelectionList sel;
571 using gmx::SelectionOption;
572 ASSERT_NO_THROW(options_.addOption(
573 SelectionOption("sel").storeVector(&sel).multiValue()));
576 gmx::OptionsAssigner assigner(&options_);
577 EXPECT_NO_THROW(assigner.start());
578 ASSERT_NO_THROW(assigner.startOption("sel"));
579 EXPECT_NO_THROW(assigner.finishOption());
580 ASSERT_NO_THROW(assigner.startOption("sf"));
581 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
582 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::InvalidInputError);
583 EXPECT_NO_THROW(assigner.finishOption());
584 EXPECT_NO_THROW(assigner.finish());
585 EXPECT_NO_THROW(options_.finish());