Merge remote-tracking branch 'origin/release-4-6' into HEAD
[alexxy/gromacs.git] / src / gromacs / options / tests / optionsassigner.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Tests option assignment.
34  *
35  * In addition to testing gmx::OptionsAssigner, these are the main
36  * tests for the classes from basicoptions.h and basicoptionstorage.h (and
37  * their base classes) that actually implement the behavior, as well as for the
38  * internal implementation of the gmx::Options and gmx::AbstractOptionStorage
39  * classes.
40  *
41  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
42  * \ingroup module_options
43  */
44 #include <limits>
45 #include <vector>
46
47 #include <gtest/gtest.h>
48
49 #include "gromacs/options/basicoptions.h"
50 #include "gromacs/options/options.h"
51 #include "gromacs/options/optionsassigner.h"
52 #include "gromacs/utility/exceptions.h"
53 #include "gromacs/utility/stringutil.h"
54
55 namespace
56 {
57
58 /********************************************************************
59  * General assignment tests
60  */
61
62 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
63 {
64     gmx::Options options(NULL, NULL);
65     int value = 0;
66     using gmx::IntegerOption;
67     ASSERT_NO_THROW(options.addOption(
68                         IntegerOption("p").store(&value).required()));
69
70     EXPECT_THROW(options.finish(), gmx::InvalidInputError);
71 }
72
73 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
74 {
75     gmx::Options options(NULL, NULL);
76     std::vector<int> values;
77     using gmx::IntegerOption;
78     ASSERT_NO_THROW(options.addOption(
79                         IntegerOption("p").storeVector(&values).multiValue()));
80
81     gmx::OptionsAssigner assigner(&options);
82     EXPECT_NO_THROW(assigner.start());
83     ASSERT_NO_THROW(assigner.startOption("p"));
84     ASSERT_NO_THROW(assigner.appendValue("1"));
85     ASSERT_NO_THROW(assigner.finishOption());
86     EXPECT_THROW(assigner.startOption("p"), gmx::InvalidInputError);
87     EXPECT_NO_THROW(assigner.finish());
88     EXPECT_NO_THROW(options.finish());
89
90     EXPECT_TRUE(options.isSet("p"));
91     ASSERT_EQ(1U, values.size());
92     EXPECT_EQ(1, values[0]);
93 }
94
95 TEST(OptionsAssignerTest, HandlesMultipleParameter)
96 {
97     gmx::Options options(NULL, NULL);
98     std::vector<int> values;
99     using gmx::IntegerOption;
100     ASSERT_NO_THROW(options.addOption(
101                         IntegerOption("p").storeVector(&values).allowMultiple()));
102
103     gmx::OptionsAssigner assigner(&options);
104     EXPECT_NO_THROW(assigner.start());
105     ASSERT_NO_THROW(assigner.startOption("p"));
106     ASSERT_NO_THROW(assigner.appendValue("1"));
107     EXPECT_NO_THROW(assigner.finishOption());
108     ASSERT_NO_THROW(assigner.startOption("p"));
109     ASSERT_NO_THROW(assigner.appendValue("2"));
110     EXPECT_NO_THROW(assigner.finishOption());
111     EXPECT_NO_THROW(assigner.finish());
112     EXPECT_NO_THROW(options.finish());
113
114     EXPECT_TRUE(options.isSet("p"));
115     ASSERT_EQ(2U, values.size());
116     EXPECT_EQ(1, values[0]);
117     EXPECT_EQ(2, values[1]);
118 }
119
120 TEST(OptionsAssignerTest, HandlesMissingValue)
121 {
122     gmx::Options options(NULL, NULL);
123     int value1 = 0, value2 = 0;
124     using gmx::IntegerOption;
125     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
126     ASSERT_NO_THROW(options.addOption(IntegerOption("q").store(&value2)));
127
128     gmx::OptionsAssigner assigner(&options);
129     EXPECT_NO_THROW(assigner.start());
130     ASSERT_NO_THROW(assigner.startOption("p"));
131     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
132     ASSERT_NO_THROW(assigner.startOption("q"));
133     ASSERT_NO_THROW(assigner.appendValue("2"));
134     EXPECT_NO_THROW(assigner.finishOption());
135     EXPECT_NO_THROW(assigner.finish());
136     EXPECT_NO_THROW(options.finish());
137
138     EXPECT_EQ(2, value2);
139 }
140
141 TEST(OptionsAssignerTest, HandlesExtraValue)
142 {
143     gmx::Options options(NULL, NULL);
144     int value1 = 0;
145     using gmx::IntegerOption;
146     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
147
148     gmx::OptionsAssigner assigner(&options);
149     EXPECT_NO_THROW(assigner.start());
150     ASSERT_NO_THROW(assigner.startOption("p"));
151     ASSERT_NO_THROW(assigner.appendValue("2"));
152     EXPECT_THROW(assigner.appendValue("3"), gmx::InvalidInputError);
153     EXPECT_NO_THROW(assigner.finishOption());
154     EXPECT_NO_THROW(assigner.finish());
155     EXPECT_NO_THROW(options.finish());
156
157     EXPECT_EQ(0, value1);
158 }
159
160 TEST(OptionsAssignerTest, HandlesSubSections)
161 {
162     gmx::Options options(NULL, NULL);
163     gmx::Options sub1("section1", NULL);
164     gmx::Options sub2("section2", NULL);
165     int value = 3;
166     int value1 = 1;
167     int value2 = 2;
168     using gmx::IntegerOption;
169     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
170     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
171     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
172     ASSERT_NO_THROW(options.addSubSection(&sub1));
173     ASSERT_NO_THROW(options.addSubSection(&sub2));
174
175     gmx::OptionsAssigner assigner(&options);
176     EXPECT_NO_THROW(assigner.start());
177     ASSERT_NO_THROW(assigner.startSubSection("section1"));
178     ASSERT_NO_THROW(assigner.startOption("p"));
179     EXPECT_NO_THROW(assigner.appendValue("5"));
180     EXPECT_NO_THROW(assigner.finishOption());
181     EXPECT_NO_THROW(assigner.finishSubSection());
182     ASSERT_NO_THROW(assigner.startOption("p"));
183     EXPECT_NO_THROW(assigner.appendValue("4"));
184     EXPECT_NO_THROW(assigner.finishOption());
185     ASSERT_NO_THROW(assigner.startSubSection("section2"));
186     ASSERT_NO_THROW(assigner.startOption("p"));
187     EXPECT_NO_THROW(assigner.appendValue("6"));
188     EXPECT_NO_THROW(assigner.finishOption());
189     EXPECT_NO_THROW(assigner.finishSubSection());
190     EXPECT_NO_THROW(assigner.finish());
191     EXPECT_NO_THROW(options.finish());
192
193     EXPECT_EQ(4, value);
194     EXPECT_EQ(5, value1);
195     EXPECT_EQ(6, value2);
196 }
197
198 TEST(OptionsAssignerTest, HandlesNoStrictSubSections)
199 {
200     gmx::Options options(NULL, NULL);
201     gmx::Options sub1("section1", NULL);
202     gmx::Options sub2("section2", NULL);
203     int pvalue = 3;
204     int pvalue1 = 1;
205     int qvalue  = 4;
206     int pvalue2 = 2;
207     int rvalue  = 5;
208     using gmx::IntegerOption;
209     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&pvalue)));
210     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&pvalue1)));
211     ASSERT_NO_THROW(sub1.addOption(IntegerOption("q").store(&qvalue)));
212     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&pvalue2)));
213     ASSERT_NO_THROW(sub2.addOption(IntegerOption("r").store(&rvalue)));
214     ASSERT_NO_THROW(options.addSubSection(&sub1));
215     ASSERT_NO_THROW(options.addSubSection(&sub2));
216
217     gmx::OptionsAssigner assigner(&options);
218     assigner.setNoStrictSectioning(true);
219     EXPECT_NO_THROW(assigner.start());
220     ASSERT_NO_THROW(assigner.startOption("q"));
221     EXPECT_NO_THROW(assigner.appendValue("6"));
222     EXPECT_NO_THROW(assigner.finishOption());
223     ASSERT_NO_THROW(assigner.startOption("p"));
224     EXPECT_NO_THROW(assigner.appendValue("7"));
225     EXPECT_NO_THROW(assigner.finishOption());
226     ASSERT_NO_THROW(assigner.startOption("r"));
227     EXPECT_NO_THROW(assigner.appendValue("8"));
228     EXPECT_NO_THROW(assigner.finishOption());
229     ASSERT_NO_THROW(assigner.startOption("p"));
230     EXPECT_NO_THROW(assigner.appendValue("9"));
231     EXPECT_NO_THROW(assigner.finishOption());
232     EXPECT_NO_THROW(assigner.finishSubSection());
233     ASSERT_NO_THROW(assigner.startOption("p"));
234     EXPECT_NO_THROW(assigner.appendValue("10"));
235     EXPECT_NO_THROW(assigner.finishOption());
236     EXPECT_NO_THROW(assigner.finish());
237     EXPECT_NO_THROW(options.finish());
238
239     EXPECT_EQ(6, qvalue);
240     EXPECT_EQ(7, pvalue1);
241     EXPECT_EQ(8, rvalue);
242     EXPECT_EQ(9, pvalue2);
243     EXPECT_EQ(10, pvalue);
244 }
245
246 TEST(OptionsAssignerTest, HandlesMultipleSources)
247 {
248     gmx::Options options(NULL, NULL);
249     int value = -1;
250     using gmx::IntegerOption;
251     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
252
253     {
254         gmx::OptionsAssigner assigner(&options);
255         EXPECT_NO_THROW(assigner.start());
256         ASSERT_NO_THROW(assigner.startOption("p"));
257         EXPECT_NO_THROW(assigner.appendValue("1"));
258         EXPECT_NO_THROW(assigner.finishOption());
259         EXPECT_NO_THROW(assigner.finish());
260     }
261     {
262         gmx::OptionsAssigner assigner2(&options);
263         EXPECT_NO_THROW(assigner2.start());
264         ASSERT_NO_THROW(assigner2.startOption("p"));
265         EXPECT_NO_THROW(assigner2.appendValue("2"));
266         EXPECT_NO_THROW(assigner2.finishOption());
267         EXPECT_NO_THROW(assigner2.finish());
268     }
269     EXPECT_NO_THROW(options.finish());
270
271     EXPECT_EQ(2, value);
272 }
273
274
275 /********************************************************************
276  * Tests for boolean assignment
277  */
278
279 TEST(OptionsAssignerBooleanTest, StoresYesValue)
280 {
281     gmx::Options options(NULL, NULL);
282     bool  value = false;
283     using gmx::BooleanOption;
284     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
285
286     gmx::OptionsAssigner assigner(&options);
287     EXPECT_NO_THROW(assigner.start());
288     ASSERT_NO_THROW(assigner.startOption("p"));
289     EXPECT_NO_THROW(assigner.appendValue("yes"));
290     EXPECT_NO_THROW(assigner.finishOption());
291     EXPECT_NO_THROW(assigner.finish());
292     EXPECT_NO_THROW(options.finish());
293
294     EXPECT_TRUE(value);
295 }
296
297 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
298 {
299     gmx::Options options(NULL, NULL);
300     bool value = false;
301     using gmx::BooleanOption;
302     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
303
304     gmx::OptionsAssigner assigner(&options);
305     EXPECT_NO_THROW(assigner.start());
306     ASSERT_NO_THROW(assigner.startOption("p"));
307     EXPECT_NO_THROW(assigner.finishOption());
308     EXPECT_NO_THROW(assigner.finish());
309     EXPECT_NO_THROW(options.finish());
310
311     EXPECT_TRUE(value);
312 }
313
314 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
315 {
316     gmx::Options options(NULL, NULL);
317     bool value = true;
318     using gmx::BooleanOption;
319     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
320
321     gmx::OptionsAssigner assigner(&options);
322     assigner.setAcceptBooleanNoPrefix(true);
323     EXPECT_NO_THROW(assigner.start());
324     ASSERT_NO_THROW(assigner.startOption("nop"));
325     EXPECT_NO_THROW(assigner.finishOption());
326     EXPECT_NO_THROW(assigner.finish());
327     EXPECT_NO_THROW(options.finish());
328
329     EXPECT_FALSE(value);
330 }
331
332 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
333 {
334     gmx::Options options(NULL, NULL);
335     bool value = false;
336     using gmx::BooleanOption;
337     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
338
339     gmx::OptionsAssigner assigner(&options);
340     assigner.setAcceptBooleanNoPrefix(true);
341     EXPECT_NO_THROW(assigner.start());
342     ASSERT_NO_THROW(assigner.startOption("nop"));
343     // It's OK to fail, but if it doesn't, it should work.
344     try
345     {
346         assigner.appendValue("no");
347         assigner.finishOption();
348         EXPECT_NO_THROW(assigner.finish());
349         EXPECT_TRUE(value);
350     }
351     catch (const gmx::InvalidInputError &)
352     {
353     }
354 }
355
356
357 /********************************************************************
358  * Tests for integer assignment
359  *
360  * These tests also contain tests for general default value handling.
361  */
362
363 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
364 {
365     gmx::Options options(NULL, NULL);
366     int value = 1;
367     using gmx::IntegerOption;
368     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
369
370     gmx::OptionsAssigner assigner(&options);
371     EXPECT_NO_THROW(assigner.start());
372     ASSERT_NO_THROW(assigner.startOption("p"));
373     ASSERT_NO_THROW(assigner.appendValue("3"));
374     EXPECT_NO_THROW(assigner.finishOption());
375     EXPECT_NO_THROW(assigner.finish());
376     EXPECT_NO_THROW(options.finish());
377
378     EXPECT_EQ(3, value);
379 }
380
381 TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
382 {
383     gmx::Options options(NULL, NULL);
384     int value = 1;
385     using gmx::IntegerOption;
386     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
387
388     gmx::OptionsAssigner assigner(&options);
389     EXPECT_NO_THROW(assigner.start());
390     ASSERT_NO_THROW(assigner.startOption("p"));
391     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
392     EXPECT_NO_THROW(assigner.finishOption());
393     EXPECT_NO_THROW(assigner.finish());
394     EXPECT_NO_THROW(options.finish());
395
396     EXPECT_EQ(1, value);
397 }
398
399 TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
400 {
401     gmx::Options options(NULL, NULL);
402     int value = 1;
403     using gmx::IntegerOption;
404     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
405
406     gmx::OptionsAssigner assigner(&options);
407     EXPECT_NO_THROW(assigner.start());
408     ASSERT_NO_THROW(assigner.startOption("p"));
409     EXPECT_THROW(assigner.appendValue("2abc"), gmx::InvalidInputError);
410     EXPECT_NO_THROW(assigner.finishOption());
411     EXPECT_NO_THROW(assigner.finish());
412     EXPECT_NO_THROW(options.finish());
413
414     EXPECT_EQ(1, value);
415 }
416
417 TEST(OptionsAssignerIntegerTest, HandlesOverflow)
418 {
419     gmx::Options options(NULL, NULL);
420     int value = 1;
421     using gmx::IntegerOption;
422     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
423
424     gmx::OptionsAssigner assigner(&options);
425     EXPECT_NO_THROW(assigner.start());
426     ASSERT_NO_THROW(assigner.startOption("p"));
427     std::string overflowValue(
428             gmx::formatString("%d0000", std::numeric_limits<int>::max()));
429     EXPECT_THROW(assigner.appendValue(overflowValue), gmx::InvalidInputError);
430     EXPECT_NO_THROW(assigner.finishOption());
431     EXPECT_NO_THROW(assigner.finish());
432     EXPECT_NO_THROW(options.finish());
433
434     EXPECT_EQ(1, value);
435 }
436
437 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
438 {
439     gmx::Options options(NULL, NULL);
440     int value = -1;
441     using gmx::IntegerOption;
442     ASSERT_NO_THROW(options.addOption(
443                         IntegerOption("p").store(&value).defaultValue(2)));
444     EXPECT_EQ(2, value);
445
446     gmx::OptionsAssigner assigner(&options);
447     EXPECT_NO_THROW(assigner.start());
448     EXPECT_NO_THROW(assigner.finish());
449     EXPECT_NO_THROW(options.finish());
450
451     EXPECT_EQ(2, value);
452 }
453
454 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
455 {
456     gmx::Options options(NULL, NULL);
457     int value = -1;
458     using gmx::IntegerOption;
459     ASSERT_NO_THROW(options.addOption(
460                         IntegerOption("p").store(&value).defaultValueIfSet(2)));
461     EXPECT_EQ(-1, value);
462
463     gmx::OptionsAssigner assigner(&options);
464     EXPECT_NO_THROW(assigner.start());
465     ASSERT_NO_THROW(assigner.startOption("p"));
466     EXPECT_NO_THROW(assigner.finishOption());
467     EXPECT_NO_THROW(assigner.finish());
468     EXPECT_NO_THROW(options.finish());
469
470     EXPECT_EQ(2, value);
471 }
472
473 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
474 {
475     gmx::Options options(NULL, NULL);
476     int value = -1;
477     using gmx::IntegerOption;
478     ASSERT_NO_THROW(options.addOption(
479                         IntegerOption("p").store(&value).defaultValueIfSet(2)));
480     EXPECT_EQ(-1, value);
481
482     gmx::OptionsAssigner assigner(&options);
483     EXPECT_NO_THROW(assigner.start());
484     EXPECT_NO_THROW(assigner.finish());
485     EXPECT_NO_THROW(options.finish());
486
487     EXPECT_EQ(-1, value);
488 }
489
490 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
491 {
492     gmx::Options options(NULL, NULL);
493     int value = -1;
494     using gmx::IntegerOption;
495     ASSERT_NO_THROW(options.addOption(
496                         IntegerOption("p").store(&value)
497                             .defaultValue(1).defaultValueIfSet(2)));
498     EXPECT_EQ(1, value);
499
500     gmx::OptionsAssigner assigner(&options);
501     EXPECT_NO_THROW(assigner.start());
502     ASSERT_NO_THROW(assigner.startOption("p"));
503     EXPECT_NO_THROW(assigner.finishOption());
504     EXPECT_NO_THROW(assigner.finish());
505     EXPECT_NO_THROW(options.finish());
506
507     EXPECT_EQ(2, value);
508 }
509
510 TEST(OptionsAssignerIntegerTest, StoresToVector)
511 {
512     gmx::Options          options(NULL, NULL);
513     std::vector<int>      values;
514     using gmx::IntegerOption;
515     ASSERT_NO_THROW(options.addOption(
516                         IntegerOption("p").storeVector(&values).multiValue()));
517
518     gmx::OptionsAssigner assigner(&options);
519     EXPECT_NO_THROW(assigner.start());
520     ASSERT_NO_THROW(assigner.startOption("p"));
521     ASSERT_NO_THROW(assigner.appendValue("-2"));
522     ASSERT_NO_THROW(assigner.appendValue("1"));
523     ASSERT_NO_THROW(assigner.appendValue("4"));
524     EXPECT_NO_THROW(assigner.finishOption());
525     EXPECT_NO_THROW(assigner.finish());
526     EXPECT_NO_THROW(options.finish());
527
528     EXPECT_EQ(3U, values.size());
529     EXPECT_EQ(-2, values[0]);
530     EXPECT_EQ(1, values[1]);
531     EXPECT_EQ(4, values[2]);
532 }
533
534 TEST(OptionsAssignerIntegerTest, HandlesVectors)
535 {
536     gmx::Options options(NULL, NULL);
537     int  vec[3] = {0, 0, 0};
538     using gmx::IntegerOption;
539     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
540
541     gmx::OptionsAssigner assigner(&options);
542     EXPECT_NO_THROW(assigner.start());
543     ASSERT_NO_THROW(assigner.startOption("p"));
544     ASSERT_NO_THROW(assigner.appendValue("-2"));
545     ASSERT_NO_THROW(assigner.appendValue("1"));
546     ASSERT_NO_THROW(assigner.appendValue("4"));
547     EXPECT_NO_THROW(assigner.finishOption());
548     EXPECT_NO_THROW(assigner.finish());
549     EXPECT_NO_THROW(options.finish());
550
551     EXPECT_EQ(-2, vec[0]);
552     EXPECT_EQ(1, vec[1]);
553     EXPECT_EQ(4, vec[2]);
554 }
555
556 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
557 {
558     gmx::Options options(NULL, NULL);
559     int  vec[3] = {0, 0, 0};
560     using gmx::IntegerOption;
561     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
562
563     gmx::OptionsAssigner assigner(&options);
564     EXPECT_NO_THROW(assigner.start());
565     ASSERT_NO_THROW(assigner.startOption("p"));
566     ASSERT_NO_THROW(assigner.appendValue("2"));
567     EXPECT_NO_THROW(assigner.finishOption());
568     EXPECT_NO_THROW(assigner.finish());
569     EXPECT_NO_THROW(options.finish());
570
571     EXPECT_EQ(2, vec[0]);
572     EXPECT_EQ(2, vec[1]);
573     EXPECT_EQ(2, vec[2]);
574 }
575
576 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
577 {
578     gmx::Options options(NULL, NULL);
579     int  vec[3] = {3, 2, 1};
580     using gmx::IntegerOption;
581     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
582
583     EXPECT_NO_THROW(options.finish());
584
585     EXPECT_EQ(3, vec[0]);
586     EXPECT_EQ(2, vec[1]);
587     EXPECT_EQ(1, vec[2]);
588 }
589
590 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
591 {
592     gmx::Options options(NULL, NULL);
593     int  vec[3] = {3, 2, 1};
594     std::vector<int> vec2(vec, vec+3);
595     using gmx::IntegerOption;
596     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
597                                           .storeVector(&vec2).vector()));
598
599     gmx::OptionsAssigner assigner(&options);
600     EXPECT_NO_THROW(assigner.start());
601     ASSERT_NO_THROW(assigner.startOption("p"));
602     EXPECT_NO_THROW(assigner.appendValue("1"));
603     EXPECT_NO_THROW(assigner.appendValue("3"));
604     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
605     EXPECT_NO_THROW(assigner.finish());
606     EXPECT_NO_THROW(options.finish());
607
608     EXPECT_EQ(3, vec[0]);
609     EXPECT_EQ(2, vec[1]);
610     EXPECT_EQ(1, vec[2]);
611     ASSERT_EQ(3U, vec2.size());
612     EXPECT_EQ(3, vec2[0]);
613     EXPECT_EQ(2, vec2[1]);
614     EXPECT_EQ(1, vec2[2]);
615 }
616
617
618 /********************************************************************
619  * Tests for double assignment
620  */
621
622 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
623 {
624     gmx::Options options(NULL, NULL);
625     double value = 0.0;
626     using gmx::DoubleOption;
627     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
628
629     gmx::OptionsAssigner assigner(&options);
630     EXPECT_NO_THROW(assigner.start());
631     ASSERT_NO_THROW(assigner.startOption("p"));
632     ASSERT_NO_THROW(assigner.appendValue("2.7"));
633     EXPECT_NO_THROW(assigner.finishOption());
634     EXPECT_NO_THROW(assigner.finish());
635     EXPECT_NO_THROW(options.finish());
636
637     EXPECT_DOUBLE_EQ(2.7, value);
638 }
639
640 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
641 {
642     gmx::Options options(NULL, NULL);
643     double value = 1.0;
644     using gmx::DoubleOption;
645     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
646
647     gmx::OptionsAssigner assigner(&options);
648     EXPECT_NO_THROW(assigner.start());
649     ASSERT_NO_THROW(assigner.startOption("p"));
650     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
651     EXPECT_NO_THROW(assigner.finishOption());
652     EXPECT_NO_THROW(assigner.finish());
653     EXPECT_NO_THROW(options.finish());
654
655     EXPECT_DOUBLE_EQ(1.0, value);
656 }
657
658
659 /********************************************************************
660  * Tests for string assignment
661  */
662
663 TEST(OptionsAssignerStringTest, StoresSingleValue)
664 {
665     gmx::Options           options(NULL, NULL);
666     std::string            value;
667     using gmx::StringOption;
668     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
669
670     gmx::OptionsAssigner assigner(&options);
671     EXPECT_NO_THROW(assigner.start());
672     ASSERT_NO_THROW(assigner.startOption("p"));
673     ASSERT_NO_THROW(assigner.appendValue("value"));
674     EXPECT_NO_THROW(assigner.finishOption());
675     EXPECT_NO_THROW(assigner.finish());
676     EXPECT_NO_THROW(options.finish());
677
678     EXPECT_EQ("value", value);
679 }
680
681 TEST(OptionsAssignerStringTest, HandlesEnumValue)
682 {
683     gmx::Options           options(NULL, NULL);
684     std::string            value;
685     const char * const     allowed[] = { "none", "test", "value", NULL };
686     int                    index = -1;
687     using gmx::StringOption;
688     ASSERT_NO_THROW(options.addOption(
689                         StringOption("p").store(&value)
690                             .enumValue(allowed).storeEnumIndex(&index)));
691
692     gmx::OptionsAssigner assigner(&options);
693     EXPECT_NO_THROW(assigner.start());
694     ASSERT_NO_THROW(assigner.startOption("p"));
695     ASSERT_NO_THROW(assigner.appendValue("test"));
696     EXPECT_NO_THROW(assigner.finishOption());
697     EXPECT_NO_THROW(assigner.finish());
698     EXPECT_NO_THROW(options.finish());
699
700     EXPECT_EQ("test", value);
701     EXPECT_EQ(1, index);
702 }
703
704 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
705 {
706     gmx::Options           options(NULL, NULL);
707     std::string            value;
708     const char * const     allowed[] = { "none", "test", "value", NULL };
709     int                    index = -1;
710     using gmx::StringOption;
711     ASSERT_NO_THROW(options.addOption(
712                         StringOption("p").store(&value)
713                             .enumValue(allowed).storeEnumIndex(&index)));
714
715     gmx::OptionsAssigner assigner(&options);
716     EXPECT_NO_THROW(assigner.start());
717     ASSERT_NO_THROW(assigner.startOption("p"));
718     ASSERT_THROW(assigner.appendValue("unknown"), gmx::InvalidInputError);
719 }
720
721 TEST(OptionsAssignerStringTest, CompletesEnumValue)
722 {
723     gmx::Options           options(NULL, NULL);
724     std::string            value;
725     const char * const     allowed[] = { "none", "test", "value", NULL };
726     int                    index = -1;
727     using gmx::StringOption;
728     ASSERT_NO_THROW(options.addOption(
729                         StringOption("p").store(&value)
730                             .enumValue(allowed).storeEnumIndex(&index)));
731
732     gmx::OptionsAssigner assigner(&options);
733     EXPECT_NO_THROW(assigner.start());
734     ASSERT_NO_THROW(assigner.startOption("p"));
735     ASSERT_NO_THROW(assigner.appendValue("te"));
736     EXPECT_NO_THROW(assigner.finishOption());
737     EXPECT_NO_THROW(assigner.finish());
738     EXPECT_NO_THROW(options.finish());
739
740     EXPECT_EQ("test", value);
741     EXPECT_EQ(1, index);
742 }
743
744 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
745 {
746     gmx::Options           options(NULL, NULL);
747     std::string            value;
748     const char * const     allowed[] = { "none", "test", "value", NULL };
749     int                    index = -3;
750     using gmx::StringOption;
751     ASSERT_NO_THROW(options.addOption(
752                         StringOption("p").store(&value)
753                             .enumValue(allowed).storeEnumIndex(&index)));
754     EXPECT_TRUE(value.empty());
755     EXPECT_EQ(-1, index);
756
757     ASSERT_NO_THROW(options.finish());
758
759     EXPECT_TRUE(value.empty());
760     EXPECT_EQ(-1, index);
761 }
762
763 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
764 {
765     gmx::Options           options(NULL, NULL);
766     std::string            value;
767     const char * const     allowed[] = { "none", "test", "value", NULL };
768     int                    index = -1;
769     using gmx::StringOption;
770     ASSERT_NO_THROW(options.addOption(
771                         StringOption("p").store(&value)
772                             .enumValue(allowed).defaultValue("test")
773                             .storeEnumIndex(&index)));
774     EXPECT_EQ("test", value);
775     EXPECT_EQ(1, index);
776
777     gmx::OptionsAssigner assigner(&options);
778     EXPECT_NO_THROW(assigner.start());
779     EXPECT_NO_THROW(assigner.finish());
780     EXPECT_NO_THROW(options.finish());
781
782     EXPECT_EQ("test", value);
783     EXPECT_EQ(1, index);
784 }
785
786 TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndex)
787 {
788     gmx::Options           options(NULL, NULL);
789     std::string            value;
790     const char * const     allowed[] = { "none", "test", "value", NULL };
791     int                    index = -1;
792     using gmx::StringOption;
793     ASSERT_NO_THROW(options.addOption(
794                         StringOption("p").store(&value)
795                             .enumValue(allowed).defaultEnumIndex(1)
796                             .storeEnumIndex(&index)));
797     EXPECT_EQ("test", value);
798     EXPECT_EQ(1, index);
799
800     gmx::OptionsAssigner assigner(&options);
801     EXPECT_NO_THROW(assigner.start());
802     EXPECT_NO_THROW(assigner.finish());
803     EXPECT_NO_THROW(options.finish());
804
805     EXPECT_EQ("test", value);
806     EXPECT_EQ(1, index);
807 }
808
809 } // namespace