Update my e-mail address on author lines.
[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@gmail.com>
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, HandlesRequiredParameterWithDefaultValue)
74 {
75     gmx::Options options(NULL, NULL);
76     int          value = 0;
77     using gmx::IntegerOption;
78     ASSERT_NO_THROW(options.addOption(
79                             IntegerOption("p").store(&value).required()
80                                 .defaultValue(1)));
81
82     EXPECT_NO_THROW(options.finish());
83     EXPECT_EQ(1, value);
84 }
85
86 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
87 {
88     gmx::Options     options(NULL, NULL);
89     std::vector<int> values;
90     using gmx::IntegerOption;
91     ASSERT_NO_THROW(options.addOption(
92                             IntegerOption("p").storeVector(&values).multiValue()));
93
94     gmx::OptionsAssigner assigner(&options);
95     EXPECT_NO_THROW(assigner.start());
96     ASSERT_NO_THROW(assigner.startOption("p"));
97     ASSERT_NO_THROW(assigner.appendValue("1"));
98     ASSERT_NO_THROW(assigner.finishOption());
99     EXPECT_THROW(assigner.startOption("p"), gmx::InvalidInputError);
100     EXPECT_NO_THROW(assigner.finish());
101     EXPECT_NO_THROW(options.finish());
102
103     EXPECT_TRUE(options.isSet("p"));
104     ASSERT_EQ(1U, values.size());
105     EXPECT_EQ(1, values[0]);
106 }
107
108 TEST(OptionsAssignerTest, HandlesMultipleParameter)
109 {
110     gmx::Options     options(NULL, NULL);
111     std::vector<int> values;
112     using gmx::IntegerOption;
113     ASSERT_NO_THROW(options.addOption(
114                             IntegerOption("p").storeVector(&values).allowMultiple()));
115
116     gmx::OptionsAssigner assigner(&options);
117     EXPECT_NO_THROW(assigner.start());
118     ASSERT_NO_THROW(assigner.startOption("p"));
119     ASSERT_NO_THROW(assigner.appendValue("1"));
120     EXPECT_NO_THROW(assigner.finishOption());
121     ASSERT_NO_THROW(assigner.startOption("p"));
122     ASSERT_NO_THROW(assigner.appendValue("2"));
123     EXPECT_NO_THROW(assigner.finishOption());
124     EXPECT_NO_THROW(assigner.finish());
125     EXPECT_NO_THROW(options.finish());
126
127     EXPECT_TRUE(options.isSet("p"));
128     ASSERT_EQ(2U, values.size());
129     EXPECT_EQ(1, values[0]);
130     EXPECT_EQ(2, values[1]);
131 }
132
133 TEST(OptionsAssignerTest, HandlesMissingValue)
134 {
135     gmx::Options options(NULL, NULL);
136     int          value1 = 0, value2 = 0;
137     using gmx::IntegerOption;
138     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
139     ASSERT_NO_THROW(options.addOption(IntegerOption("q").store(&value2)));
140
141     gmx::OptionsAssigner assigner(&options);
142     EXPECT_NO_THROW(assigner.start());
143     ASSERT_NO_THROW(assigner.startOption("p"));
144     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
145     ASSERT_NO_THROW(assigner.startOption("q"));
146     ASSERT_NO_THROW(assigner.appendValue("2"));
147     EXPECT_NO_THROW(assigner.finishOption());
148     EXPECT_NO_THROW(assigner.finish());
149     EXPECT_NO_THROW(options.finish());
150
151     EXPECT_EQ(2, value2);
152 }
153
154 TEST(OptionsAssignerTest, HandlesExtraValue)
155 {
156     gmx::Options options(NULL, NULL);
157     int          value1 = 0;
158     using gmx::IntegerOption;
159     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
160
161     gmx::OptionsAssigner assigner(&options);
162     EXPECT_NO_THROW(assigner.start());
163     ASSERT_NO_THROW(assigner.startOption("p"));
164     ASSERT_NO_THROW(assigner.appendValue("2"));
165     EXPECT_THROW(assigner.appendValue("3"), gmx::InvalidInputError);
166     EXPECT_NO_THROW(assigner.finishOption());
167     EXPECT_NO_THROW(assigner.finish());
168     EXPECT_NO_THROW(options.finish());
169
170     EXPECT_EQ(0, value1);
171 }
172
173 TEST(OptionsAssignerTest, HandlesSubSections)
174 {
175     gmx::Options options(NULL, NULL);
176     gmx::Options sub1("section1", NULL);
177     gmx::Options sub2("section2", NULL);
178     int          value  = 3;
179     int          value1 = 1;
180     int          value2 = 2;
181     using gmx::IntegerOption;
182     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
183     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
184     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
185     ASSERT_NO_THROW(options.addSubSection(&sub1));
186     ASSERT_NO_THROW(options.addSubSection(&sub2));
187
188     gmx::OptionsAssigner assigner(&options);
189     EXPECT_NO_THROW(assigner.start());
190     ASSERT_NO_THROW(assigner.startSubSection("section1"));
191     ASSERT_NO_THROW(assigner.startOption("p"));
192     EXPECT_NO_THROW(assigner.appendValue("5"));
193     EXPECT_NO_THROW(assigner.finishOption());
194     EXPECT_NO_THROW(assigner.finishSubSection());
195     ASSERT_NO_THROW(assigner.startOption("p"));
196     EXPECT_NO_THROW(assigner.appendValue("4"));
197     EXPECT_NO_THROW(assigner.finishOption());
198     ASSERT_NO_THROW(assigner.startSubSection("section2"));
199     ASSERT_NO_THROW(assigner.startOption("p"));
200     EXPECT_NO_THROW(assigner.appendValue("6"));
201     EXPECT_NO_THROW(assigner.finishOption());
202     EXPECT_NO_THROW(assigner.finishSubSection());
203     EXPECT_NO_THROW(assigner.finish());
204     EXPECT_NO_THROW(options.finish());
205
206     EXPECT_EQ(4, value);
207     EXPECT_EQ(5, value1);
208     EXPECT_EQ(6, value2);
209 }
210
211 TEST(OptionsAssignerTest, HandlesNoStrictSubSections)
212 {
213     gmx::Options options(NULL, NULL);
214     gmx::Options sub1("section1", NULL);
215     gmx::Options sub2("section2", NULL);
216     int          pvalue  = 3;
217     int          pvalue1 = 1;
218     int          qvalue  = 4;
219     int          pvalue2 = 2;
220     int          rvalue  = 5;
221     using gmx::IntegerOption;
222     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&pvalue)));
223     ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&pvalue1)));
224     ASSERT_NO_THROW(sub1.addOption(IntegerOption("q").store(&qvalue)));
225     ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&pvalue2)));
226     ASSERT_NO_THROW(sub2.addOption(IntegerOption("r").store(&rvalue)));
227     ASSERT_NO_THROW(options.addSubSection(&sub1));
228     ASSERT_NO_THROW(options.addSubSection(&sub2));
229
230     gmx::OptionsAssigner assigner(&options);
231     assigner.setNoStrictSectioning(true);
232     EXPECT_NO_THROW(assigner.start());
233     ASSERT_NO_THROW(assigner.startOption("q"));
234     EXPECT_NO_THROW(assigner.appendValue("6"));
235     EXPECT_NO_THROW(assigner.finishOption());
236     ASSERT_NO_THROW(assigner.startOption("p"));
237     EXPECT_NO_THROW(assigner.appendValue("7"));
238     EXPECT_NO_THROW(assigner.finishOption());
239     ASSERT_NO_THROW(assigner.startOption("r"));
240     EXPECT_NO_THROW(assigner.appendValue("8"));
241     EXPECT_NO_THROW(assigner.finishOption());
242     ASSERT_NO_THROW(assigner.startOption("p"));
243     EXPECT_NO_THROW(assigner.appendValue("9"));
244     EXPECT_NO_THROW(assigner.finishOption());
245     EXPECT_NO_THROW(assigner.finishSubSection());
246     ASSERT_NO_THROW(assigner.startOption("p"));
247     EXPECT_NO_THROW(assigner.appendValue("10"));
248     EXPECT_NO_THROW(assigner.finishOption());
249     EXPECT_NO_THROW(assigner.finish());
250     EXPECT_NO_THROW(options.finish());
251
252     EXPECT_EQ(6, qvalue);
253     EXPECT_EQ(7, pvalue1);
254     EXPECT_EQ(8, rvalue);
255     EXPECT_EQ(9, pvalue2);
256     EXPECT_EQ(10, pvalue);
257 }
258
259 TEST(OptionsAssignerTest, HandlesMultipleSources)
260 {
261     gmx::Options options(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
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(NULL, NULL);
606     int              vec[3] = {3, 2, 1};
607     std::vector<int> vec2(vec, vec+3);
608     using gmx::IntegerOption;
609     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
610                                           .storeVector(&vec2).vector()));
611
612     gmx::OptionsAssigner assigner(&options);
613     EXPECT_NO_THROW(assigner.start());
614     ASSERT_NO_THROW(assigner.startOption("p"));
615     EXPECT_NO_THROW(assigner.appendValue("1"));
616     EXPECT_NO_THROW(assigner.appendValue("3"));
617     EXPECT_THROW(assigner.finishOption(), gmx::InvalidInputError);
618     EXPECT_NO_THROW(assigner.finish());
619     EXPECT_NO_THROW(options.finish());
620
621     EXPECT_EQ(3, vec[0]);
622     EXPECT_EQ(2, vec[1]);
623     EXPECT_EQ(1, vec[2]);
624     ASSERT_EQ(3U, vec2.size());
625     EXPECT_EQ(3, vec2[0]);
626     EXPECT_EQ(2, vec2[1]);
627     EXPECT_EQ(1, vec2[2]);
628 }
629
630
631 /********************************************************************
632  * Tests for double assignment
633  */
634
635 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
636 {
637     gmx::Options options(NULL, NULL);
638     double       value = 0.0;
639     using gmx::DoubleOption;
640     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
641
642     gmx::OptionsAssigner assigner(&options);
643     EXPECT_NO_THROW(assigner.start());
644     ASSERT_NO_THROW(assigner.startOption("p"));
645     ASSERT_NO_THROW(assigner.appendValue("2.7"));
646     EXPECT_NO_THROW(assigner.finishOption());
647     EXPECT_NO_THROW(assigner.finish());
648     EXPECT_NO_THROW(options.finish());
649
650     EXPECT_DOUBLE_EQ(2.7, value);
651 }
652
653 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
654 {
655     gmx::Options options(NULL, NULL);
656     double       value = 1.0;
657     using gmx::DoubleOption;
658     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
659
660     gmx::OptionsAssigner assigner(&options);
661     EXPECT_NO_THROW(assigner.start());
662     ASSERT_NO_THROW(assigner.startOption("p"));
663     EXPECT_THROW(assigner.appendValue(""), gmx::InvalidInputError);
664     EXPECT_NO_THROW(assigner.finishOption());
665     EXPECT_NO_THROW(assigner.finish());
666     EXPECT_NO_THROW(options.finish());
667
668     EXPECT_DOUBLE_EQ(1.0, value);
669 }
670
671
672 /********************************************************************
673  * Tests for string assignment
674  */
675
676 TEST(OptionsAssignerStringTest, StoresSingleValue)
677 {
678     gmx::Options           options(NULL, NULL);
679     std::string            value;
680     using gmx::StringOption;
681     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
682
683     gmx::OptionsAssigner assigner(&options);
684     EXPECT_NO_THROW(assigner.start());
685     ASSERT_NO_THROW(assigner.startOption("p"));
686     ASSERT_NO_THROW(assigner.appendValue("value"));
687     EXPECT_NO_THROW(assigner.finishOption());
688     EXPECT_NO_THROW(assigner.finish());
689     EXPECT_NO_THROW(options.finish());
690
691     EXPECT_EQ("value", value);
692 }
693
694 TEST(OptionsAssignerStringTest, HandlesEnumValue)
695 {
696     gmx::Options           options(NULL, NULL);
697     std::string            value;
698     const char * const     allowed[] = { "none", "test", "value", NULL };
699     int                    index     = -1;
700     using gmx::StringOption;
701     ASSERT_NO_THROW(options.addOption(
702                             StringOption("p").store(&value)
703                                 .enumValue(allowed).storeEnumIndex(&index)));
704
705     gmx::OptionsAssigner assigner(&options);
706     EXPECT_NO_THROW(assigner.start());
707     ASSERT_NO_THROW(assigner.startOption("p"));
708     ASSERT_NO_THROW(assigner.appendValue("test"));
709     EXPECT_NO_THROW(assigner.finishOption());
710     EXPECT_NO_THROW(assigner.finish());
711     EXPECT_NO_THROW(options.finish());
712
713     EXPECT_EQ("test", value);
714     EXPECT_EQ(1, index);
715 }
716
717 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
718 {
719     gmx::Options           options(NULL, NULL);
720     std::string            value;
721     const char * const     allowed[] = { "none", "test", "value", NULL };
722     int                    index     = -1;
723     using gmx::StringOption;
724     ASSERT_NO_THROW(options.addOption(
725                             StringOption("p").store(&value)
726                                 .enumValue(allowed).storeEnumIndex(&index)));
727
728     gmx::OptionsAssigner assigner(&options);
729     EXPECT_NO_THROW(assigner.start());
730     ASSERT_NO_THROW(assigner.startOption("p"));
731     ASSERT_THROW(assigner.appendValue("unknown"), gmx::InvalidInputError);
732 }
733
734 TEST(OptionsAssignerStringTest, CompletesEnumValue)
735 {
736     gmx::Options           options(NULL, NULL);
737     std::string            value;
738     const char * const     allowed[] = { "none", "test", "value", NULL };
739     int                    index     = -1;
740     using gmx::StringOption;
741     ASSERT_NO_THROW(options.addOption(
742                             StringOption("p").store(&value)
743                                 .enumValue(allowed).storeEnumIndex(&index)));
744
745     gmx::OptionsAssigner assigner(&options);
746     EXPECT_NO_THROW(assigner.start());
747     ASSERT_NO_THROW(assigner.startOption("p"));
748     ASSERT_NO_THROW(assigner.appendValue("te"));
749     EXPECT_NO_THROW(assigner.finishOption());
750     EXPECT_NO_THROW(assigner.finish());
751     EXPECT_NO_THROW(options.finish());
752
753     EXPECT_EQ("test", value);
754     EXPECT_EQ(1, index);
755 }
756
757 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
758 {
759     gmx::Options           options(NULL, NULL);
760     std::string            value;
761     const char * const     allowed[] = { "none", "test", "value", NULL };
762     int                    index     = -3;
763     using gmx::StringOption;
764     ASSERT_NO_THROW(options.addOption(
765                             StringOption("p").store(&value)
766                                 .enumValue(allowed).storeEnumIndex(&index)));
767     EXPECT_TRUE(value.empty());
768     EXPECT_EQ(-1, index);
769
770     ASSERT_NO_THROW(options.finish());
771
772     EXPECT_TRUE(value.empty());
773     EXPECT_EQ(-1, index);
774 }
775
776 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
777 {
778     gmx::Options           options(NULL, NULL);
779     std::string            value;
780     const char * const     allowed[] = { "none", "test", "value", NULL };
781     int                    index     = -1;
782     using gmx::StringOption;
783     ASSERT_NO_THROW(options.addOption(
784                             StringOption("p").store(&value)
785                                 .enumValue(allowed).defaultValue("test")
786                                 .storeEnumIndex(&index)));
787     EXPECT_EQ("test", value);
788     EXPECT_EQ(1, index);
789
790     gmx::OptionsAssigner assigner(&options);
791     EXPECT_NO_THROW(assigner.start());
792     EXPECT_NO_THROW(assigner.finish());
793     EXPECT_NO_THROW(options.finish());
794
795     EXPECT_EQ("test", value);
796     EXPECT_EQ(1, index);
797 }
798
799 TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndex)
800 {
801     gmx::Options           options(NULL, NULL);
802     std::string            value;
803     const char * const     allowed[] = { "none", "test", "value", NULL };
804     int                    index     = -1;
805     using gmx::StringOption;
806     ASSERT_NO_THROW(options.addOption(
807                             StringOption("p").store(&value)
808                                 .enumValue(allowed).defaultEnumIndex(1)
809                                 .storeEnumIndex(&index)));
810     EXPECT_EQ("test", value);
811     EXPECT_EQ(1, index);
812
813     gmx::OptionsAssigner assigner(&options);
814     EXPECT_NO_THROW(assigner.start());
815     EXPECT_NO_THROW(assigner.finish());
816     EXPECT_NO_THROW(options.finish());
817
818     EXPECT_EQ("test", value);
819     EXPECT_EQ(1, index);
820 }
821
822 } // namespace