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