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/testfilemanager.h"
52 using gmx::test::TestFileManager;
57 /********************************************************************
58 * Base fixture for tests in this file.
61 class SelectionOptionTestBase : public ::testing::Test
64 SelectionOptionTestBase();
68 gmx::SelectionCollection sc_;
69 gmx::SelectionOptionManager manager_;
70 gmx::Options options_;
73 SelectionOptionTestBase::SelectionOptionTestBase()
74 : manager_(&sc_), options_(NULL, NULL)
76 sc_.setReferencePosType("atom");
77 sc_.setOutputPosType("atom");
80 void SelectionOptionTestBase::setManager()
82 setManagerForSelectionOptions(&options_, &manager_);
86 /********************************************************************
87 * Tests for SelectionOption
90 typedef SelectionOptionTestBase SelectionOptionTest;
92 TEST_F(SelectionOptionTest, ParsesSimpleSelection)
95 using gmx::SelectionOption;
96 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
99 gmx::OptionsAssigner assigner(&options_);
100 EXPECT_NO_THROW(assigner.start());
101 ASSERT_NO_THROW(assigner.startOption("sel"));
102 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
103 EXPECT_NO_THROW(assigner.finishOption());
104 EXPECT_NO_THROW(assigner.finish());
105 EXPECT_NO_THROW(options_.finish());
107 ASSERT_FALSE(sel.isDynamic());
111 TEST_F(SelectionOptionTest, HandlesDynamicSelectionWhenStaticRequired)
114 using gmx::SelectionOption;
115 ASSERT_NO_THROW(options_.addOption(
116 SelectionOption("sel").store(&sel).onlyStatic()));
119 gmx::OptionsAssigner assigner(&options_);
120 EXPECT_NO_THROW(assigner.start());
121 ASSERT_NO_THROW(assigner.startOption("sel"));
122 EXPECT_THROW(assigner.appendValue("resname RA RB and x < 5"), gmx::InvalidInputError);
123 EXPECT_NO_THROW(assigner.finishOption());
124 EXPECT_NO_THROW(assigner.finish());
125 EXPECT_NO_THROW(options_.finish());
129 TEST_F(SelectionOptionTest, HandlesTooManySelections)
132 using gmx::SelectionOption;
133 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
136 gmx::OptionsAssigner assigner(&options_);
137 EXPECT_NO_THROW(assigner.start());
138 ASSERT_NO_THROW(assigner.startOption("sel"));
139 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
140 EXPECT_THROW(assigner.appendValue("resname RB RC"), gmx::InvalidInputError);
141 EXPECT_NO_THROW(assigner.finishOption());
142 EXPECT_NO_THROW(assigner.finish());
143 EXPECT_NO_THROW(options_.finish());
147 TEST_F(SelectionOptionTest, HandlesTooFewSelections)
149 gmx::Selection sel[2];
150 using gmx::SelectionOption;
151 ASSERT_NO_THROW(options_.addOption(
152 SelectionOption("sel").store(sel).valueCount(2)));
155 gmx::OptionsAssigner assigner(&options_);
156 EXPECT_NO_THROW(assigner.start());
157 ASSERT_NO_THROW(assigner.startOption("sel"));
158 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
159 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
160 EXPECT_NO_THROW(assigner.finish());
161 EXPECT_NO_THROW(options_.finish());
165 TEST_F(SelectionOptionTest, HandlesAdjuster)
167 gmx::SelectionList sel;
168 gmx::SelectionOptionInfo *info;
169 using gmx::SelectionOption;
170 ASSERT_NO_THROW(options_.addOption(
171 SelectionOption("sel").storeVector(&sel).multiValue()
172 .getAdjuster(&info)));
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 gmx::SelectionOptionInfo *info;
191 using gmx::SelectionOption;
192 ASSERT_NO_THROW(options_.addOption(
193 SelectionOption("sel").store(&sel)
194 .getAdjuster(&info)));
197 gmx::OptionsAssigner assigner(&options_);
198 EXPECT_NO_THROW(assigner.start());
199 ASSERT_NO_THROW(assigner.startOption("sel"));
200 EXPECT_NO_THROW(assigner.appendValue("x < 5"));
201 EXPECT_NO_THROW(assigner.finishOption());
202 EXPECT_NO_THROW(assigner.finish());
203 EXPECT_NO_THROW(options_.finish());
204 EXPECT_THROW(info->setOnlyStatic(true), gmx::InvalidInputError);
208 TEST_F(SelectionOptionTest, HandlesTooManySelectionsWithAdjuster)
210 gmx::SelectionList sel;
211 gmx::SelectionOptionInfo *info;
212 using gmx::SelectionOption;
213 ASSERT_NO_THROW(options_.addOption(
214 SelectionOption("sel").storeVector(&sel).multiValue()
215 .getAdjuster(&info)));
218 gmx::OptionsAssigner assigner(&options_);
219 EXPECT_NO_THROW(assigner.start());
220 ASSERT_NO_THROW(assigner.startOption("sel"));
221 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
222 EXPECT_NO_THROW(assigner.appendValue("resname RB RC"));
223 EXPECT_NO_THROW(assigner.finishOption());
224 EXPECT_NO_THROW(assigner.finish());
225 EXPECT_NO_THROW(options_.finish());
226 EXPECT_THROW(info->setValueCount(1), gmx::InvalidInputError);
230 TEST_F(SelectionOptionTest, HandlesTooFewSelectionsWithAdjuster)
232 gmx::SelectionList sel;
233 gmx::SelectionOptionInfo *info;
234 using gmx::SelectionOption;
235 ASSERT_NO_THROW(options_.addOption(
236 SelectionOption("sel").storeVector(&sel).multiValue()
237 .getAdjuster(&info)));
240 gmx::OptionsAssigner assigner(&options_);
241 EXPECT_NO_THROW(assigner.start());
242 ASSERT_NO_THROW(assigner.startOption("sel"));
243 EXPECT_NO_THROW(assigner.appendValue("resname RA RB"));
244 EXPECT_NO_THROW(assigner.finishOption());
245 EXPECT_NO_THROW(assigner.finish());
246 EXPECT_NO_THROW(options_.finish());
247 EXPECT_THROW(info->setValueCount(2), gmx::InvalidInputError);
251 TEST_F(SelectionOptionTest, HandlesDelayedRequiredSelection)
254 using gmx::SelectionOption;
255 ASSERT_NO_THROW(options_.addOption(
256 SelectionOption("sel").store(&sel).required()));
259 gmx::OptionsAssigner assigner(&options_);
260 EXPECT_NO_THROW(assigner.start());
261 EXPECT_NO_THROW(assigner.finish());
262 EXPECT_NO_THROW(options_.finish());
263 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
264 ASSERT_STREQ("resname RA RB", sel.selectionText());
268 TEST_F(SelectionOptionTest, HandlesTooFewDelayedRequiredSelections)
270 gmx::Selection sel[2];
271 using gmx::SelectionOption;
272 ASSERT_NO_THROW(options_.addOption(
273 SelectionOption("sel").store(sel).required()
277 gmx::OptionsAssigner assigner(&options_);
278 EXPECT_NO_THROW(assigner.start());
279 EXPECT_NO_THROW(assigner.finish());
280 EXPECT_NO_THROW(options_.finish());
281 EXPECT_THROW(manager_.parseRequestedFromString("resname RA RB"), gmx::InvalidInputError);
285 TEST_F(SelectionOptionTest, HandlesDelayedOptionalSelection)
288 using gmx::SelectionOption;
289 ASSERT_NO_THROW(options_.addOption(SelectionOption("sel").store(&sel)));
292 gmx::OptionsAssigner assigner(&options_);
293 EXPECT_NO_THROW(assigner.start());
294 ASSERT_NO_THROW(assigner.startOption("sel"));
295 EXPECT_NO_THROW(assigner.finishOption());
296 EXPECT_NO_THROW(assigner.finish());
297 EXPECT_NO_THROW(options_.finish());
298 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB"));
299 ASSERT_STREQ("resname RA RB", sel.selectionText());
303 TEST_F(SelectionOptionTest, HandlesDelayedSelectionWithAdjuster)
305 gmx::SelectionList sel;
306 gmx::SelectionOptionInfo *info;
307 using gmx::SelectionOption;
308 ASSERT_NO_THROW(options_.addOption(
309 SelectionOption("sel").storeVector(&sel).valueCount(3)
310 .getAdjuster(&info)));
313 gmx::OptionsAssigner assigner(&options_);
314 EXPECT_NO_THROW(assigner.start());
315 ASSERT_NO_THROW(assigner.startOption("sel"));
316 EXPECT_NO_THROW(assigner.finishOption());
317 EXPECT_NO_THROW(assigner.finish());
318 EXPECT_NO_THROW(options_.finish());
319 EXPECT_NO_THROW(info->setValueCount(2));
320 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RA RB; resname RB RC"));
324 /********************************************************************
325 * Tests for SelectionFileOption
328 class SelectionFileOptionTest : public SelectionOptionTestBase
331 SelectionFileOptionTest();
334 SelectionFileOptionTest::SelectionFileOptionTest()
336 options_.addOption(gmx::SelectionFileOption("sf"));
340 TEST_F(SelectionFileOptionTest, HandlesSingleSelectionOptionFromFile)
342 gmx::SelectionList sel;
343 gmx::SelectionList reqsel;
344 using gmx::SelectionOption;
345 ASSERT_NO_THROW(options_.addOption(
346 SelectionOption("sel").storeVector(&sel).multiValue()));
347 ASSERT_NO_THROW(options_.addOption(
348 SelectionOption("reqsel").storeVector(&reqsel)
349 .multiValue().required()));
352 gmx::OptionsAssigner assigner(&options_);
353 EXPECT_NO_THROW(assigner.start());
354 ASSERT_NO_THROW(assigner.startOption("sel"));
355 EXPECT_NO_THROW(assigner.finishOption());
356 ASSERT_NO_THROW(assigner.startOption("sf"));
357 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
358 EXPECT_NO_THROW(assigner.finishOption());
359 EXPECT_NO_THROW(assigner.finish());
360 EXPECT_NO_THROW(options_.finish());
362 // These should match the contents of selfile.dat
363 ASSERT_EQ(2U, sel.size());
364 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
365 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
366 ASSERT_EQ(0U, reqsel.size());
370 TEST_F(SelectionFileOptionTest, HandlesTwoSeparateSelectionOptions)
372 gmx::SelectionList sel1;
373 gmx::SelectionList sel2;
374 using gmx::SelectionOption;
375 ASSERT_NO_THROW(options_.addOption(
376 SelectionOption("sel1").storeVector(&sel1).multiValue()));
377 ASSERT_NO_THROW(options_.addOption(
378 SelectionOption("sel2").storeVector(&sel2).multiValue()));
381 gmx::OptionsAssigner assigner(&options_);
382 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
383 EXPECT_NO_THROW(assigner.start());
384 ASSERT_NO_THROW(assigner.startOption("sel1"));
385 EXPECT_NO_THROW(assigner.finishOption());
386 ASSERT_NO_THROW(assigner.startOption("sf"));
387 EXPECT_NO_THROW(assigner.appendValue(value));
388 EXPECT_NO_THROW(assigner.finishOption());
389 ASSERT_NO_THROW(assigner.startOption("sel2"));
390 EXPECT_NO_THROW(assigner.finishOption());
391 ASSERT_NO_THROW(assigner.startOption("sf"));
392 EXPECT_NO_THROW(assigner.appendValue(value));
393 EXPECT_NO_THROW(assigner.finishOption());
394 EXPECT_NO_THROW(assigner.finish());
395 EXPECT_NO_THROW(options_.finish());
397 // These should match the contents of selfile.dat
398 ASSERT_EQ(2U, sel1.size());
399 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
400 EXPECT_STREQ("resname RB RC", sel1[1].selectionText());
401 ASSERT_EQ(2U, sel2.size());
402 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
403 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
407 TEST_F(SelectionFileOptionTest, HandlesTwoSelectionOptionsFromSingleFile)
409 gmx::SelectionList sel1;
410 gmx::SelectionList sel2;
411 using gmx::SelectionOption;
412 ASSERT_NO_THROW(options_.addOption(
413 SelectionOption("sel1").storeVector(&sel1)));
414 ASSERT_NO_THROW(options_.addOption(
415 SelectionOption("sel2").storeVector(&sel2)));
418 gmx::OptionsAssigner assigner(&options_);
419 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
420 EXPECT_NO_THROW(assigner.start());
421 ASSERT_NO_THROW(assigner.startOption("sel1"));
422 EXPECT_NO_THROW(assigner.finishOption());
423 ASSERT_NO_THROW(assigner.startOption("sel2"));
424 EXPECT_NO_THROW(assigner.finishOption());
425 ASSERT_NO_THROW(assigner.startOption("sf"));
426 EXPECT_NO_THROW(assigner.appendValue(value));
427 EXPECT_NO_THROW(assigner.finishOption());
428 EXPECT_NO_THROW(assigner.finish());
429 EXPECT_NO_THROW(options_.finish());
431 // These should match the contents of selfile.dat
432 ASSERT_EQ(1U, sel1.size());
433 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
434 ASSERT_EQ(1U, sel2.size());
435 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
439 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFile)
441 gmx::SelectionList sel;
442 gmx::SelectionList optsel;
443 using gmx::SelectionOption;
444 ASSERT_NO_THROW(options_.addOption(
445 SelectionOption("sel").storeVector(&sel)
446 .multiValue().required()));
447 ASSERT_NO_THROW(options_.addOption(
448 SelectionOption("optsel").storeVector(&optsel)
452 gmx::OptionsAssigner assigner(&options_);
453 EXPECT_NO_THROW(assigner.start());
454 ASSERT_NO_THROW(assigner.startOption("sf"));
455 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
456 EXPECT_NO_THROW(assigner.finishOption());
457 EXPECT_NO_THROW(assigner.startOption("optsel"));
458 EXPECT_NO_THROW(assigner.finishOption());
459 EXPECT_NO_THROW(assigner.finish());
460 EXPECT_NO_THROW(options_.finish());
461 EXPECT_NO_THROW(manager_.parseRequestedFromString("resname RC RD"));
463 // These should match the contents of selfile.dat
464 ASSERT_EQ(2U, sel.size());
465 EXPECT_STREQ("resname RA RB", sel[0].selectionText());
466 EXPECT_STREQ("resname RB RC", sel[1].selectionText());
467 ASSERT_EQ(1U, optsel.size());
468 EXPECT_STREQ("resname RC RD", optsel[0].selectionText());
472 // TODO: Is this the best possible behavior, or should it error out?
473 TEST_F(SelectionFileOptionTest, HandlesRequiredOptionFromFileWithOtherOptionSet)
475 gmx::SelectionList sel1;
476 gmx::SelectionList sel2;
477 using gmx::SelectionOption;
478 ASSERT_NO_THROW(options_.addOption(
479 SelectionOption("sel1").storeVector(&sel1)
480 .multiValue().required()));
481 ASSERT_NO_THROW(options_.addOption(
482 SelectionOption("sel2").storeVector(&sel2)
483 .multiValue().required()));
486 gmx::OptionsAssigner assigner(&options_);
487 EXPECT_NO_THROW(assigner.start());
488 EXPECT_NO_THROW(assigner.startOption("sel1"));
489 EXPECT_NO_THROW(assigner.appendValue("resname RC RD"));
490 EXPECT_NO_THROW(assigner.finishOption());
491 ASSERT_NO_THROW(assigner.startOption("sf"));
492 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
493 EXPECT_NO_THROW(assigner.finishOption());
494 EXPECT_NO_THROW(assigner.finish());
495 EXPECT_NO_THROW(options_.finish());
497 // These should match the contents of selfile.dat
498 ASSERT_EQ(2U, sel2.size());
499 EXPECT_STREQ("resname RA RB", sel2[0].selectionText());
500 EXPECT_STREQ("resname RB RC", sel2[1].selectionText());
501 ASSERT_EQ(1U, sel1.size());
502 EXPECT_STREQ("resname RC RD", sel1[0].selectionText());
506 TEST_F(SelectionFileOptionTest, HandlesTwoRequiredOptionsFromSingleFile)
508 gmx::SelectionList sel1;
509 gmx::SelectionList sel2;
510 using gmx::SelectionOption;
511 ASSERT_NO_THROW(options_.addOption(
512 SelectionOption("sel1").storeVector(&sel1).required()));
513 ASSERT_NO_THROW(options_.addOption(
514 SelectionOption("sel2").storeVector(&sel2).required()));
517 gmx::OptionsAssigner assigner(&options_);
518 std::string value(TestFileManager::getInputFilePath("selfile.dat"));
519 EXPECT_NO_THROW(assigner.start());
520 ASSERT_NO_THROW(assigner.startOption("sf"));
521 EXPECT_NO_THROW(assigner.appendValue(value));
522 EXPECT_NO_THROW(assigner.finishOption());
523 EXPECT_NO_THROW(assigner.finish());
524 EXPECT_NO_THROW(options_.finish());
526 // These should match the contents of selfile.dat
527 ASSERT_EQ(1U, sel1.size());
528 EXPECT_STREQ("resname RA RB", sel1[0].selectionText());
529 ASSERT_EQ(1U, sel2.size());
530 EXPECT_STREQ("resname RB RC", sel2[0].selectionText());
534 TEST_F(SelectionFileOptionTest, GivesErrorWithNoFile)
536 gmx::SelectionList sel;
537 using gmx::SelectionOption;
538 ASSERT_NO_THROW(options_.addOption(
539 SelectionOption("sel").storeVector(&sel).multiValue()));
542 gmx::OptionsAssigner assigner(&options_);
543 EXPECT_NO_THROW(assigner.start());
544 ASSERT_NO_THROW(assigner.startOption("sel"));
545 EXPECT_NO_THROW(assigner.finishOption());
546 ASSERT_NO_THROW(assigner.startOption("sf"));
547 EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
548 EXPECT_NO_THROW(assigner.finish());
549 EXPECT_NO_THROW(options_.finish());
553 TEST_F(SelectionFileOptionTest, GivesErrorWithNonExistentFile)
555 gmx::SelectionList sel;
556 using gmx::SelectionOption;
557 ASSERT_NO_THROW(options_.addOption(
558 SelectionOption("sel").storeVector(&sel).multiValue()));
561 gmx::OptionsAssigner assigner(&options_);
562 EXPECT_NO_THROW(assigner.start());
563 ASSERT_NO_THROW(assigner.startOption("sel"));
564 EXPECT_NO_THROW(assigner.finishOption());
565 ASSERT_NO_THROW(assigner.startOption("sf"));
566 // TODO: Should this be changed to an InvalidInputError?
567 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::FileIOError);
568 EXPECT_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")),
569 gmx::InvalidInputError);
570 EXPECT_NO_THROW(assigner.finishOption());
571 EXPECT_NO_THROW(assigner.finish());
572 EXPECT_NO_THROW(options_.finish());
576 TEST_F(SelectionFileOptionTest, GivesErrorWithMultipleFiles)
578 gmx::SelectionList sel;
579 using gmx::SelectionOption;
580 ASSERT_NO_THROW(options_.addOption(
581 SelectionOption("sel").storeVector(&sel).multiValue()));
584 gmx::OptionsAssigner assigner(&options_);
585 EXPECT_NO_THROW(assigner.start());
586 ASSERT_NO_THROW(assigner.startOption("sel"));
587 EXPECT_NO_THROW(assigner.finishOption());
588 ASSERT_NO_THROW(assigner.startOption("sf"));
589 EXPECT_NO_THROW(assigner.appendValue(TestFileManager::getInputFilePath("selfile.dat")));
590 EXPECT_THROW(assigner.appendValue("nonexistentfile"), gmx::InvalidInputError);
591 EXPECT_NO_THROW(assigner.finishOption());
592 EXPECT_NO_THROW(assigner.finish());
593 EXPECT_NO_THROW(options_.finish());