0925a4900ae75a413d8ac2104852cba247c311a6
[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, 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/utility/exceptions.h"
60 #include "gromacs/utility/stringutil.h"
61
62 namespace
63 {
64
65 /********************************************************************
66  * General assignment tests
67  */
68
69 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
70 {
71     gmx::Options options(NULL, NULL);
72     int          value = 0;
73     using gmx::IntegerOption;
74     ASSERT_NO_THROW(options.addOption(
75                             IntegerOption("p").store(&value).required()));
76
77     EXPECT_THROW(options.finish(), gmx::InvalidInputError);
78 }
79
80 TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
81 {
82     gmx::Options options(NULL, NULL);
83     int          value = 0;
84     using gmx::IntegerOption;
85     ASSERT_NO_THROW(options.addOption(
86                             IntegerOption("p").store(&value).required()
87                                 .defaultValue(1)));
88
89     EXPECT_NO_THROW(options.finish());
90     EXPECT_EQ(1, value);
91 }
92
93 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
94 {
95     gmx::Options     options(NULL, NULL);
96     std::vector<int> values;
97     using gmx::IntegerOption;
98     ASSERT_NO_THROW(options.addOption(
99                             IntegerOption("p").storeVector(&values).multiValue()));
100
101     gmx::OptionsAssigner assigner(&options);
102     EXPECT_NO_THROW(assigner.start());
103     ASSERT_NO_THROW(assigner.startOption("p"));
104     ASSERT_NO_THROW(assigner.appendValue("1"));
105     ASSERT_NO_THROW(assigner.finishOption());
106     EXPECT_THROW(assigner.startOption("p"), gmx::InvalidInputError);
107     EXPECT_NO_THROW(assigner.finish());
108     EXPECT_NO_THROW(options.finish());
109
110     EXPECT_TRUE(options.isSet("p"));
111     ASSERT_EQ(1U, values.size());
112     EXPECT_EQ(1, values[0]);
113 }
114
115 TEST(OptionsAssignerTest, HandlesMultipleParameter)
116 {
117     gmx::Options     options(NULL, NULL);
118     std::vector<int> values;
119     using gmx::IntegerOption;
120     ASSERT_NO_THROW(options.addOption(
121                             IntegerOption("p").storeVector(&values).allowMultiple()));
122
123     gmx::OptionsAssigner assigner(&options);
124     EXPECT_NO_THROW(assigner.start());
125     ASSERT_NO_THROW(assigner.startOption("p"));
126     ASSERT_NO_THROW(assigner.appendValue("1"));
127     EXPECT_NO_THROW(assigner.finishOption());
128     ASSERT_NO_THROW(assigner.startOption("p"));
129     ASSERT_NO_THROW(assigner.appendValue("2"));
130     EXPECT_NO_THROW(assigner.finishOption());
131     EXPECT_NO_THROW(assigner.finish());
132     EXPECT_NO_THROW(options.finish());
133
134     EXPECT_TRUE(options.isSet("p"));
135     ASSERT_EQ(2U, values.size());
136     EXPECT_EQ(1, values[0]);
137     EXPECT_EQ(2, values[1]);
138 }
139
140 TEST(OptionsAssignerTest, HandlesMissingValue)
141 {
142     gmx::Options options(NULL, NULL);
143     int          value1 = 0, value2 = 0;
144     using gmx::IntegerOption;
145     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
146     ASSERT_NO_THROW(options.addOption(IntegerOption("q").store(&value2)));
147
148     gmx::OptionsAssigner assigner(&options);
149     EXPECT_NO_THROW(assigner.start());
150     ASSERT_NO_THROW(assigner.startOption("p"));
151     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
152     ASSERT_NO_THROW(assigner.startOption("q"));
153     ASSERT_NO_THROW(assigner.appendValue("2"));
154     EXPECT_NO_THROW(assigner.finishOption());
155     EXPECT_NO_THROW(assigner.finish());
156     EXPECT_NO_THROW(options.finish());
157
158     EXPECT_EQ(2, value2);
159 }
160
161 TEST(OptionsAssignerTest, HandlesExtraValue)
162 {
163     gmx::Options options(NULL, NULL);
164     int          value1 = 0;
165     using gmx::IntegerOption;
166     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
167
168     gmx::OptionsAssigner assigner(&options);
169     EXPECT_NO_THROW(assigner.start());
170     ASSERT_NO_THROW(assigner.startOption("p"));
171     ASSERT_NO_THROW(assigner.appendValue("2"));
172     EXPECT_THROW(assigner.appendValue("3"), gmx::InvalidInputError);
173     EXPECT_NO_THROW(assigner.finishOption());
174     EXPECT_NO_THROW(assigner.finish());
175     EXPECT_NO_THROW(options.finish());
176
177     EXPECT_EQ(0, value1);
178 }
179
180 TEST(OptionsAssignerTest, HandlesGroups)
181 {
182     gmx::Options            options(NULL, NULL);
183     gmx::IOptionsContainer &group1 = options.addGroup();
184     gmx::IOptionsContainer &group2 = options.addGroup();
185     int                     value  = 3;
186     int                     value1 = 1;
187     int                     value2 = 2;
188     using gmx::IntegerOption;
189     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
190     ASSERT_NO_THROW(group1.addOption(IntegerOption("q").store(&value1)));
191     ASSERT_NO_THROW(group2.addOption(IntegerOption("r").store(&value2)));
192
193     gmx::OptionsAssigner assigner(&options);
194     EXPECT_NO_THROW(assigner.start());
195     ASSERT_NO_THROW(assigner.startOption("p"));
196     EXPECT_NO_THROW(assigner.appendValue("5"));
197     EXPECT_NO_THROW(assigner.finishOption());
198     ASSERT_NO_THROW(assigner.startOption("q"));
199     EXPECT_NO_THROW(assigner.appendValue("4"));
200     EXPECT_NO_THROW(assigner.finishOption());
201     ASSERT_NO_THROW(assigner.startOption("r"));
202     EXPECT_NO_THROW(assigner.appendValue("6"));
203     EXPECT_NO_THROW(assigner.finishOption());
204     EXPECT_NO_THROW(assigner.finish());
205     EXPECT_NO_THROW(options.finish());
206
207     EXPECT_EQ(5, value);
208     EXPECT_EQ(4, value1);
209     EXPECT_EQ(6, value2);
210 }
211
212 TEST(OptionsAssignerTest, HandlesSubSections)
213 {
214     gmx::Options options(NULL, NULL);
215     gmx::Options sub1("section1", NULL);
216     gmx::Options sub2("section2", NULL);
217     int          value  = 3;
218     int          value1 = 1;
219     int          value2 = 2;
220     using gmx::IntegerOption;
221     ASSERT_NO_THROW(options.addSubSection(&sub1));
222     ASSERT_NO_THROW(options.addSubSection(&sub2));
223     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
224     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
225     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
226
227     gmx::OptionsAssigner assigner(&options);
228     EXPECT_NO_THROW(assigner.start());
229     ASSERT_NO_THROW(assigner.startSubSection("section1"));
230     ASSERT_NO_THROW(assigner.startOption("p"));
231     EXPECT_NO_THROW(assigner.appendValue("5"));
232     EXPECT_NO_THROW(assigner.finishOption());
233     EXPECT_NO_THROW(assigner.finishSubSection());
234     ASSERT_NO_THROW(assigner.startOption("p"));
235     EXPECT_NO_THROW(assigner.appendValue("4"));
236     EXPECT_NO_THROW(assigner.finishOption());
237     ASSERT_NO_THROW(assigner.startSubSection("section2"));
238     ASSERT_NO_THROW(assigner.startOption("p"));
239     EXPECT_NO_THROW(assigner.appendValue("6"));
240     EXPECT_NO_THROW(assigner.finishOption());
241     EXPECT_NO_THROW(assigner.finishSubSection());
242     EXPECT_NO_THROW(assigner.finish());
243     EXPECT_NO_THROW(options.finish());
244
245     EXPECT_EQ(4, value);
246     EXPECT_EQ(5, value1);
247     EXPECT_EQ(6, value2);
248 }
249
250 TEST(OptionsAssignerTest, HandlesMultipleSources)
251 {
252     gmx::Options options(NULL, NULL);
253     int          value = -1;
254     using gmx::IntegerOption;
255     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
256
257     {
258         gmx::OptionsAssigner assigner(&options);
259         EXPECT_NO_THROW(assigner.start());
260         ASSERT_NO_THROW(assigner.startOption("p"));
261         EXPECT_NO_THROW(assigner.appendValue("1"));
262         EXPECT_NO_THROW(assigner.finishOption());
263         EXPECT_NO_THROW(assigner.finish());
264     }
265     {
266         gmx::OptionsAssigner assigner2(&options);
267         EXPECT_NO_THROW(assigner2.start());
268         ASSERT_NO_THROW(assigner2.startOption("p"));
269         EXPECT_NO_THROW(assigner2.appendValue("2"));
270         EXPECT_NO_THROW(assigner2.finishOption());
271         EXPECT_NO_THROW(assigner2.finish());
272     }
273     EXPECT_NO_THROW(options.finish());
274
275     EXPECT_EQ(2, value);
276 }
277
278
279 /********************************************************************
280  * Tests for boolean assignment
281  */
282
283 TEST(OptionsAssignerBooleanTest, StoresYesValue)
284 {
285     gmx::Options options(NULL, NULL);
286     bool         value = false;
287     using gmx::BooleanOption;
288     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
289
290     gmx::OptionsAssigner assigner(&options);
291     EXPECT_NO_THROW(assigner.start());
292     ASSERT_NO_THROW(assigner.startOption("p"));
293     EXPECT_NO_THROW(assigner.appendValue("yes"));
294     EXPECT_NO_THROW(assigner.finishOption());
295     EXPECT_NO_THROW(assigner.finish());
296     EXPECT_NO_THROW(options.finish());
297
298     EXPECT_TRUE(value);
299 }
300
301 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
302 {
303     gmx::Options options(NULL, NULL);
304     bool         value = false;
305     using gmx::BooleanOption;
306     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
307
308     gmx::OptionsAssigner assigner(&options);
309     EXPECT_NO_THROW(assigner.start());
310     ASSERT_NO_THROW(assigner.startOption("p"));
311     EXPECT_NO_THROW(assigner.finishOption());
312     EXPECT_NO_THROW(assigner.finish());
313     EXPECT_NO_THROW(options.finish());
314
315     EXPECT_TRUE(value);
316 }
317
318 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
319 {
320     gmx::Options options(NULL, NULL);
321     bool         value = true;
322     using gmx::BooleanOption;
323     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
324
325     gmx::OptionsAssigner assigner(&options);
326     assigner.setAcceptBooleanNoPrefix(true);
327     EXPECT_NO_THROW(assigner.start());
328     ASSERT_NO_THROW(assigner.startOption("nop"));
329     EXPECT_NO_THROW(assigner.finishOption());
330     EXPECT_NO_THROW(assigner.finish());
331     EXPECT_NO_THROW(options.finish());
332
333     EXPECT_FALSE(value);
334 }
335
336 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
337 {
338     gmx::Options options(NULL, NULL);
339     bool         value = false;
340     using gmx::BooleanOption;
341     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
342
343     gmx::OptionsAssigner assigner(&options);
344     assigner.setAcceptBooleanNoPrefix(true);
345     EXPECT_NO_THROW(assigner.start());
346     ASSERT_NO_THROW(assigner.startOption("nop"));
347     // It's OK to fail, but if it doesn't, it should work.
348     try
349     {
350         assigner.appendValue("no");
351         assigner.finishOption();
352         EXPECT_NO_THROW(assigner.finish());
353         EXPECT_TRUE(value);
354     }
355     catch (const gmx::InvalidInputError &)
356     {
357     }
358 }
359
360
361 /********************************************************************
362  * Tests for integer assignment
363  *
364  * These tests also contain tests for general default value handling.
365  */
366
367 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
368 {
369     gmx::Options options(NULL, NULL);
370     int          value = 1;
371     using gmx::IntegerOption;
372     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
373
374     gmx::OptionsAssigner assigner(&options);
375     EXPECT_NO_THROW(assigner.start());
376     ASSERT_NO_THROW(assigner.startOption("p"));
377     ASSERT_NO_THROW(assigner.appendValue("3"));
378     EXPECT_NO_THROW(assigner.finishOption());
379     EXPECT_NO_THROW(assigner.finish());
380     EXPECT_NO_THROW(options.finish());
381
382     EXPECT_EQ(3, value);
383 }
384
385 TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
386 {
387     gmx::Options options(NULL, NULL);
388     int          value = 1;
389     using gmx::IntegerOption;
390     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
391
392     gmx::OptionsAssigner assigner(&options);
393     EXPECT_NO_THROW(assigner.start());
394     ASSERT_NO_THROW(assigner.startOption("p"));
395     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
396     EXPECT_NO_THROW(assigner.finishOption());
397     EXPECT_NO_THROW(assigner.finish());
398     EXPECT_NO_THROW(options.finish());
399
400     EXPECT_EQ(1, value);
401 }
402
403 TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
404 {
405     gmx::Options options(NULL, NULL);
406     int          value = 1;
407     using gmx::IntegerOption;
408     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
409
410     gmx::OptionsAssigner assigner(&options);
411     EXPECT_NO_THROW(assigner.start());
412     ASSERT_NO_THROW(assigner.startOption("p"));
413     EXPECT_THROW(assigner.appendValue("2abc"), gmx::InvalidInputError);
414     EXPECT_NO_THROW(assigner.finishOption());
415     EXPECT_NO_THROW(assigner.finish());
416     EXPECT_NO_THROW(options.finish());
417
418     EXPECT_EQ(1, value);
419 }
420
421 TEST(OptionsAssignerIntegerTest, HandlesOverflow)
422 {
423     gmx::Options options(NULL, NULL);
424     int          value = 1;
425     using gmx::IntegerOption;
426     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
427
428     gmx::OptionsAssigner assigner(&options);
429     EXPECT_NO_THROW(assigner.start());
430     ASSERT_NO_THROW(assigner.startOption("p"));
431     std::string overflowValue(
432             gmx::formatString("%d0000", std::numeric_limits<int>::max()));
433     EXPECT_THROW(assigner.appendValue(overflowValue), gmx::InvalidInputError);
434     EXPECT_NO_THROW(assigner.finishOption());
435     EXPECT_NO_THROW(assigner.finish());
436     EXPECT_NO_THROW(options.finish());
437
438     EXPECT_EQ(1, value);
439 }
440
441 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
442 {
443     gmx::Options options(NULL, NULL);
444     int          value = -1;
445     using gmx::IntegerOption;
446     ASSERT_NO_THROW(options.addOption(
447                             IntegerOption("p").store(&value).defaultValue(2)));
448     EXPECT_EQ(2, value);
449
450     gmx::OptionsAssigner assigner(&options);
451     EXPECT_NO_THROW(assigner.start());
452     EXPECT_NO_THROW(assigner.finish());
453     EXPECT_NO_THROW(options.finish());
454
455     EXPECT_EQ(2, value);
456 }
457
458 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
459 {
460     gmx::Options options(NULL, NULL);
461     int          value = -1;
462     using gmx::IntegerOption;
463     ASSERT_NO_THROW(options.addOption(
464                             IntegerOption("p").store(&value).defaultValueIfSet(2)));
465     EXPECT_EQ(-1, value);
466
467     gmx::OptionsAssigner assigner(&options);
468     EXPECT_NO_THROW(assigner.start());
469     ASSERT_NO_THROW(assigner.startOption("p"));
470     EXPECT_NO_THROW(assigner.finishOption());
471     EXPECT_NO_THROW(assigner.finish());
472     EXPECT_NO_THROW(options.finish());
473
474     EXPECT_EQ(2, value);
475 }
476
477 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
478 {
479     gmx::Options options(NULL, NULL);
480     int          value = -1;
481     using gmx::IntegerOption;
482     ASSERT_NO_THROW(options.addOption(
483                             IntegerOption("p").store(&value).defaultValueIfSet(2)));
484     EXPECT_EQ(-1, value);
485
486     gmx::OptionsAssigner assigner(&options);
487     EXPECT_NO_THROW(assigner.start());
488     EXPECT_NO_THROW(assigner.finish());
489     EXPECT_NO_THROW(options.finish());
490
491     EXPECT_EQ(-1, value);
492 }
493
494 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
495 {
496     gmx::Options options(NULL, NULL);
497     int          value = -1;
498     using gmx::IntegerOption;
499     ASSERT_NO_THROW(options.addOption(
500                             IntegerOption("p").store(&value)
501                                 .defaultValue(1).defaultValueIfSet(2)));
502     EXPECT_EQ(1, value);
503
504     gmx::OptionsAssigner assigner(&options);
505     EXPECT_NO_THROW(assigner.start());
506     ASSERT_NO_THROW(assigner.startOption("p"));
507     EXPECT_NO_THROW(assigner.finishOption());
508     EXPECT_NO_THROW(assigner.finish());
509     EXPECT_NO_THROW(options.finish());
510
511     EXPECT_EQ(2, value);
512 }
513
514 TEST(OptionsAssignerIntegerTest, StoresToVector)
515 {
516     gmx::Options          options(NULL, NULL);
517     std::vector<int>      values;
518     using gmx::IntegerOption;
519     ASSERT_NO_THROW(options.addOption(
520                             IntegerOption("p").storeVector(&values).multiValue()));
521
522     gmx::OptionsAssigner assigner(&options);
523     EXPECT_NO_THROW(assigner.start());
524     ASSERT_NO_THROW(assigner.startOption("p"));
525     ASSERT_NO_THROW(assigner.appendValue("-2"));
526     ASSERT_NO_THROW(assigner.appendValue("1"));
527     ASSERT_NO_THROW(assigner.appendValue("4"));
528     EXPECT_NO_THROW(assigner.finishOption());
529     EXPECT_NO_THROW(assigner.finish());
530     EXPECT_NO_THROW(options.finish());
531
532     EXPECT_EQ(3U, values.size());
533     EXPECT_EQ(-2, values[0]);
534     EXPECT_EQ(1, values[1]);
535     EXPECT_EQ(4, values[2]);
536 }
537
538 TEST(OptionsAssignerIntegerTest, HandlesVectors)
539 {
540     gmx::Options options(NULL, NULL);
541     int          vec[3] = {0, 0, 0};
542     using gmx::IntegerOption;
543     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
544
545     gmx::OptionsAssigner assigner(&options);
546     EXPECT_NO_THROW(assigner.start());
547     ASSERT_NO_THROW(assigner.startOption("p"));
548     ASSERT_NO_THROW(assigner.appendValue("-2"));
549     ASSERT_NO_THROW(assigner.appendValue("1"));
550     ASSERT_NO_THROW(assigner.appendValue("4"));
551     EXPECT_NO_THROW(assigner.finishOption());
552     EXPECT_NO_THROW(assigner.finish());
553     EXPECT_NO_THROW(options.finish());
554
555     EXPECT_EQ(-2, vec[0]);
556     EXPECT_EQ(1, vec[1]);
557     EXPECT_EQ(4, vec[2]);
558 }
559
560 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
561 {
562     gmx::Options options(NULL, NULL);
563     int          vec[3] = {0, 0, 0};
564     using gmx::IntegerOption;
565     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
566
567     gmx::OptionsAssigner assigner(&options);
568     EXPECT_NO_THROW(assigner.start());
569     ASSERT_NO_THROW(assigner.startOption("p"));
570     ASSERT_NO_THROW(assigner.appendValue("2"));
571     EXPECT_NO_THROW(assigner.finishOption());
572     EXPECT_NO_THROW(assigner.finish());
573     EXPECT_NO_THROW(options.finish());
574
575     EXPECT_EQ(2, vec[0]);
576     EXPECT_EQ(2, vec[1]);
577     EXPECT_EQ(2, vec[2]);
578 }
579
580 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
581 {
582     gmx::Options options(NULL, NULL);
583     int          vec[3] = {3, 2, 1};
584     using gmx::IntegerOption;
585     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
586
587     EXPECT_NO_THROW(options.finish());
588
589     EXPECT_EQ(3, vec[0]);
590     EXPECT_EQ(2, vec[1]);
591     EXPECT_EQ(1, vec[2]);
592 }
593
594 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
595 {
596     gmx::Options     options(NULL, NULL);
597     int              vec[3] = {3, 2, 1};
598     std::vector<int> vec2(vec, vec+3);
599     using gmx::IntegerOption;
600     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
601                                           .storeVector(&vec2).vector()));
602
603     gmx::OptionsAssigner assigner(&options);
604     EXPECT_NO_THROW(assigner.start());
605     ASSERT_NO_THROW(assigner.startOption("p"));
606     EXPECT_NO_THROW(assigner.appendValue("1"));
607     EXPECT_NO_THROW(assigner.appendValue("3"));
608     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
609     EXPECT_NO_THROW(assigner.finish());
610     EXPECT_NO_THROW(options.finish());
611
612     EXPECT_EQ(3, vec[0]);
613     EXPECT_EQ(2, vec[1]);
614     EXPECT_EQ(1, vec[2]);
615     ASSERT_EQ(3U, vec2.size());
616     EXPECT_EQ(3, vec2[0]);
617     EXPECT_EQ(2, vec2[1]);
618     EXPECT_EQ(1, vec2[2]);
619 }
620
621
622 /********************************************************************
623  * Tests for double assignment
624  */
625
626 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
627 {
628     gmx::Options options(NULL, NULL);
629     double       value = 0.0;
630     using gmx::DoubleOption;
631     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
632
633     gmx::OptionsAssigner assigner(&options);
634     EXPECT_NO_THROW(assigner.start());
635     ASSERT_NO_THROW(assigner.startOption("p"));
636     ASSERT_NO_THROW(assigner.appendValue("2.7"));
637     EXPECT_NO_THROW(assigner.finishOption());
638     EXPECT_NO_THROW(assigner.finish());
639     EXPECT_NO_THROW(options.finish());
640
641     EXPECT_DOUBLE_EQ(2.7, value);
642 }
643
644 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
645 {
646     gmx::Options options(NULL, NULL);
647     double       value = 1.0;
648     using gmx::DoubleOption;
649     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
650
651     gmx::OptionsAssigner assigner(&options);
652     EXPECT_NO_THROW(assigner.start());
653     ASSERT_NO_THROW(assigner.startOption("p"));
654     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
655     EXPECT_NO_THROW(assigner.finishOption());
656     EXPECT_NO_THROW(assigner.finish());
657     EXPECT_NO_THROW(options.finish());
658
659     EXPECT_DOUBLE_EQ(1.0, value);
660 }
661
662
663 /********************************************************************
664  * Tests for string assignment
665  */
666
667 TEST(OptionsAssignerStringTest, StoresSingleValue)
668 {
669     gmx::Options           options(NULL, NULL);
670     std::string            value;
671     using gmx::StringOption;
672     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
673
674     gmx::OptionsAssigner assigner(&options);
675     EXPECT_NO_THROW(assigner.start());
676     ASSERT_NO_THROW(assigner.startOption("p"));
677     ASSERT_NO_THROW(assigner.appendValue("value"));
678     EXPECT_NO_THROW(assigner.finishOption());
679     EXPECT_NO_THROW(assigner.finish());
680     EXPECT_NO_THROW(options.finish());
681
682     EXPECT_EQ("value", value);
683 }
684
685 TEST(OptionsAssignerStringTest, HandlesEnumValue)
686 {
687     gmx::Options           options(NULL, NULL);
688     std::string            value;
689     const char * const     allowed[] = { "none", "test", "value" };
690     int                    index     = -1;
691     using gmx::StringOption;
692     ASSERT_NO_THROW(options.addOption(
693                             StringOption("p").store(&value)
694                                 .enumValue(allowed).storeEnumIndex(&index)));
695
696     gmx::OptionsAssigner assigner(&options);
697     EXPECT_NO_THROW(assigner.start());
698     ASSERT_NO_THROW(assigner.startOption("p"));
699     ASSERT_NO_THROW(assigner.appendValue("test"));
700     EXPECT_NO_THROW(assigner.finishOption());
701     EXPECT_NO_THROW(assigner.finish());
702     EXPECT_NO_THROW(options.finish());
703
704     EXPECT_EQ("test", value);
705     EXPECT_EQ(1, index);
706 }
707
708 TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
709 {
710     gmx::Options           options(NULL, NULL);
711     std::string            value;
712     const char * const     allowed[] = { "none", "test", "value", NULL };
713     int                    index     = -1;
714     using gmx::StringOption;
715     ASSERT_NO_THROW(options.addOption(
716                             StringOption("p").store(&value)
717                                 .enumValueFromNullTerminatedArray(allowed)
718                                 .storeEnumIndex(&index)));
719
720     gmx::OptionsAssigner assigner(&options);
721     EXPECT_NO_THROW(assigner.start());
722     ASSERT_NO_THROW(assigner.startOption("p"));
723     ASSERT_NO_THROW(assigner.appendValue("value"));
724     EXPECT_NO_THROW(assigner.finishOption());
725     EXPECT_NO_THROW(assigner.finish());
726     EXPECT_NO_THROW(options.finish());
727
728     EXPECT_EQ("value", value);
729     EXPECT_EQ(2, index);
730 }
731
732 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
733 {
734     gmx::Options           options(NULL, NULL);
735     std::string            value;
736     const char * const     allowed[] = { "none", "test", "value" };
737     int                    index     = -1;
738     using gmx::StringOption;
739     ASSERT_NO_THROW(options.addOption(
740                             StringOption("p").store(&value)
741                                 .enumValue(allowed).storeEnumIndex(&index)));
742
743     gmx::OptionsAssigner assigner(&options);
744     EXPECT_NO_THROW(assigner.start());
745     ASSERT_NO_THROW(assigner.startOption("p"));
746     ASSERT_THROW(assigner.appendValue("unknown"), gmx::InvalidInputError);
747 }
748
749 TEST(OptionsAssignerStringTest, CompletesEnumValue)
750 {
751     gmx::Options           options(NULL, NULL);
752     std::string            value;
753     const char * const     allowed[] = { "none", "test", "value" };
754     int                    index     = -1;
755     using gmx::StringOption;
756     ASSERT_NO_THROW(options.addOption(
757                             StringOption("p").store(&value)
758                                 .enumValue(allowed).storeEnumIndex(&index)));
759
760     gmx::OptionsAssigner assigner(&options);
761     EXPECT_NO_THROW(assigner.start());
762     ASSERT_NO_THROW(assigner.startOption("p"));
763     ASSERT_NO_THROW(assigner.appendValue("te"));
764     EXPECT_NO_THROW(assigner.finishOption());
765     EXPECT_NO_THROW(assigner.finish());
766     EXPECT_NO_THROW(options.finish());
767
768     EXPECT_EQ("test", value);
769     EXPECT_EQ(1, index);
770 }
771
772 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
773 {
774     gmx::Options           options(NULL, NULL);
775     std::string            value;
776     const char * const     allowed[] = { "none", "test", "value" };
777     int                    index     = -3;
778     using gmx::StringOption;
779     ASSERT_NO_THROW(options.addOption(
780                             StringOption("p").store(&value)
781                                 .enumValue(allowed).storeEnumIndex(&index)));
782     EXPECT_TRUE(value.empty());
783     EXPECT_EQ(-1, index);
784
785     ASSERT_NO_THROW(options.finish());
786
787     EXPECT_TRUE(value.empty());
788     EXPECT_EQ(-1, index);
789 }
790
791 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
792 {
793     gmx::Options           options(NULL, NULL);
794     std::string            value;
795     const char * const     allowed[] = { "none", "test", "value" };
796     int                    index     = -1;
797     using gmx::StringOption;
798     ASSERT_NO_THROW(options.addOption(
799                             StringOption("p").store(&value)
800                                 .enumValue(allowed).defaultValue("test")
801                                 .storeEnumIndex(&index)));
802     EXPECT_EQ("test", value);
803     EXPECT_EQ(1, index);
804
805     gmx::OptionsAssigner assigner(&options);
806     EXPECT_NO_THROW(assigner.start());
807     EXPECT_NO_THROW(assigner.finish());
808     EXPECT_NO_THROW(options.finish());
809
810     EXPECT_EQ("test", value);
811     EXPECT_EQ(1, index);
812 }
813
814 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
815 {
816     gmx::Options           options(NULL, NULL);
817     std::string            value("test");
818     const char * const     allowed[] = { "none", "test", "value" };
819     int                    index     = -1;
820     using gmx::StringOption;
821     ASSERT_NO_THROW(options.addOption(
822                             StringOption("p").store(&value)
823                                 .enumValue(allowed).storeEnumIndex(&index)));
824     EXPECT_EQ("test", value);
825     EXPECT_EQ(1, index);
826
827     gmx::OptionsAssigner assigner(&options);
828     EXPECT_NO_THROW(assigner.start());
829     EXPECT_NO_THROW(assigner.finish());
830     EXPECT_NO_THROW(options.finish());
831
832     EXPECT_EQ("test", value);
833     EXPECT_EQ(1, index);
834 }
835
836 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVector)
837 {
838     gmx::Options             options(NULL, NULL);
839     std::vector<std::string> value;
840     value.push_back("test");
841     value.push_back("value");
842     const char * const       allowed[] = { "none", "test", "value" };
843     int                      index[2]  = {-1, -1};
844     using gmx::StringOption;
845     ASSERT_NO_THROW(options.addOption(
846                             StringOption("p").storeVector(&value).valueCount(2)
847                                 .enumValue(allowed).storeEnumIndex(index)));
848     EXPECT_EQ("test", value[0]);
849     EXPECT_EQ("value", value[1]);
850     EXPECT_EQ(1, index[0]);
851     EXPECT_EQ(2, index[1]);
852
853     gmx::OptionsAssigner assigner(&options);
854     EXPECT_NO_THROW(assigner.start());
855     EXPECT_NO_THROW(assigner.finish());
856     EXPECT_NO_THROW(options.finish());
857
858     EXPECT_EQ("test", value[0]);
859     EXPECT_EQ("value", value[1]);
860     EXPECT_EQ(1, index[0]);
861     EXPECT_EQ(2, index[1]);
862 }
863
864 TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndex)
865 {
866     gmx::Options           options(NULL, NULL);
867     std::string            value;
868     const char * const     allowed[] = { "none", "test", "value" };
869     int                    index     = -1;
870     using gmx::StringOption;
871     ASSERT_NO_THROW(options.addOption(
872                             StringOption("p").store(&value)
873                                 .enumValue(allowed).defaultEnumIndex(1)
874                                 .storeEnumIndex(&index)));
875     EXPECT_EQ("test", value);
876     EXPECT_EQ(1, index);
877
878     gmx::OptionsAssigner assigner(&options);
879     EXPECT_NO_THROW(assigner.start());
880     EXPECT_NO_THROW(assigner.finish());
881     EXPECT_NO_THROW(options.finish());
882
883     EXPECT_EQ("test", value);
884     EXPECT_EQ(1, index);
885 }
886
887 TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndexFromVariable)
888 {
889     gmx::Options           options(NULL, NULL);
890     const char * const     allowed[] = { "none", "test", "value" };
891     int                    index     = 1;
892     using gmx::StringOption;
893     ASSERT_NO_THROW(options.addOption(
894                             StringOption("p")
895                                 .enumValue(allowed).storeEnumIndex(&index)));
896     EXPECT_EQ(1, index);
897
898     gmx::OptionsAssigner assigner(&options);
899     EXPECT_NO_THROW(assigner.start());
900     EXPECT_NO_THROW(assigner.finish());
901     EXPECT_NO_THROW(options.finish());
902
903     EXPECT_EQ(1, index);
904 }
905
906 } // namespace