2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015,2016,2017,2019, 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.
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.
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.
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.
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.
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.
37 * Tests gmx::CommandLineHelpWriter.
39 * These tests fail for any change in the output, and it should be reviewed
40 * whether the change was intentional.
41 * For development, the tests can be run with a '-stdout' command-line option
42 * to print out the help to stdout instead of using the XML reference
45 * \author Teemu Murtola <teemu.murtola@gmail.com>
46 * \ingroup module_commandline
50 #include "gromacs/commandline/cmdlinehelpwriter.h"
52 #include <gtest/gtest.h>
54 #include "gromacs/commandline/cmdlinehelpcontext.h"
55 #include "gromacs/math/vectypes.h"
56 #include "gromacs/options/basicoptions.h"
57 #include "gromacs/options/filenameoption.h"
58 #include "gromacs/options/options.h"
59 #include "gromacs/utility/arrayref.h"
60 #include "gromacs/utility/stringstream.h"
61 #include "gromacs/utility/textwriter.h"
63 #include "testutils/stringtest.h"
68 class CommandLineHelpWriterTest
: public ::gmx::test::StringTestBase
71 CommandLineHelpWriterTest() : bHidden_(false) {}
73 void checkHelp(gmx::CommandLineHelpWriter
*writer
);
78 void CommandLineHelpWriterTest::checkHelp(gmx::CommandLineHelpWriter
*writer
)
80 gmx::StringOutputStream stream
;
81 gmx::TextWriter
streamWriter(&stream
);
82 gmx::CommandLineHelpContext
context(&streamWriter
, gmx::eHelpOutputFormat_Console
,
84 context
.setShowHidden(bHidden_
);
85 writer
->writeHelp(context
);
88 checkText(stream
.toString(), "HelpText");
92 /********************************************************************
97 * Tests help printing for each option type, but doesn't contain much
98 * variablity in the options.
100 TEST_F(CommandLineHelpWriterTest
, HandlesOptionTypes
)
105 options
.addOption(BooleanOption("bool").description("Boolean option")
106 .defaultValue(true));
107 options
.addOption(BooleanOption("hidden").description("Hidden option")
108 .hidden().defaultValue(true));
109 options
.addOption(IntegerOption("int").description("Integer option")
111 ivec intvec
= {1, 2, 3};
112 options
.addOption(IntegerOption("ivec").description("Integer vector option")
113 .vector().store(intvec
));
114 options
.addOption(DoubleOption("double").description("Double option")
116 dvec dblvec
= {1.1, 2.3, 3.2};
117 options
.addOption(DoubleOption("dvec").description("Double vector option")
118 .vector().store(dblvec
));
119 options
.addOption(DoubleOption("time").description("Time option (%t)")
120 .timeValue().defaultValue(10.0));
121 options
.addOption(StringOption("string").description("String option")
122 .defaultValue("test"));
123 const char * const enumValues
[] = { "no", "opt1", "opt2" };
124 options
.addOption(StringOption("enum").description("Enum option")
125 .enumValue(enumValues
).defaultEnumIndex(0));
126 options
.addOption(EnumIntOption("ienum").description("Enum option")
127 .enumValue(enumValues
).defaultValue(1));
129 std::string filename
;
130 options
.addOption(FileNameOption("f")
131 .description("Input file description")
132 .filetype(eftTrajectory
).inputFile().required()
133 .defaultBasename("traj"));
134 options
.addOption(FileNameOption("mult")
135 .description("Multiple file description")
136 .filetype(eftTrajectory
).inputFile().multiValue()
137 .defaultBasename("traj"));
138 options
.addOption(FileNameOption("lib")
139 .description("Library file description")
140 .filetype(eftGenericData
).inputFile().libraryFile()
141 .defaultBasename("libdata"));
142 options
.addOption(FileNameOption("io")
144 .description("Input/Output file description")
145 .filetype(eftGenericData
).inputOutputFile()
146 .defaultBasename("inout"));
147 options
.addOption(FileNameOption("o")
148 .description("Output file description")
149 .filetype(eftPlot
).outputFile());
151 CommandLineHelpWriter
writer(options
);
156 //! Enum value for testing.
162 * Tests that default values taken from variables are properly visible in the
165 TEST_F(CommandLineHelpWriterTest
, HandlesDefaultValuesFromVariables
)
172 options
.addOption(BooleanOption("bool").description("Boolean option")
176 options
.addOption(IntegerOption("int").description("Integer option")
179 int iavalue
[] = {2, 3};
180 options
.addOption(IntegerOption("int2").description("Integer 2-value option")
181 .store(iavalue
).valueCount(2));
183 std::vector
<std::string
> svalues
;
184 svalues
.emplace_back("foo");
185 options
.addOption(StringOption("str").description("String option")
186 .storeVector(&svalues
).multiValue());
188 TestEnum evalue
= eBar
;
189 const char *const allowed
[] = { "foo", "bar" };
190 options
.addOption(EnumOption
<TestEnum
>("enum").description("Enum option")
191 .enumValue(allowed
).store(&evalue
));
193 CommandLineHelpWriter
writer(options
);
198 * Tests help printing with file name options with various values that don't
199 * fit into the allocated columns.
201 TEST_F(CommandLineHelpWriterTest
, HandlesLongFileOptions
)
203 using gmx::FileNameOption
;
204 using gmx::eftGenericData
;
205 using gmx::eftTrajectory
;
207 gmx::Options options
;
208 options
.addOption(FileNameOption("f")
209 .description("File name option with a long value")
210 .filetype(eftTrajectory
).inputFile().required()
211 .defaultBasename("path/to/long/trajectory/name"));
212 options
.addOption(FileNameOption("f2")
213 .description("File name option with a long value")
214 .filetype(eftTrajectory
).inputFile().required()
215 .defaultBasename("path/to/long/trajectory"));
216 options
.addOption(FileNameOption("lib")
217 .description("File name option with a long value and type")
218 .filetype(eftTrajectory
).inputFile().libraryFile()
219 .defaultBasename("path/to/long/trajectory/name"));
220 options
.addOption(FileNameOption("longfileopt")
221 .description("File name option with a long name")
222 .filetype(eftGenericData
).inputFile()
223 .defaultBasename("deffile"));
224 options
.addOption(FileNameOption("longfileopt2")
225 .description("File name option with multiple long fields")
226 .filetype(eftGenericData
).inputFile().libraryFile()
227 .defaultBasename("path/to/long/file/name"));
229 gmx::CommandLineHelpWriter
writer(options
);
234 * Tests help printing with general options with various values that don't
235 * fit into the allocated columns.
237 TEST_F(CommandLineHelpWriterTest
, HandlesLongOptions
)
239 using gmx::BooleanOption
;
240 using gmx::DoubleOption
;
241 using gmx::StringOption
;
243 gmx::Options options
;
244 options
.addOption(BooleanOption("longboolean")
245 .description("Boolean option with a long name")
246 .defaultValue(true));
247 dvec dblvec
= {1.135, 2.32, 3.2132};
248 options
.addOption(DoubleOption("dvec").description("Double vector option")
249 .vector().store(dblvec
));
250 std::vector
<std::string
> values
;
251 values
.emplace_back("A very long string value that overflows even the description column");
252 values
.emplace_back("Another very long string value that overflows even the description column");
253 options
.addOption(StringOption("string")
254 .description("String option with very long values (may "
255 "be less relevant with selections having "
256 "their own option type)")
257 .storeVector(&values
));
259 gmx::CommandLineHelpWriter
writer(options
);
263 /* TODO: Add corresponding tests to either the selection module, or as part of
264 * trajectoryanalysis tests.
265 * Tests help printing with selection options with values.
268 TEST_F(CommandLineHelpWriterTest
, HandlesSelectionOptions
)
270 using gmx::SelectionFileOption
;
271 using gmx::SelectionOption
;
273 gmx::Options options
;
274 gmx::SelectionCollection selections
;
275 gmx::SelectionOptionManager
manager(&selections
);
276 options
.addManager(&manager
);
277 options
.addOption(SelectionFileOption("sf"));
278 options
.addOption(SelectionOption("refsel").required()
279 .description("Reference selection option"));
280 options
.addOption(SelectionOption("sel").required().valueCount(2)
281 .description("Selection option"));
283 manager
.parseRequestedFromString(
285 "surface = within 0.5 of resname SOL;"
286 "group \"Protein\" and surface;"
287 "group \"Protein\" and not surface;");
289 gmx::CommandLineHelpWriter
writer(options
);
295 * Tests help output with option groups.
297 TEST_F(CommandLineHelpWriterTest
, HandlesOptionGroups
)
299 using gmx::IntegerOption
;
301 gmx::Options options
;
302 gmx::IOptionsContainer
&group1
= options
.addGroup();
303 gmx::IOptionsContainer
&group2
= options
.addGroup();
304 group2
.addOption(IntegerOption("sub2").description("Option in group 2"));
305 group1
.addOption(IntegerOption("sub11").description("Option in group 1"));
306 options
.addOption(IntegerOption("main").description("Option in root group"));
307 group1
.addOption(IntegerOption("sub12").description("Option in group 1"));
309 gmx::CommandLineHelpWriter
writer(options
);
314 * Tests help output using a help text.
316 TEST_F(CommandLineHelpWriterTest
, HandlesHelpText
)
318 const char *const help
[] = {
322 using gmx::IntegerOption
;
324 gmx::Options options
;
325 options
.addOption(IntegerOption("int").description("Integer option")
328 gmx::CommandLineHelpWriter
writer(options
);
329 writer
.setHelpText(help
);
334 * Test known issue output.
336 TEST_F(CommandLineHelpWriterTest
, HandlesKnownIssues
)
338 const char *const bugs
[] = {
340 "And this is another one."
342 using gmx::IntegerOption
;
344 gmx::Options options
;
345 options
.addOption(IntegerOption("int").description("Integer option")
348 gmx::CommandLineHelpWriter
writer(options
);
349 writer
.setKnownIssues(bugs
);