e13a17ecdb631438bf03b7d6093f7b7ad97ddc0e
[alexxy/gromacs.git] / src / gromacs / options / tests / optionsassigner.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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 option assignment.
38  *
39  * In addition to testing gmx::OptionsAssigner, these are the main
40  * tests for the classes from basicoptions.h and basicoptionstorage.h (and
41  * their base classes) that actually implement the behavior, as well as for the
42  * internal implementation of the gmx::Options and gmx::AbstractOptionStorage
43  * classes.
44  *
45  * \author Teemu Murtola <teemu.murtola@gmail.com>
46  * \ingroup module_options
47  */
48 #include "gmxpre.h"
49
50 #include "gromacs/options/optionsassigner.h"
51
52 #include <limits>
53 #include <vector>
54
55 #include <gtest/gtest.h>
56
57 #include "gromacs/options/basicoptions.h"
58 #include "gromacs/options/options.h"
59 #include "gromacs/options/optionsection.h"
60 #include "gromacs/utility/exceptions.h"
61 #include "gromacs/utility/stringutil.h"
62 #include "gromacs/utility/variant.h"
63
64 #include "testutils/testasserts.h"
65
66 namespace
67 {
68
69 /********************************************************************
70  * General assignment tests
71  */
72
73 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
74 {
75     gmx::Options options;
76     int          value = 0;
77     using gmx::IntegerOption;
78     ASSERT_NO_THROW(options.addOption(
79                             IntegerOption("p").store(&value).required()));
80
81     EXPECT_THROW(options.finish(), gmx::InvalidInputError);
82 }
83
84 TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
85 {
86     gmx::Options options;
87     int          value = 0;
88     using gmx::IntegerOption;
89     ASSERT_NO_THROW(options.addOption(
90                             IntegerOption("p").store(&value).required()
91                                 .defaultValue(1)));
92
93     EXPECT_NO_THROW(options.finish());
94     EXPECT_EQ(1, value);
95 }
96
97 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
98 {
99     gmx::Options     options;
100     std::vector<int> values;
101     bool             bIsSet = false;
102     using gmx::IntegerOption;
103     ASSERT_NO_THROW(options.addOption(
104                             IntegerOption("p")
105                                 .storeVector(&values).storeIsSet(&bIsSet)
106                                 .multiValue()));
107
108     gmx::OptionsAssigner assigner(&options);
109     EXPECT_NO_THROW(assigner.start());
110     ASSERT_NO_THROW(assigner.startOption("p"));
111     ASSERT_NO_THROW(assigner.appendValue("1"));
112     ASSERT_NO_THROW(assigner.finishOption());
113     EXPECT_THROW(assigner.startOption("p"), gmx::InvalidInputError);
114     EXPECT_NO_THROW(assigner.finish());
115     EXPECT_NO_THROW(options.finish());
116
117     EXPECT_TRUE(bIsSet);
118     ASSERT_EQ(1U, values.size());
119     EXPECT_EQ(1, values[0]);
120 }
121
122 TEST(OptionsAssignerTest, HandlesMultipleParameter)
123 {
124     gmx::Options     options;
125     std::vector<int> values;
126     bool             bIsSet = false;
127     using gmx::IntegerOption;
128     ASSERT_NO_THROW(options.addOption(
129                             IntegerOption("p")
130                                 .storeVector(&values).storeIsSet(&bIsSet)
131                                 .allowMultiple()));
132
133     gmx::OptionsAssigner assigner(&options);
134     EXPECT_NO_THROW_GMX(assigner.start());
135     ASSERT_NO_THROW_GMX(assigner.startOption("p"));
136     ASSERT_NO_THROW_GMX(assigner.appendValue("1"));
137     EXPECT_NO_THROW_GMX(assigner.finishOption());
138     ASSERT_NO_THROW_GMX(assigner.startOption("p"));
139     ASSERT_NO_THROW_GMX(assigner.appendValue("2"));
140     EXPECT_NO_THROW_GMX(assigner.finishOption());
141     EXPECT_NO_THROW_GMX(assigner.finish());
142     EXPECT_NO_THROW_GMX(options.finish());
143
144     EXPECT_TRUE(bIsSet);
145     ASSERT_EQ(2U, values.size());
146     EXPECT_EQ(1, values[0]);
147     EXPECT_EQ(2, values[1]);
148 }
149
150 TEST(OptionsAssignerTest, HandlesMissingValue)
151 {
152     gmx::Options options;
153     int          value1 = 0, value2 = 0;
154     using gmx::IntegerOption;
155     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
156     ASSERT_NO_THROW(options.addOption(IntegerOption("q").store(&value2)));
157
158     gmx::OptionsAssigner assigner(&options);
159     EXPECT_NO_THROW(assigner.start());
160     ASSERT_NO_THROW(assigner.startOption("p"));
161     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
162     ASSERT_NO_THROW(assigner.startOption("q"));
163     ASSERT_NO_THROW(assigner.appendValue("2"));
164     EXPECT_NO_THROW(assigner.finishOption());
165     EXPECT_NO_THROW(assigner.finish());
166     EXPECT_NO_THROW(options.finish());
167
168     EXPECT_EQ(2, value2);
169 }
170
171 TEST(OptionsAssignerTest, HandlesExtraValue)
172 {
173     gmx::Options options;
174     int          value1 = 0;
175     using gmx::IntegerOption;
176     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
177
178     gmx::OptionsAssigner assigner(&options);
179     EXPECT_NO_THROW(assigner.start());
180     ASSERT_NO_THROW(assigner.startOption("p"));
181     ASSERT_NO_THROW(assigner.appendValue("2"));
182     EXPECT_THROW(assigner.appendValue("3"), gmx::InvalidInputError);
183     EXPECT_NO_THROW(assigner.finishOption());
184     EXPECT_NO_THROW(assigner.finish());
185     EXPECT_NO_THROW(options.finish());
186
187     EXPECT_EQ(0, value1);
188 }
189
190 TEST(OptionsAssignerTest, HandlesGroups)
191 {
192     gmx::Options            options;
193     gmx::IOptionsContainer &group1 = options.addGroup();
194     gmx::IOptionsContainer &group2 = options.addGroup();
195     int                     value  = 3;
196     int                     value1 = 1;
197     int                     value2 = 2;
198     using gmx::IntegerOption;
199     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
200     ASSERT_NO_THROW(group1.addOption(IntegerOption("q").store(&value1)));
201     ASSERT_NO_THROW(group2.addOption(IntegerOption("r").store(&value2)));
202
203     gmx::OptionsAssigner assigner(&options);
204     EXPECT_NO_THROW(assigner.start());
205     ASSERT_NO_THROW(assigner.startOption("p"));
206     EXPECT_NO_THROW(assigner.appendValue("5"));
207     EXPECT_NO_THROW(assigner.finishOption());
208     ASSERT_NO_THROW(assigner.startOption("q"));
209     EXPECT_NO_THROW(assigner.appendValue("4"));
210     EXPECT_NO_THROW(assigner.finishOption());
211     ASSERT_NO_THROW(assigner.startOption("r"));
212     EXPECT_NO_THROW(assigner.appendValue("6"));
213     EXPECT_NO_THROW(assigner.finishOption());
214     EXPECT_NO_THROW(assigner.finish());
215     EXPECT_NO_THROW(options.finish());
216
217     EXPECT_EQ(5, value);
218     EXPECT_EQ(4, value1);
219     EXPECT_EQ(6, value2);
220 }
221
222 TEST(OptionsAssignerTest, HandlesSections)
223 {
224     using gmx::OptionSection;
225     gmx::Options options;
226     auto         sub1   = options.addSection(OptionSection("section1"));
227     auto         sub2   = options.addSection(OptionSection("section2"));
228     int          value  = 3;
229     int          value1 = 1;
230     int          value2 = 2;
231     using gmx::IntegerOption;
232     ASSERT_NO_THROW_GMX(options.addOption(IntegerOption("p").store(&value)));
233     ASSERT_NO_THROW_GMX(sub1.addOption(IntegerOption("p").store(&value1)));
234     ASSERT_NO_THROW_GMX(sub2.addOption(IntegerOption("p").store(&value2)));
235
236     gmx::OptionsAssigner assigner(&options);
237     EXPECT_NO_THROW(assigner.start());
238     ASSERT_NO_THROW(assigner.startSection("section1"));
239     ASSERT_NO_THROW(assigner.startOption("p"));
240     EXPECT_NO_THROW(assigner.appendValue("5"));
241     EXPECT_NO_THROW(assigner.finishOption());
242     EXPECT_NO_THROW(assigner.finishSection());
243     ASSERT_NO_THROW(assigner.startOption("p"));
244     EXPECT_NO_THROW(assigner.appendValue("4"));
245     EXPECT_NO_THROW(assigner.finishOption());
246     ASSERT_NO_THROW(assigner.startSection("section2"));
247     ASSERT_NO_THROW(assigner.startOption("p"));
248     EXPECT_NO_THROW(assigner.appendValue("6"));
249     EXPECT_NO_THROW(assigner.finishOption());
250     EXPECT_NO_THROW(assigner.finishSection());
251     EXPECT_NO_THROW(assigner.finish());
252     EXPECT_NO_THROW(options.finish());
253
254     EXPECT_EQ(4, value);
255     EXPECT_EQ(5, value1);
256     EXPECT_EQ(6, value2);
257 }
258
259 TEST(OptionsAssignerTest, HandlesMultipleSources)
260 {
261     gmx::Options options;
262     int          value = -1;
263     using gmx::IntegerOption;
264     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
265
266     {
267         gmx::OptionsAssigner assigner(&options);
268         EXPECT_NO_THROW(assigner.start());
269         ASSERT_NO_THROW(assigner.startOption("p"));
270         EXPECT_NO_THROW(assigner.appendValue("1"));
271         EXPECT_NO_THROW(assigner.finishOption());
272         EXPECT_NO_THROW(assigner.finish());
273     }
274     {
275         gmx::OptionsAssigner assigner2(&options);
276         EXPECT_NO_THROW(assigner2.start());
277         ASSERT_NO_THROW(assigner2.startOption("p"));
278         EXPECT_NO_THROW(assigner2.appendValue("2"));
279         EXPECT_NO_THROW(assigner2.finishOption());
280         EXPECT_NO_THROW(assigner2.finish());
281     }
282     EXPECT_NO_THROW(options.finish());
283
284     EXPECT_EQ(2, value);
285 }
286
287
288 /********************************************************************
289  * Tests for boolean assignment
290  */
291
292 TEST(OptionsAssignerBooleanTest, StoresYesValue)
293 {
294     gmx::Options options;
295     bool         value = false;
296     using gmx::BooleanOption;
297     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
298
299     gmx::OptionsAssigner assigner(&options);
300     EXPECT_NO_THROW(assigner.start());
301     ASSERT_NO_THROW(assigner.startOption("p"));
302     EXPECT_NO_THROW(assigner.appendValue("yes"));
303     EXPECT_NO_THROW(assigner.finishOption());
304     EXPECT_NO_THROW(assigner.finish());
305     EXPECT_NO_THROW(options.finish());
306
307     EXPECT_TRUE(value);
308 }
309
310 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
311 {
312     gmx::Options options;
313     bool         value = false;
314     using gmx::BooleanOption;
315     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
316
317     gmx::OptionsAssigner assigner(&options);
318     EXPECT_NO_THROW(assigner.start());
319     ASSERT_NO_THROW(assigner.startOption("p"));
320     EXPECT_NO_THROW(assigner.finishOption());
321     EXPECT_NO_THROW(assigner.finish());
322     EXPECT_NO_THROW(options.finish());
323
324     EXPECT_TRUE(value);
325 }
326
327 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
328 {
329     gmx::Options options;
330     bool         value = true;
331     using gmx::BooleanOption;
332     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
333
334     gmx::OptionsAssigner assigner(&options);
335     assigner.setAcceptBooleanNoPrefix(true);
336     EXPECT_NO_THROW(assigner.start());
337     ASSERT_NO_THROW(assigner.startOption("nop"));
338     EXPECT_NO_THROW(assigner.finishOption());
339     EXPECT_NO_THROW(assigner.finish());
340     EXPECT_NO_THROW(options.finish());
341
342     EXPECT_FALSE(value);
343 }
344
345 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
346 {
347     gmx::Options options;
348     bool         value = false;
349     using gmx::BooleanOption;
350     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
351
352     gmx::OptionsAssigner assigner(&options);
353     assigner.setAcceptBooleanNoPrefix(true);
354     EXPECT_NO_THROW(assigner.start());
355     ASSERT_NO_THROW(assigner.startOption("nop"));
356     // It's OK to fail, but if it doesn't, it should work.
357     try
358     {
359         assigner.appendValue("no");
360         assigner.finishOption();
361         EXPECT_NO_THROW(assigner.finish());
362         EXPECT_TRUE(value);
363     }
364     catch (const gmx::InvalidInputError &)
365     {
366     }
367 }
368
369
370 /********************************************************************
371  * Tests for integer assignment
372  *
373  * These tests also contain tests for general default value handling.
374  */
375
376 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
377 {
378     gmx::Options options;
379     int          value = 1;
380     using gmx::IntegerOption;
381     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
382
383     gmx::OptionsAssigner assigner(&options);
384     EXPECT_NO_THROW(assigner.start());
385     ASSERT_NO_THROW(assigner.startOption("p"));
386     ASSERT_NO_THROW(assigner.appendValue("3"));
387     EXPECT_NO_THROW(assigner.finishOption());
388     EXPECT_NO_THROW(assigner.finish());
389     EXPECT_NO_THROW(options.finish());
390
391     EXPECT_EQ(3, value);
392 }
393
394 TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
395 {
396     gmx::Options options;
397     int          value = 1;
398     using gmx::IntegerOption;
399     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
400
401     gmx::OptionsAssigner assigner(&options);
402     EXPECT_NO_THROW(assigner.start());
403     ASSERT_NO_THROW(assigner.startOption("p"));
404     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
405     EXPECT_NO_THROW(assigner.finishOption());
406     EXPECT_NO_THROW(assigner.finish());
407     EXPECT_NO_THROW(options.finish());
408
409     EXPECT_EQ(1, value);
410 }
411
412 TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
413 {
414     gmx::Options options;
415     int          value = 1;
416     using gmx::IntegerOption;
417     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
418
419     gmx::OptionsAssigner assigner(&options);
420     EXPECT_NO_THROW(assigner.start());
421     ASSERT_NO_THROW(assigner.startOption("p"));
422     EXPECT_THROW(assigner.appendValue("2abc"), gmx::InvalidInputError);
423     EXPECT_NO_THROW(assigner.finishOption());
424     EXPECT_NO_THROW(assigner.finish());
425     EXPECT_NO_THROW(options.finish());
426
427     EXPECT_EQ(1, value);
428 }
429
430 TEST(OptionsAssignerIntegerTest, HandlesOverflow)
431 {
432     gmx::Options options;
433     int          value = 1;
434     using gmx::IntegerOption;
435     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
436
437     gmx::OptionsAssigner assigner(&options);
438     EXPECT_NO_THROW(assigner.start());
439     ASSERT_NO_THROW(assigner.startOption("p"));
440     std::string overflowValue(
441             gmx::formatString("%d0000", std::numeric_limits<int>::max()));
442     EXPECT_THROW(assigner.appendValue(overflowValue), gmx::InvalidInputError);
443     EXPECT_NO_THROW(assigner.finishOption());
444     EXPECT_NO_THROW(assigner.finish());
445     EXPECT_NO_THROW(options.finish());
446
447     EXPECT_EQ(1, value);
448 }
449
450 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
451 {
452     gmx::Options options;
453     int          value = -1;
454     using gmx::IntegerOption;
455     ASSERT_NO_THROW(options.addOption(
456                             IntegerOption("p").store(&value).defaultValue(2)));
457     EXPECT_EQ(2, value);
458
459     gmx::OptionsAssigner assigner(&options);
460     EXPECT_NO_THROW(assigner.start());
461     EXPECT_NO_THROW(assigner.finish());
462     EXPECT_NO_THROW(options.finish());
463
464     EXPECT_EQ(2, value);
465 }
466
467 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
468 {
469     gmx::Options options;
470     int          value = -1;
471     using gmx::IntegerOption;
472     ASSERT_NO_THROW(options.addOption(
473                             IntegerOption("p").store(&value).defaultValueIfSet(2)));
474     EXPECT_EQ(-1, value);
475
476     gmx::OptionsAssigner assigner(&options);
477     EXPECT_NO_THROW(assigner.start());
478     ASSERT_NO_THROW(assigner.startOption("p"));
479     EXPECT_NO_THROW(assigner.finishOption());
480     EXPECT_NO_THROW(assigner.finish());
481     EXPECT_NO_THROW(options.finish());
482
483     EXPECT_EQ(2, value);
484 }
485
486 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
487 {
488     gmx::Options options;
489     int          value = -1;
490     using gmx::IntegerOption;
491     ASSERT_NO_THROW(options.addOption(
492                             IntegerOption("p").store(&value).defaultValueIfSet(2)));
493     EXPECT_EQ(-1, value);
494
495     gmx::OptionsAssigner assigner(&options);
496     EXPECT_NO_THROW(assigner.start());
497     EXPECT_NO_THROW(assigner.finish());
498     EXPECT_NO_THROW(options.finish());
499
500     EXPECT_EQ(-1, value);
501 }
502
503 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
504 {
505     gmx::Options options;
506     int          value = -1;
507     using gmx::IntegerOption;
508     ASSERT_NO_THROW(options.addOption(
509                             IntegerOption("p").store(&value)
510                                 .defaultValue(1).defaultValueIfSet(2)));
511     EXPECT_EQ(1, value);
512
513     gmx::OptionsAssigner assigner(&options);
514     EXPECT_NO_THROW(assigner.start());
515     ASSERT_NO_THROW(assigner.startOption("p"));
516     EXPECT_NO_THROW(assigner.finishOption());
517     EXPECT_NO_THROW(assigner.finish());
518     EXPECT_NO_THROW(options.finish());
519
520     EXPECT_EQ(2, value);
521 }
522
523 TEST(OptionsAssignerIntegerTest, StoresToVector)
524 {
525     gmx::Options          options;
526     std::vector<int>      values;
527     using gmx::IntegerOption;
528     ASSERT_NO_THROW(options.addOption(
529                             IntegerOption("p").storeVector(&values).multiValue()));
530
531     gmx::OptionsAssigner assigner(&options);
532     EXPECT_NO_THROW(assigner.start());
533     ASSERT_NO_THROW(assigner.startOption("p"));
534     ASSERT_NO_THROW(assigner.appendValue("-2"));
535     ASSERT_NO_THROW(assigner.appendValue("1"));
536     ASSERT_NO_THROW(assigner.appendValue("4"));
537     EXPECT_NO_THROW(assigner.finishOption());
538     EXPECT_NO_THROW(assigner.finish());
539     EXPECT_NO_THROW(options.finish());
540
541     EXPECT_EQ(3U, values.size());
542     EXPECT_EQ(-2, values[0]);
543     EXPECT_EQ(1, values[1]);
544     EXPECT_EQ(4, values[2]);
545 }
546
547 TEST(OptionsAssignerIntegerTest, HandlesVectors)
548 {
549     gmx::Options options;
550     int          vec[3] = {0, 0, 0};
551     using gmx::IntegerOption;
552     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
553
554     gmx::OptionsAssigner assigner(&options);
555     EXPECT_NO_THROW(assigner.start());
556     ASSERT_NO_THROW(assigner.startOption("p"));
557     ASSERT_NO_THROW(assigner.appendValue("-2"));
558     ASSERT_NO_THROW(assigner.appendValue("1"));
559     ASSERT_NO_THROW(assigner.appendValue("4"));
560     EXPECT_NO_THROW(assigner.finishOption());
561     EXPECT_NO_THROW(assigner.finish());
562     EXPECT_NO_THROW(options.finish());
563
564     EXPECT_EQ(-2, vec[0]);
565     EXPECT_EQ(1, vec[1]);
566     EXPECT_EQ(4, vec[2]);
567 }
568
569 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
570 {
571     gmx::Options options;
572     int          vec[3] = {0, 0, 0};
573     using gmx::IntegerOption;
574     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
575
576     gmx::OptionsAssigner assigner(&options);
577     EXPECT_NO_THROW(assigner.start());
578     ASSERT_NO_THROW(assigner.startOption("p"));
579     ASSERT_NO_THROW(assigner.appendValue("2"));
580     EXPECT_NO_THROW(assigner.finishOption());
581     EXPECT_NO_THROW(assigner.finish());
582     EXPECT_NO_THROW(options.finish());
583
584     EXPECT_EQ(2, vec[0]);
585     EXPECT_EQ(2, vec[1]);
586     EXPECT_EQ(2, vec[2]);
587 }
588
589 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
590 {
591     gmx::Options options;
592     int          vec[3] = {3, 2, 1};
593     using gmx::IntegerOption;
594     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
595
596     EXPECT_NO_THROW(options.finish());
597
598     EXPECT_EQ(3, vec[0]);
599     EXPECT_EQ(2, vec[1]);
600     EXPECT_EQ(1, vec[2]);
601 }
602
603 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
604 {
605     gmx::Options     options;
606     int              vec[3] = {3, 2, 1};
607     using gmx::IntegerOption;
608     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
609
610     gmx::OptionsAssigner assigner(&options);
611     EXPECT_NO_THROW(assigner.start());
612     ASSERT_NO_THROW(assigner.startOption("p"));
613     EXPECT_NO_THROW(assigner.appendValue("1"));
614     EXPECT_NO_THROW(assigner.appendValue("3"));
615     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
616     EXPECT_NO_THROW(assigner.finish());
617     EXPECT_NO_THROW(options.finish());
618
619     EXPECT_EQ(3, vec[0]);
620     EXPECT_EQ(2, vec[1]);
621     EXPECT_EQ(1, vec[2]);
622 }
623
624
625 /********************************************************************
626  * Tests for double assignment
627  */
628
629 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
630 {
631     gmx::Options options;
632     double       value = 0.0;
633     using gmx::DoubleOption;
634     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
635
636     gmx::OptionsAssigner assigner(&options);
637     EXPECT_NO_THROW(assigner.start());
638     ASSERT_NO_THROW(assigner.startOption("p"));
639     ASSERT_NO_THROW(assigner.appendValue("2.7"));
640     EXPECT_NO_THROW(assigner.finishOption());
641     EXPECT_NO_THROW(assigner.finish());
642     EXPECT_NO_THROW(options.finish());
643
644     EXPECT_DOUBLE_EQ(2.7, value);
645 }
646
647 TEST(OptionsAssignerDoubleTest, StoresValueFromFloat)
648 {
649     gmx::Options options;
650     double       value = 0.0;
651     using gmx::DoubleOption;
652     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
653
654     gmx::OptionsAssigner assigner(&options);
655     EXPECT_NO_THROW(assigner.start());
656     ASSERT_NO_THROW(assigner.startOption("p"));
657     ASSERT_NO_THROW(assigner.appendValue(gmx::Variant::create<float>(2.7)));
658     EXPECT_NO_THROW(assigner.finishOption());
659     EXPECT_NO_THROW(assigner.finish());
660     EXPECT_NO_THROW(options.finish());
661
662     EXPECT_FLOAT_EQ(2.7, value);
663 }
664
665 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
666 {
667     gmx::Options options;
668     double       value = 1.0;
669     using gmx::DoubleOption;
670     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
671
672     gmx::OptionsAssigner assigner(&options);
673     EXPECT_NO_THROW(assigner.start());
674     ASSERT_NO_THROW(assigner.startOption("p"));
675     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
676     EXPECT_NO_THROW(assigner.finishOption());
677     EXPECT_NO_THROW(assigner.finish());
678     EXPECT_NO_THROW(options.finish());
679
680     EXPECT_DOUBLE_EQ(1.0, value);
681 }
682
683 TEST(OptionsAssignerDoubleTest, HandlesPreSetScaleValue)
684 {
685     gmx::Options           options;
686     double                 value = 1.0;
687     using gmx::DoubleOption;
688     gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
689     EXPECT_NO_THROW(info->setScaleFactor(10));
690
691     gmx::OptionsAssigner assigner(&options);
692     EXPECT_NO_THROW(assigner.start());
693     ASSERT_NO_THROW(assigner.startOption("p"));
694     ASSERT_NO_THROW(assigner.appendValue("2.7"));
695     EXPECT_NO_THROW(assigner.finishOption());
696     EXPECT_NO_THROW(assigner.finish());
697     EXPECT_NO_THROW(options.finish());
698
699     EXPECT_DOUBLE_EQ(27, value);
700 }
701
702 TEST(OptionsAssignerDoubleTest, HandlesPostSetScaleValue)
703 {
704     gmx::Options           options;
705     double                 value = 1.0;
706     using gmx::DoubleOption;
707     gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
708
709     gmx::OptionsAssigner   assigner(&options);
710     EXPECT_NO_THROW(assigner.start());
711     ASSERT_NO_THROW(assigner.startOption("p"));
712     ASSERT_NO_THROW(assigner.appendValue("2.7"));
713     EXPECT_NO_THROW(assigner.finishOption());
714     EXPECT_NO_THROW(assigner.finish());
715     EXPECT_NO_THROW(info->setScaleFactor(10));
716     EXPECT_NO_THROW(options.finish());
717
718     EXPECT_DOUBLE_EQ(27, value);
719 }
720
721
722 /********************************************************************
723  * Tests for string assignment
724  */
725
726 //! Set of allowed values for enum option tests.
727 const char *const c_allowed[] = { "none", "test", "value" };
728
729 TEST(OptionsAssignerStringTest, StoresSingleValue)
730 {
731     gmx::Options           options;
732     std::string            value;
733     using gmx::StringOption;
734     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
735
736     gmx::OptionsAssigner assigner(&options);
737     EXPECT_NO_THROW(assigner.start());
738     ASSERT_NO_THROW(assigner.startOption("p"));
739     ASSERT_NO_THROW(assigner.appendValue("value"));
740     EXPECT_NO_THROW(assigner.finishOption());
741     EXPECT_NO_THROW(assigner.finish());
742     EXPECT_NO_THROW(options.finish());
743
744     EXPECT_EQ("value", value);
745 }
746
747 TEST(OptionsAssignerStringTest, HandlesEnumValue)
748 {
749     gmx::Options           options;
750     std::string            value;
751     using gmx::StringOption;
752     ASSERT_NO_THROW(options.addOption(
753                             StringOption("p").store(&value)
754                                 .enumValue(c_allowed)));
755
756     gmx::OptionsAssigner assigner(&options);
757     EXPECT_NO_THROW(assigner.start());
758     ASSERT_NO_THROW(assigner.startOption("p"));
759     ASSERT_NO_THROW(assigner.appendValue("test"));
760     EXPECT_NO_THROW(assigner.finishOption());
761     EXPECT_NO_THROW(assigner.finish());
762     EXPECT_NO_THROW(options.finish());
763
764     EXPECT_EQ("test", value);
765 }
766
767 TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
768 {
769     gmx::Options           options;
770     std::string            value;
771     const char * const     allowed[] = { "none", "test", "value", NULL };
772     using gmx::StringOption;
773     ASSERT_NO_THROW(options.addOption(
774                             StringOption("p").store(&value)
775                                 .enumValueFromNullTerminatedArray(allowed)));
776
777     gmx::OptionsAssigner assigner(&options);
778     EXPECT_NO_THROW(assigner.start());
779     ASSERT_NO_THROW(assigner.startOption("p"));
780     ASSERT_NO_THROW(assigner.appendValue("value"));
781     EXPECT_NO_THROW(assigner.finishOption());
782     EXPECT_NO_THROW(assigner.finish());
783     EXPECT_NO_THROW(options.finish());
784
785     EXPECT_EQ("value", value);
786 }
787
788 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
789 {
790     gmx::Options           options;
791     std::string            value;
792     using gmx::StringOption;
793     ASSERT_NO_THROW(options.addOption(
794                             StringOption("p").store(&value)
795                                 .enumValue(c_allowed)));
796
797     gmx::OptionsAssigner assigner(&options);
798     EXPECT_NO_THROW(assigner.start());
799     ASSERT_NO_THROW(assigner.startOption("p"));
800     ASSERT_THROW(assigner.appendValue("unknown"), gmx::InvalidInputError);
801 }
802
803 TEST(OptionsAssignerStringTest, CompletesEnumValue)
804 {
805     gmx::Options           options;
806     std::string            value;
807     using gmx::StringOption;
808     ASSERT_NO_THROW(options.addOption(
809                             StringOption("p").store(&value)
810                                 .enumValue(c_allowed)));
811
812     gmx::OptionsAssigner assigner(&options);
813     EXPECT_NO_THROW(assigner.start());
814     ASSERT_NO_THROW(assigner.startOption("p"));
815     ASSERT_NO_THROW(assigner.appendValue("te"));
816     EXPECT_NO_THROW(assigner.finishOption());
817     EXPECT_NO_THROW(assigner.finish());
818     EXPECT_NO_THROW(options.finish());
819
820     EXPECT_EQ("test", value);
821 }
822
823 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
824 {
825     gmx::Options           options;
826     std::string            value;
827     using gmx::StringOption;
828     ASSERT_NO_THROW(options.addOption(
829                             StringOption("p").store(&value)
830                                 .enumValue(c_allowed)));
831     EXPECT_TRUE(value.empty());
832
833     ASSERT_NO_THROW(options.finish());
834
835     EXPECT_TRUE(value.empty());
836 }
837
838 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
839 {
840     gmx::Options           options;
841     std::string            value;
842     using gmx::StringOption;
843     ASSERT_NO_THROW(options.addOption(
844                             StringOption("p").store(&value)
845                                 .enumValue(c_allowed).defaultValue("test")));
846     EXPECT_EQ("test", value);
847
848     gmx::OptionsAssigner assigner(&options);
849     EXPECT_NO_THROW(assigner.start());
850     EXPECT_NO_THROW(assigner.finish());
851     EXPECT_NO_THROW(options.finish());
852
853     EXPECT_EQ("test", value);
854 }
855
856 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
857 {
858     gmx::Options           options;
859     std::string            value("test");
860     using gmx::StringOption;
861     ASSERT_NO_THROW(options.addOption(
862                             StringOption("p").store(&value)
863                                 .enumValue(c_allowed)));
864     EXPECT_EQ("test", value);
865
866     gmx::OptionsAssigner assigner(&options);
867     EXPECT_NO_THROW(assigner.start());
868     EXPECT_NO_THROW(assigner.finish());
869     EXPECT_NO_THROW(options.finish());
870
871     EXPECT_EQ("test", value);
872 }
873
874 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVector)
875 {
876     gmx::Options             options;
877     std::vector<std::string> value;
878     value.emplace_back("test");
879     value.emplace_back("value");
880     using gmx::StringOption;
881     ASSERT_NO_THROW(options.addOption(
882                             StringOption("p").storeVector(&value).valueCount(2)
883                                 .enumValue(c_allowed)));
884     ASSERT_EQ(2U, value.size());
885     EXPECT_EQ("test", value[0]);
886     EXPECT_EQ("value", value[1]);
887
888     gmx::OptionsAssigner assigner(&options);
889     EXPECT_NO_THROW(assigner.start());
890     EXPECT_NO_THROW(assigner.finish());
891     EXPECT_NO_THROW(options.finish());
892
893     ASSERT_EQ(2U, value.size());
894     EXPECT_EQ("test", value[0]);
895     EXPECT_EQ("value", value[1]);
896 }
897
898
899 /********************************************************************
900  * Tests for enum options
901  */
902
903 //! Enum type for EnumOption tests.
904 enum TestEnum
905 {
906     etestNone,
907     etestTest,
908     etestValue,
909     etestNR
910 };
911
912 TEST(OptionsAssignerEnumTest, StoresSingleValue)
913 {
914     gmx::Options           options;
915     TestEnum               value     = etestNone;
916     using gmx::EnumOption;
917     ASSERT_NO_THROW(options.addOption(
918                             EnumOption<TestEnum>("p").store(&value)
919                                 .enumValue(c_allowed)));
920     EXPECT_EQ(etestNone, value);
921
922     gmx::OptionsAssigner assigner(&options);
923     EXPECT_NO_THROW(assigner.start());
924     ASSERT_NO_THROW(assigner.startOption("p"));
925     ASSERT_NO_THROW(assigner.appendValue("test"));
926     EXPECT_NO_THROW(assigner.finishOption());
927     EXPECT_NO_THROW(assigner.finish());
928     EXPECT_NO_THROW(options.finish());
929
930     EXPECT_EQ(etestTest, value);
931 }
932
933 TEST(OptionsAssignerEnumTest, StoresVectorValues)
934 {
935     gmx::Options           options;
936     std::vector<TestEnum>  values;
937     using gmx::EnumOption;
938     ASSERT_NO_THROW(options.addOption(
939                             EnumOption<TestEnum>("p").storeVector(&values)
940                                 .multiValue().enumValue(c_allowed)));
941     EXPECT_TRUE(values.empty());
942
943     gmx::OptionsAssigner assigner(&options);
944     EXPECT_NO_THROW(assigner.start());
945     ASSERT_NO_THROW(assigner.startOption("p"));
946     ASSERT_NO_THROW(assigner.appendValue("test"));
947     ASSERT_NO_THROW(assigner.appendValue("value"));
948     EXPECT_NO_THROW(assigner.finishOption());
949     EXPECT_NO_THROW(assigner.finish());
950     EXPECT_NO_THROW(options.finish());
951
952     ASSERT_EQ(2U, values.size());
953     EXPECT_EQ(etestTest, values[0]);
954     EXPECT_EQ(etestValue, values[1]);
955 }
956
957 TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
958 {
959     gmx::Options           options;
960     TestEnum               value     = etestNR;
961     using gmx::EnumOption;
962     ASSERT_NO_THROW(options.addOption(
963                             EnumOption<TestEnum>("p").store(&value)
964                                 .enumValue(c_allowed)));
965     EXPECT_EQ(etestNR, value);
966
967     gmx::OptionsAssigner assigner(&options);
968     EXPECT_NO_THROW(assigner.start());
969     EXPECT_NO_THROW(assigner.finish());
970     EXPECT_NO_THROW(options.finish());
971
972     EXPECT_EQ(etestNR, value);
973 }
974
975 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
976 {
977     gmx::Options           options;
978     TestEnum               value     = etestNone;
979     using gmx::EnumOption;
980     ASSERT_NO_THROW(options.addOption(
981                             EnumOption<TestEnum>("p").store(&value)
982                                 .enumValue(c_allowed).defaultValue(etestTest)));
983     EXPECT_EQ(etestTest, value);
984
985     gmx::OptionsAssigner assigner(&options);
986     EXPECT_NO_THROW(assigner.start());
987     EXPECT_NO_THROW(assigner.finish());
988     EXPECT_NO_THROW(options.finish());
989
990     EXPECT_EQ(etestTest, value);
991 }
992
993 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
994 {
995     gmx::Options           options;
996     TestEnum               value     = etestTest;
997     using gmx::EnumOption;
998     ASSERT_NO_THROW(options.addOption(
999                             EnumOption<TestEnum>("p").store(&value)
1000                                 .enumValue(c_allowed)));
1001     EXPECT_EQ(etestTest, value);
1002
1003     gmx::OptionsAssigner assigner(&options);
1004     EXPECT_NO_THROW(assigner.start());
1005     EXPECT_NO_THROW(assigner.finish());
1006     EXPECT_NO_THROW(options.finish());
1007
1008     EXPECT_EQ(etestTest, value);
1009 }
1010
1011 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVector)
1012 {
1013     gmx::Options             options;
1014     std::vector<TestEnum>    value;
1015     value.push_back(etestNone);
1016     value.push_back(etestTest);
1017     using gmx::EnumOption;
1018     ASSERT_NO_THROW(options.addOption(
1019                             EnumOption<TestEnum>("p").storeVector(&value).valueCount(2)
1020                                 .enumValue(c_allowed)));
1021     ASSERT_EQ(2U, value.size());
1022     EXPECT_EQ(etestNone, value[0]);
1023     EXPECT_EQ(etestTest, value[1]);
1024
1025     gmx::OptionsAssigner assigner(&options);
1026     EXPECT_NO_THROW(assigner.start());
1027     EXPECT_NO_THROW(assigner.finish());
1028     EXPECT_NO_THROW(options.finish());
1029
1030     ASSERT_EQ(2U, value.size());
1031     EXPECT_EQ(etestNone, value[0]);
1032     EXPECT_EQ(etestTest, value[1]);
1033 }
1034
1035 } // namespace