2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
5 * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Tests gmx::CommandLineHelpWriter.
40 * These tests fail for any change in the output, and it should be reviewed
41 * whether the change was intentional.
42 * For development, the tests can be run with a '-stdout' command-line option
43 * to print out the help to stdout instead of using the XML reference
46 * \author Teemu Murtola <teemu.murtola@gmail.com>
47 * \ingroup module_commandline
51 #include "gromacs/commandline/cmdlinehelpwriter.h"
53 #include <gtest/gtest.h>
55 #include "gromacs/commandline/cmdlinehelpcontext.h"
56 #include "gromacs/math/vectypes.h"
57 #include "gromacs/options/basicoptions.h"
58 #include "gromacs/options/filenameoption.h"
59 #include "gromacs/options/options.h"
60 #include "gromacs/utility/arrayref.h"
61 #include "gromacs/utility/enumerationhelpers.h"
62 #include "gromacs/utility/stringstream.h"
63 #include "gromacs/utility/textwriter.h"
65 #include "testutils/stringtest.h"
70 class CommandLineHelpWriterTest
: public ::gmx::test::StringTestBase
73 CommandLineHelpWriterTest() : bHidden_(false) {}
75 void checkHelp(gmx::CommandLineHelpWriter
* writer
);
80 void CommandLineHelpWriterTest::checkHelp(gmx::CommandLineHelpWriter
* writer
)
82 gmx::StringOutputStream stream
;
83 gmx::TextWriter
streamWriter(&stream
);
84 gmx::CommandLineHelpContext
context(&streamWriter
, gmx::eHelpOutputFormat_Console
, nullptr,
86 context
.setShowHidden(bHidden_
);
87 writer
->writeHelp(context
);
90 checkText(stream
.toString(), "HelpText");
94 /********************************************************************
99 * Tests help printing for each option type, but doesn't contain much
100 * variablity in the options.
102 TEST_F(CommandLineHelpWriterTest
, HandlesOptionTypes
)
107 options
.addOption(BooleanOption("bool").description("Boolean option").defaultValue(true));
108 options
.addOption(BooleanOption("hidden").description("Hidden option").hidden().defaultValue(true));
109 options
.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
110 ivec intvec
= { 1, 2, 3 };
111 options
.addOption(IntegerOption("ivec").description("Integer vector option").vector().store(intvec
));
112 options
.addOption(DoubleOption("double").description("Double option").defaultValue(2.5));
113 dvec dblvec
= { 1.1, 2.3, 3.2 };
114 options
.addOption(DoubleOption("dvec").description("Double vector option").vector().store(dblvec
));
115 options
.addOption(DoubleOption("time").description("Time option (%t)").timeValue().defaultValue(10.0));
116 options
.addOption(StringOption("string").description("String option").defaultValue("test"));
117 const char* const enumValues
[] = { "no", "opt1", "opt2" };
118 enum class TestEnum
: int
125 const gmx::EnumerationArray
<TestEnum
, const char*> testEnumNames
= { { "no", "opt1", "opt2" } };
128 StringOption("enum").description("Enum option").enumValue(enumValues
).defaultEnumIndex(0));
130 EnumOption
<TestEnum
>("ienum").description("Enum option").enumValue(testEnumNames
).defaultValue(TestEnum::Opt1
));
132 std::string filename
;
133 options
.addOption(FileNameOption("f")
134 .description("Input file description")
135 .filetype(eftTrajectory
)
138 .defaultBasename("traj"));
139 options
.addOption(FileNameOption("mult")
140 .description("Multiple file description")
141 .filetype(eftTrajectory
)
144 .defaultBasename("traj"));
145 options
.addOption(FileNameOption("lib")
146 .description("Library file description")
147 .filetype(eftGenericData
)
150 .defaultBasename("libdata"));
151 options
.addOption(FileNameOption("io")
153 .description("Input/Output file description")
154 .filetype(eftGenericData
)
156 .defaultBasename("inout"));
158 FileNameOption("o").description("Output file description").filetype(eftPlot
).outputFile());
160 CommandLineHelpWriter
writer(options
);
165 //! Enum value for testing.
166 enum class TestEnum
: int
174 * Tests that default values taken from variables are properly visible in the
177 TEST_F(CommandLineHelpWriterTest
, HandlesDefaultValuesFromVariables
)
184 options
.addOption(BooleanOption("bool").description("Boolean option").store(&bValue
));
187 options
.addOption(IntegerOption("int").description("Integer option").store(&ivalue
));
189 int iavalue
[] = { 2, 3 };
191 IntegerOption("int2").description("Integer 2-value option").store(iavalue
).valueCount(2));
193 std::vector
<std::string
> svalues
;
194 svalues
.emplace_back("foo");
195 options
.addOption(StringOption("str").description("String option").storeVector(&svalues
).multiValue());
197 TestEnum evalue
= TestEnum::Bar
;
198 const gmx::EnumerationArray
<TestEnum
, const char*> allowed
= { { "foo", "bar" } };
200 EnumOption
<TestEnum
>("enum").description("Enum option").enumValue(allowed
).store(&evalue
));
202 CommandLineHelpWriter
writer(options
);
207 * Tests help printing with file name options with various values that don't
208 * fit into the allocated columns.
210 TEST_F(CommandLineHelpWriterTest
, HandlesLongFileOptions
)
212 using gmx::eftGenericData
;
213 using gmx::eftTrajectory
;
214 using gmx::FileNameOption
;
216 gmx::Options options
;
217 options
.addOption(FileNameOption("f")
218 .description("File name option with a long value")
219 .filetype(eftTrajectory
)
222 .defaultBasename("path/to/long/trajectory/name"));
223 options
.addOption(FileNameOption("f2")
224 .description("File name option with a long value")
225 .filetype(eftTrajectory
)
228 .defaultBasename("path/to/long/trajectory"));
229 options
.addOption(FileNameOption("lib")
230 .description("File name option with a long value and type")
231 .filetype(eftTrajectory
)
234 .defaultBasename("path/to/long/trajectory/name"));
235 options
.addOption(FileNameOption("longfileopt")
236 .description("File name option with a long name")
237 .filetype(eftGenericData
)
239 .defaultBasename("deffile"));
240 options
.addOption(FileNameOption("longfileopt2")
241 .description("File name option with multiple long fields")
242 .filetype(eftGenericData
)
245 .defaultBasename("path/to/long/file/name"));
247 gmx::CommandLineHelpWriter
writer(options
);
252 * Tests help printing with general options with various values that don't
253 * fit into the allocated columns.
255 TEST_F(CommandLineHelpWriterTest
, HandlesLongOptions
)
257 using gmx::BooleanOption
;
258 using gmx::DoubleOption
;
259 using gmx::StringOption
;
261 gmx::Options options
;
263 BooleanOption("longboolean").description("Boolean option with a long name").defaultValue(true));
264 dvec dblvec
= { 1.135, 2.32, 3.2132 };
265 options
.addOption(DoubleOption("dvec").description("Double vector option").vector().store(dblvec
));
266 std::vector
<std::string
> values
;
267 values
.emplace_back("A very long string value that overflows even the description column");
269 "Another very long string value that overflows even the description column");
270 options
.addOption(StringOption("string")
271 .description("String option with very long values (may "
272 "be less relevant with selections having "
273 "their own option type)")
274 .storeVector(&values
));
276 gmx::CommandLineHelpWriter
writer(options
);
280 /* TODO: Add corresponding tests to either the selection module, or as part of
281 * trajectoryanalysis tests.
282 * Tests help printing with selection options with values.
285 TEST_F(CommandLineHelpWriterTest
, HandlesSelectionOptions
)
287 using gmx::SelectionFileOption
;
288 using gmx::SelectionOption
;
290 gmx::Options options
;
291 gmx::SelectionCollection selections
;
292 gmx::SelectionOptionManager
manager(&selections
);
293 options
.addManager(&manager
);
294 options
.addOption(SelectionFileOption("sf"));
295 options
.addOption(SelectionOption("refsel").required()
296 .description("Reference selection option"));
297 options
.addOption(SelectionOption("sel").required().valueCount(2)
298 .description("Selection option"));
300 manager
.parseRequestedFromString(
302 "surface = within 0.5 of resname SOL;"
303 "group \"Protein\" and surface;"
304 "group \"Protein\" and not surface;");
306 gmx::CommandLineHelpWriter
writer(options
);
312 * Tests help output with option groups.
314 TEST_F(CommandLineHelpWriterTest
, HandlesOptionGroups
)
316 using gmx::IntegerOption
;
318 gmx::Options options
;
319 gmx::IOptionsContainer
& group1
= options
.addGroup();
320 gmx::IOptionsContainer
& group2
= options
.addGroup();
321 group2
.addOption(IntegerOption("sub2").description("Option in group 2"));
322 group1
.addOption(IntegerOption("sub11").description("Option in group 1"));
323 options
.addOption(IntegerOption("main").description("Option in root group"));
324 group1
.addOption(IntegerOption("sub12").description("Option in group 1"));
326 gmx::CommandLineHelpWriter
writer(options
);
331 * Tests help output using a help text.
333 TEST_F(CommandLineHelpWriterTest
, HandlesHelpText
)
335 const char* const help
[] = { "Help text", "for testing." };
336 using gmx::IntegerOption
;
338 gmx::Options options
;
339 options
.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
341 gmx::CommandLineHelpWriter
writer(options
);
342 writer
.setHelpText(help
);
347 * Test known issue output.
349 TEST_F(CommandLineHelpWriterTest
, HandlesKnownIssues
)
351 const char* const bugs
[] = { "This is a bug.", "And this is another one." };
352 using gmx::IntegerOption
;
354 gmx::Options options
;
355 options
.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
357 gmx::CommandLineHelpWriter
writer(options
);
358 writer
.setKnownIssues(bugs
);