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