Misc. exception-related fixes.
[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 <vector>
45
46 #include <gtest/gtest.h>
47
48 #include "gromacs/fatalerror/exceptions.h"
49 #include "gromacs/options/basicoptions.h"
50 #include "gromacs/options/options.h"
51 #include "gromacs/options/optionsassigner.h"
52
53 namespace
54 {
55
56 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
57 {
58     gmx::Options options(NULL, NULL);
59     int value = 0;
60     using gmx::IntegerOption;
61     ASSERT_NO_THROW(options.addOption(
62                         IntegerOption("p").store(&value).required()));
63
64     EXPECT_THROW(options.finish(), gmx::InvalidInputError);
65 }
66
67 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
68 {
69     gmx::Options options(NULL, NULL);
70     std::vector<int> values;
71     using gmx::IntegerOption;
72     ASSERT_NO_THROW(options.addOption(
73                         IntegerOption("p").storeVector(&values).multiValue()));
74
75     gmx::OptionsAssigner assigner(&options);
76     EXPECT_NO_THROW(assigner.start());
77     ASSERT_NO_THROW(assigner.startOption("p"));
78     ASSERT_NO_THROW(assigner.appendValue("1"));
79     ASSERT_NO_THROW(assigner.finishOption());
80     EXPECT_THROW(assigner.startOption("p"), gmx::InvalidInputError);
81     EXPECT_NO_THROW(assigner.finish());
82     EXPECT_NO_THROW(options.finish());
83
84     EXPECT_TRUE(options.isSet("p"));
85     ASSERT_EQ(1U, values.size());
86     EXPECT_EQ(1, values[0]);
87 }
88
89 TEST(OptionsAssignerTest, HandlesMultipleParameter)
90 {
91     gmx::Options options(NULL, NULL);
92     std::vector<int> values;
93     using gmx::IntegerOption;
94     ASSERT_NO_THROW(options.addOption(
95                         IntegerOption("p").storeVector(&values).allowMultiple()));
96
97     gmx::OptionsAssigner assigner(&options);
98     EXPECT_NO_THROW(assigner.start());
99     ASSERT_NO_THROW(assigner.startOption("p"));
100     ASSERT_NO_THROW(assigner.appendValue("1"));
101     EXPECT_NO_THROW(assigner.finishOption());
102     ASSERT_NO_THROW(assigner.startOption("p"));
103     ASSERT_NO_THROW(assigner.appendValue("2"));
104     EXPECT_NO_THROW(assigner.finishOption());
105     EXPECT_NO_THROW(assigner.finish());
106     EXPECT_NO_THROW(options.finish());
107
108     EXPECT_TRUE(options.isSet("p"));
109     ASSERT_EQ(2U, values.size());
110     EXPECT_EQ(1, values[0]);
111     EXPECT_EQ(2, values[1]);
112 }
113
114 TEST(OptionsAssignerTest, HandlesMissingValue)
115 {
116     gmx::Options options(NULL, NULL);
117     int value1 = 0, value2 = 0;
118     using gmx::IntegerOption;
119     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
120     ASSERT_NO_THROW(options.addOption(IntegerOption("q").store(&value2)));
121
122     gmx::OptionsAssigner assigner(&options);
123     EXPECT_NO_THROW(assigner.start());
124     ASSERT_NO_THROW(assigner.startOption("p"));
125     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
126     ASSERT_NO_THROW(assigner.startOption("q"));
127     ASSERT_NO_THROW(assigner.appendValue("2"));
128     EXPECT_NO_THROW(assigner.finishOption());
129     EXPECT_NO_THROW(assigner.finish());
130     EXPECT_NO_THROW(options.finish());
131
132     EXPECT_EQ(2, value2);
133 }
134
135 TEST(OptionsAssignerTest, HandlesExtraValue)
136 {
137     gmx::Options options(NULL, NULL);
138     int value1 = 0;
139     using gmx::IntegerOption;
140     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
141
142     gmx::OptionsAssigner assigner(&options);
143     EXPECT_NO_THROW(assigner.start());
144     ASSERT_NO_THROW(assigner.startOption("p"));
145     ASSERT_NO_THROW(assigner.appendValue("2"));
146     EXPECT_THROW(assigner.appendValue("3"), gmx::InvalidInputError);
147     EXPECT_NO_THROW(assigner.finishOption());
148     EXPECT_NO_THROW(assigner.finish());
149     EXPECT_NO_THROW(options.finish());
150
151     EXPECT_EQ(2, value1);
152 }
153
154 TEST(OptionsAssignerTest, HandlesSubSections)
155 {
156     gmx::Options options(NULL, NULL);
157     gmx::Options sub1("section1", NULL);
158     gmx::Options sub2("section2", NULL);
159     int value = 3;
160     int value1 = 1;
161     int value2 = 2;
162     using gmx::IntegerOption;
163     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
164     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
165     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
166     ASSERT_NO_THROW(options.addSubSection(&sub1));
167     ASSERT_NO_THROW(options.addSubSection(&sub2));
168
169     gmx::OptionsAssigner assigner(&options);
170     EXPECT_NO_THROW(assigner.start());
171     ASSERT_NO_THROW(assigner.startSubSection("section1"));
172     ASSERT_NO_THROW(assigner.startOption("p"));
173     EXPECT_NO_THROW(assigner.appendValue("5"));
174     EXPECT_NO_THROW(assigner.finishOption());
175     EXPECT_NO_THROW(assigner.finishSubSection());
176     ASSERT_NO_THROW(assigner.startOption("p"));
177     EXPECT_NO_THROW(assigner.appendValue("4"));
178     EXPECT_NO_THROW(assigner.finishOption());
179     ASSERT_NO_THROW(assigner.startSubSection("section2"));
180     ASSERT_NO_THROW(assigner.startOption("p"));
181     EXPECT_NO_THROW(assigner.appendValue("6"));
182     EXPECT_NO_THROW(assigner.finishOption());
183     EXPECT_NO_THROW(assigner.finishSubSection());
184     EXPECT_NO_THROW(assigner.finish());
185     EXPECT_NO_THROW(options.finish());
186
187     EXPECT_EQ(4, value);
188     EXPECT_EQ(5, value1);
189     EXPECT_EQ(6, value2);
190 }
191
192 TEST(OptionsAssignerTest, HandlesNoStrictSubSections)
193 {
194     gmx::Options options(NULL, NULL);
195     gmx::Options sub1("section1", NULL);
196     gmx::Options sub2("section2", NULL);
197     int pvalue = 3;
198     int pvalue1 = 1;
199     int qvalue  = 4;
200     int pvalue2 = 2;
201     int rvalue  = 5;
202     using gmx::IntegerOption;
203     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&pvalue)));
204     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&pvalue1)));
205     ASSERT_NO_THROW(sub1.addOption(IntegerOption("q").store(&qvalue)));
206     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&pvalue2)));
207     ASSERT_NO_THROW(sub2.addOption(IntegerOption("r").store(&rvalue)));
208     ASSERT_NO_THROW(options.addSubSection(&sub1));
209     ASSERT_NO_THROW(options.addSubSection(&sub2));
210
211     gmx::OptionsAssigner assigner(&options);
212     assigner.setNoStrictSectioning(true);
213     EXPECT_NO_THROW(assigner.start());
214     ASSERT_NO_THROW(assigner.startOption("q"));
215     EXPECT_NO_THROW(assigner.appendValue("6"));
216     EXPECT_NO_THROW(assigner.finishOption());
217     ASSERT_NO_THROW(assigner.startOption("p"));
218     EXPECT_NO_THROW(assigner.appendValue("7"));
219     EXPECT_NO_THROW(assigner.finishOption());
220     ASSERT_NO_THROW(assigner.startOption("r"));
221     EXPECT_NO_THROW(assigner.appendValue("8"));
222     EXPECT_NO_THROW(assigner.finishOption());
223     ASSERT_NO_THROW(assigner.startOption("p"));
224     EXPECT_NO_THROW(assigner.appendValue("9"));
225     EXPECT_NO_THROW(assigner.finishOption());
226     EXPECT_NO_THROW(assigner.finishSubSection());
227     ASSERT_NO_THROW(assigner.startOption("p"));
228     EXPECT_NO_THROW(assigner.appendValue("10"));
229     EXPECT_NO_THROW(assigner.finishOption());
230     EXPECT_NO_THROW(assigner.finish());
231     EXPECT_NO_THROW(options.finish());
232
233     EXPECT_EQ(6, qvalue);
234     EXPECT_EQ(7, pvalue1);
235     EXPECT_EQ(8, rvalue);
236     EXPECT_EQ(9, pvalue2);
237     EXPECT_EQ(10, pvalue);
238 }
239
240 TEST(OptionsAssignerTest, HandlesMultipleSources)
241 {
242     gmx::Options options(NULL, NULL);
243     int value = -1;
244     using gmx::IntegerOption;
245     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
246
247     {
248         gmx::OptionsAssigner assigner(&options);
249         EXPECT_NO_THROW(assigner.start());
250         ASSERT_NO_THROW(assigner.startOption("p"));
251         EXPECT_NO_THROW(assigner.appendValue("1"));
252         EXPECT_NO_THROW(assigner.finishOption());
253         EXPECT_NO_THROW(assigner.finish());
254     }
255     {
256         gmx::OptionsAssigner assigner2(&options);
257         EXPECT_NO_THROW(assigner2.start());
258         ASSERT_NO_THROW(assigner2.startOption("p"));
259         EXPECT_NO_THROW(assigner2.appendValue("2"));
260         EXPECT_NO_THROW(assigner2.finishOption());
261         EXPECT_NO_THROW(assigner2.finish());
262     }
263     EXPECT_NO_THROW(options.finish());
264
265     EXPECT_EQ(2, value);
266 }
267
268
269 TEST(OptionsAssignerBooleanTest, StoresYesValue)
270 {
271     gmx::Options options(NULL, NULL);
272     bool  value = false;
273     using gmx::BooleanOption;
274     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
275
276     gmx::OptionsAssigner assigner(&options);
277     EXPECT_NO_THROW(assigner.start());
278     ASSERT_NO_THROW(assigner.startOption("p"));
279     EXPECT_NO_THROW(assigner.appendValue("yes"));
280     EXPECT_NO_THROW(assigner.finishOption());
281     EXPECT_NO_THROW(assigner.finish());
282     EXPECT_NO_THROW(options.finish());
283
284     EXPECT_TRUE(value);
285 }
286
287 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
288 {
289     gmx::Options options(NULL, NULL);
290     bool value = false;
291     using gmx::BooleanOption;
292     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
293
294     gmx::OptionsAssigner assigner(&options);
295     EXPECT_NO_THROW(assigner.start());
296     ASSERT_NO_THROW(assigner.startOption("p"));
297     EXPECT_NO_THROW(assigner.finishOption());
298     EXPECT_NO_THROW(assigner.finish());
299     EXPECT_NO_THROW(options.finish());
300
301     EXPECT_TRUE(value);
302 }
303
304 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
305 {
306     gmx::Options options(NULL, NULL);
307     bool value = true;
308     using gmx::BooleanOption;
309     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
310
311     gmx::OptionsAssigner assigner(&options);
312     assigner.setAcceptBooleanNoPrefix(true);
313     EXPECT_NO_THROW(assigner.start());
314     ASSERT_NO_THROW(assigner.startOption("nop"));
315     EXPECT_NO_THROW(assigner.finishOption());
316     EXPECT_NO_THROW(assigner.finish());
317     EXPECT_NO_THROW(options.finish());
318
319     EXPECT_FALSE(value);
320 }
321
322 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
323 {
324     gmx::Options options(NULL, NULL);
325     bool value = false;
326     using gmx::BooleanOption;
327     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
328
329     gmx::OptionsAssigner assigner(&options);
330     assigner.setAcceptBooleanNoPrefix(true);
331     EXPECT_NO_THROW(assigner.start());
332     ASSERT_NO_THROW(assigner.startOption("nop"));
333     // It's OK to fail, but if it doesn't, it should work.
334     try
335     {
336         assigner.appendValue("no");
337         assigner.finishOption();
338         EXPECT_NO_THROW(assigner.finish());
339         EXPECT_TRUE(value);
340     }
341     catch (const gmx::InvalidInputError &)
342     {
343     }
344 }
345
346
347 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
348 {
349     gmx::Options options(NULL, NULL);
350     int value = 1;
351     using gmx::IntegerOption;
352     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
353
354     gmx::OptionsAssigner assigner(&options);
355     EXPECT_NO_THROW(assigner.start());
356     ASSERT_NO_THROW(assigner.startOption("p"));
357     ASSERT_NO_THROW(assigner.appendValue("3"));
358     EXPECT_NO_THROW(assigner.finishOption());
359     EXPECT_NO_THROW(assigner.finish());
360     EXPECT_NO_THROW(options.finish());
361
362     EXPECT_EQ(3, value);
363 }
364
365 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
366 {
367     gmx::Options options(NULL, NULL);
368     int value = -1;
369     using gmx::IntegerOption;
370     ASSERT_NO_THROW(options.addOption(
371                         IntegerOption("p").store(&value).defaultValue(2)));
372     EXPECT_EQ(2, value);
373
374     gmx::OptionsAssigner assigner(&options);
375     EXPECT_NO_THROW(assigner.start());
376     EXPECT_NO_THROW(assigner.finish());
377     EXPECT_NO_THROW(options.finish());
378
379     EXPECT_EQ(2, value);
380 }
381
382 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
383 {
384     gmx::Options options(NULL, NULL);
385     int value = -1;
386     using gmx::IntegerOption;
387     ASSERT_NO_THROW(options.addOption(
388                         IntegerOption("p").store(&value).defaultValueIfSet(2)));
389     EXPECT_EQ(-1, value);
390
391     gmx::OptionsAssigner assigner(&options);
392     EXPECT_NO_THROW(assigner.start());
393     ASSERT_NO_THROW(assigner.startOption("p"));
394     EXPECT_NO_THROW(assigner.finishOption());
395     EXPECT_NO_THROW(assigner.finish());
396     EXPECT_NO_THROW(options.finish());
397
398     EXPECT_EQ(2, value);
399 }
400
401 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
402 {
403     gmx::Options options(NULL, NULL);
404     int value = -1;
405     using gmx::IntegerOption;
406     ASSERT_NO_THROW(options.addOption(
407                         IntegerOption("p").store(&value).defaultValueIfSet(2)));
408     EXPECT_EQ(-1, value);
409
410     gmx::OptionsAssigner assigner(&options);
411     EXPECT_NO_THROW(assigner.start());
412     EXPECT_NO_THROW(assigner.finish());
413     EXPECT_NO_THROW(options.finish());
414
415     EXPECT_EQ(-1, value);
416 }
417
418 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
419 {
420     gmx::Options options(NULL, NULL);
421     int value = -1;
422     using gmx::IntegerOption;
423     ASSERT_NO_THROW(options.addOption(
424                         IntegerOption("p").store(&value)
425                             .defaultValue(1).defaultValueIfSet(2)));
426     EXPECT_EQ(1, value);
427
428     gmx::OptionsAssigner assigner(&options);
429     EXPECT_NO_THROW(assigner.start());
430     ASSERT_NO_THROW(assigner.startOption("p"));
431     EXPECT_NO_THROW(assigner.finishOption());
432     EXPECT_NO_THROW(assigner.finish());
433     EXPECT_NO_THROW(options.finish());
434
435     EXPECT_EQ(2, value);
436 }
437
438 TEST(OptionsAssignerIntegerTest, StoresToVector)
439 {
440     gmx::Options          options(NULL, NULL);
441     std::vector<int>      values;
442     using gmx::IntegerOption;
443     ASSERT_NO_THROW(options.addOption(
444                         IntegerOption("p").storeVector(&values).multiValue()));
445
446     gmx::OptionsAssigner assigner(&options);
447     EXPECT_NO_THROW(assigner.start());
448     ASSERT_NO_THROW(assigner.startOption("p"));
449     ASSERT_NO_THROW(assigner.appendValue("-2"));
450     ASSERT_NO_THROW(assigner.appendValue("1"));
451     ASSERT_NO_THROW(assigner.appendValue("4"));
452     EXPECT_NO_THROW(assigner.finishOption());
453     EXPECT_NO_THROW(assigner.finish());
454     EXPECT_NO_THROW(options.finish());
455
456     EXPECT_EQ(3U, values.size());
457     EXPECT_EQ(-2, values[0]);
458     EXPECT_EQ(1, values[1]);
459     EXPECT_EQ(4, values[2]);
460 }
461
462 TEST(OptionsAssignerIntegerTest, HandlesVectors)
463 {
464     gmx::Options options(NULL, NULL);
465     int  vec[3] = {0, 0, 0};
466     using gmx::IntegerOption;
467     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
468
469     gmx::OptionsAssigner assigner(&options);
470     EXPECT_NO_THROW(assigner.start());
471     ASSERT_NO_THROW(assigner.startOption("p"));
472     ASSERT_NO_THROW(assigner.appendValue("-2"));
473     ASSERT_NO_THROW(assigner.appendValue("1"));
474     ASSERT_NO_THROW(assigner.appendValue("4"));
475     EXPECT_NO_THROW(assigner.finishOption());
476     EXPECT_NO_THROW(assigner.finish());
477     EXPECT_NO_THROW(options.finish());
478
479     EXPECT_EQ(-2, vec[0]);
480     EXPECT_EQ(1, vec[1]);
481     EXPECT_EQ(4, vec[2]);
482 }
483
484 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
485 {
486     gmx::Options options(NULL, NULL);
487     int  vec[3] = {0, 0, 0};
488     using gmx::IntegerOption;
489     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
490
491     gmx::OptionsAssigner assigner(&options);
492     EXPECT_NO_THROW(assigner.start());
493     ASSERT_NO_THROW(assigner.startOption("p"));
494     ASSERT_NO_THROW(assigner.appendValue("2"));
495     EXPECT_NO_THROW(assigner.finishOption());
496     EXPECT_NO_THROW(assigner.finish());
497     EXPECT_NO_THROW(options.finish());
498
499     EXPECT_EQ(2, vec[0]);
500     EXPECT_EQ(2, vec[1]);
501     EXPECT_EQ(2, vec[2]);
502 }
503
504 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
505 {
506     gmx::Options options(NULL, NULL);
507     int  vec[3] = {3, 2, 1};
508     using gmx::IntegerOption;
509     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
510
511     EXPECT_NO_THROW(options.finish());
512
513     EXPECT_EQ(3, vec[0]);
514     EXPECT_EQ(2, vec[1]);
515     EXPECT_EQ(1, vec[2]);
516 }
517
518 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
519 {
520     gmx::Options options(NULL, NULL);
521     int  vec[3] = {3, 2, 1};
522     std::vector<int> vec2(vec, vec+3);
523     using gmx::IntegerOption;
524     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
525                                           .storeVector(&vec2).vector()));
526
527     gmx::OptionsAssigner assigner(&options);
528     EXPECT_NO_THROW(assigner.start());
529     ASSERT_NO_THROW(assigner.startOption("p"));
530     EXPECT_NO_THROW(assigner.appendValue("1"));
531     EXPECT_NO_THROW(assigner.appendValue("3"));
532     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
533     EXPECT_NO_THROW(assigner.finish());
534     EXPECT_NO_THROW(options.finish());
535
536     EXPECT_EQ(3, vec[0]);
537     EXPECT_EQ(2, vec[1]);
538     EXPECT_EQ(1, vec[2]);
539     ASSERT_EQ(3U, vec2.size());
540     EXPECT_EQ(3, vec2[0]);
541     EXPECT_EQ(2, vec2[1]);
542     EXPECT_EQ(1, vec2[2]);
543 }
544
545 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
546 {
547     gmx::Options options(NULL, NULL);
548     double value = 0.0;
549     using gmx::DoubleOption;
550     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
551
552     gmx::OptionsAssigner assigner(&options);
553     EXPECT_NO_THROW(assigner.start());
554     ASSERT_NO_THROW(assigner.startOption("p"));
555     ASSERT_NO_THROW(assigner.appendValue("2.7"));
556     EXPECT_NO_THROW(assigner.finishOption());
557     EXPECT_NO_THROW(assigner.finish());
558     EXPECT_NO_THROW(options.finish());
559
560     EXPECT_DOUBLE_EQ(2.7, value);
561 }
562
563
564 TEST(OptionsAssignerStringTest, StoresSingleValue)
565 {
566     gmx::Options           options(NULL, NULL);
567     std::string            value;
568     using gmx::StringOption;
569     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
570
571     gmx::OptionsAssigner assigner(&options);
572     EXPECT_NO_THROW(assigner.start());
573     ASSERT_NO_THROW(assigner.startOption("p"));
574     ASSERT_NO_THROW(assigner.appendValue("value"));
575     EXPECT_NO_THROW(assigner.finishOption());
576     EXPECT_NO_THROW(assigner.finish());
577     EXPECT_NO_THROW(options.finish());
578
579     EXPECT_EQ("value", value);
580 }
581
582 TEST(OptionsAssignerStringTest, HandlesEnumValue)
583 {
584     gmx::Options           options(NULL, NULL);
585     std::string            value;
586     const char * const     allowed[] = { "none", "test", "value", NULL };
587     int                    index = -1;
588     using gmx::StringOption;
589     ASSERT_NO_THROW(options.addOption(
590                         StringOption("p").store(&value)
591                             .enumValue(allowed).storeEnumIndex(&index)));
592
593     gmx::OptionsAssigner assigner(&options);
594     EXPECT_NO_THROW(assigner.start());
595     ASSERT_NO_THROW(assigner.startOption("p"));
596     ASSERT_NO_THROW(assigner.appendValue("test"));
597     EXPECT_NO_THROW(assigner.finishOption());
598     EXPECT_NO_THROW(assigner.finish());
599     EXPECT_NO_THROW(options.finish());
600
601     EXPECT_EQ("test", value);
602     EXPECT_EQ(1, index);
603 }
604
605 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
606 {
607     gmx::Options           options(NULL, NULL);
608     std::string            value;
609     const char * const     allowed[] = { "none", "test", "value", NULL };
610     int                    index = -1;
611     using gmx::StringOption;
612     ASSERT_NO_THROW(options.addOption(
613                         StringOption("p").store(&value)
614                             .enumValue(allowed).storeEnumIndex(&index)));
615
616     gmx::OptionsAssigner assigner(&options);
617     EXPECT_NO_THROW(assigner.start());
618     ASSERT_NO_THROW(assigner.startOption("p"));
619     ASSERT_THROW(assigner.appendValue("unknown"), gmx::InvalidInputError);
620 }
621
622 TEST(OptionsAssignerStringTest, CompletesEnumValue)
623 {
624     gmx::Options           options(NULL, NULL);
625     std::string            value;
626     const char * const     allowed[] = { "none", "test", "value", NULL };
627     int                    index = -1;
628     using gmx::StringOption;
629     ASSERT_NO_THROW(options.addOption(
630                         StringOption("p").store(&value)
631                             .enumValue(allowed).storeEnumIndex(&index)));
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("te"));
637     EXPECT_NO_THROW(assigner.finishOption());
638     EXPECT_NO_THROW(assigner.finish());
639     EXPECT_NO_THROW(options.finish());
640
641     EXPECT_EQ("test", value);
642     EXPECT_EQ(1, index);
643 }
644
645 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
646 {
647     gmx::Options           options(NULL, NULL);
648     std::string            value;
649     const char * const     allowed[] = { "none", "test", "value", NULL };
650     int                    index = -3;
651     using gmx::StringOption;
652     ASSERT_NO_THROW(options.addOption(
653                         StringOption("p").store(&value)
654                             .enumValue(allowed).storeEnumIndex(&index)));
655     EXPECT_TRUE(value.empty());
656     EXPECT_EQ(-1, index);
657
658     ASSERT_NO_THROW(options.finish());
659
660     EXPECT_TRUE(value.empty());
661     EXPECT_EQ(-1, index);
662 }
663
664 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
665 {
666     gmx::Options           options(NULL, NULL);
667     std::string            value;
668     const char * const     allowed[] = { "none", "test", "value", NULL };
669     int                    index = -1;
670     using gmx::StringOption;
671     ASSERT_NO_THROW(options.addOption(
672                         StringOption("p").store(&value)
673                             .enumValue(allowed).defaultValue("test")
674                             .storeEnumIndex(&index)));
675     EXPECT_EQ("test", value);
676     EXPECT_EQ(1, index);
677
678     gmx::OptionsAssigner assigner(&options);
679     EXPECT_NO_THROW(assigner.start());
680     EXPECT_NO_THROW(assigner.finish());
681     EXPECT_NO_THROW(options.finish());
682
683     EXPECT_EQ("test", value);
684     EXPECT_EQ(1, index);
685 }
686
687 TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndex)
688 {
689     gmx::Options           options(NULL, NULL);
690     std::string            value;
691     const char * const     allowed[] = { "none", "test", "value", NULL };
692     int                    index = -1;
693     using gmx::StringOption;
694     ASSERT_NO_THROW(options.addOption(
695                         StringOption("p").store(&value)
696                             .enumValue(allowed).defaultEnumIndex(1)
697                             .storeEnumIndex(&index)));
698     EXPECT_EQ("test", value);
699     EXPECT_EQ(1, index);
700
701     gmx::OptionsAssigner assigner(&options);
702     EXPECT_NO_THROW(assigner.start());
703     EXPECT_NO_THROW(assigner.finish());
704     EXPECT_NO_THROW(options.finish());
705
706     EXPECT_EQ("test", value);
707     EXPECT_EQ(1, index);
708 }
709
710 } // namespace