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, nullptr,
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").defaultValue(true));
106 options.addOption(BooleanOption("hidden").description("Hidden option").hidden().defaultValue(true));
107 options.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
108 ivec intvec = { 1, 2, 3 };
109 options.addOption(IntegerOption("ivec").description("Integer vector option").vector().store(intvec));
110 options.addOption(DoubleOption("double").description("Double option").defaultValue(2.5));
111 dvec dblvec = { 1.1, 2.3, 3.2 };
112 options.addOption(DoubleOption("dvec").description("Double vector option").vector().store(dblvec));
113 options.addOption(DoubleOption("time").description("Time option (%t)").timeValue().defaultValue(10.0));
114 options.addOption(StringOption("string").description("String option").defaultValue("test"));
115 const char* const enumValues[] = { "no", "opt1", "opt2" };
117 StringOption("enum").description("Enum option").enumValue(enumValues).defaultEnumIndex(0));
119 EnumIntOption("ienum").description("Enum option").enumValue(enumValues).defaultValue(1));
121 std::string filename;
122 options.addOption(FileNameOption("f")
123 .description("Input file description")
124 .filetype(eftTrajectory)
127 .defaultBasename("traj"));
128 options.addOption(FileNameOption("mult")
129 .description("Multiple file description")
130 .filetype(eftTrajectory)
133 .defaultBasename("traj"));
134 options.addOption(FileNameOption("lib")
135 .description("Library file description")
136 .filetype(eftGenericData)
139 .defaultBasename("libdata"));
140 options.addOption(FileNameOption("io")
142 .description("Input/Output file description")
143 .filetype(eftGenericData)
145 .defaultBasename("inout"));
147 FileNameOption("o").description("Output file description").filetype(eftPlot).outputFile());
149 CommandLineHelpWriter writer(options);
154 //! 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").store(&bValue));
175 options.addOption(IntegerOption("int").description("Integer option").store(&ivalue));
177 int iavalue[] = { 2, 3 };
179 IntegerOption("int2").description("Integer 2-value option").store(iavalue).valueCount(2));
181 std::vector<std::string> svalues;
182 svalues.emplace_back("foo");
183 options.addOption(StringOption("str").description("String option").storeVector(&svalues).multiValue());
185 TestEnum evalue = eBar;
186 const char* const allowed[] = { "foo", "bar" };
188 EnumOption<TestEnum>("enum").description("Enum option").enumValue(allowed).store(&evalue));
190 CommandLineHelpWriter writer(options);
195 * Tests help printing with file name options with various values that don't
196 * fit into the allocated columns.
198 TEST_F(CommandLineHelpWriterTest, HandlesLongFileOptions)
200 using gmx::eftGenericData;
201 using gmx::eftTrajectory;
202 using gmx::FileNameOption;
204 gmx::Options options;
205 options.addOption(FileNameOption("f")
206 .description("File name option with a long value")
207 .filetype(eftTrajectory)
210 .defaultBasename("path/to/long/trajectory/name"));
211 options.addOption(FileNameOption("f2")
212 .description("File name option with a long value")
213 .filetype(eftTrajectory)
216 .defaultBasename("path/to/long/trajectory"));
217 options.addOption(FileNameOption("lib")
218 .description("File name option with a long value and type")
219 .filetype(eftTrajectory)
222 .defaultBasename("path/to/long/trajectory/name"));
223 options.addOption(FileNameOption("longfileopt")
224 .description("File name option with a long name")
225 .filetype(eftGenericData)
227 .defaultBasename("deffile"));
228 options.addOption(FileNameOption("longfileopt2")
229 .description("File name option with multiple long fields")
230 .filetype(eftGenericData)
233 .defaultBasename("path/to/long/file/name"));
235 gmx::CommandLineHelpWriter writer(options);
240 * Tests help printing with general options with various values that don't
241 * fit into the allocated columns.
243 TEST_F(CommandLineHelpWriterTest, HandlesLongOptions)
245 using gmx::BooleanOption;
246 using gmx::DoubleOption;
247 using gmx::StringOption;
249 gmx::Options options;
251 BooleanOption("longboolean").description("Boolean option with a long name").defaultValue(true));
252 dvec dblvec = { 1.135, 2.32, 3.2132 };
253 options.addOption(DoubleOption("dvec").description("Double vector option").vector().store(dblvec));
254 std::vector<std::string> values;
255 values.emplace_back("A very long string value that overflows even the description column");
257 "Another very long string value that overflows even the description column");
258 options.addOption(StringOption("string")
259 .description("String option with very long values (may "
260 "be less relevant with selections having "
261 "their own option type)")
262 .storeVector(&values));
264 gmx::CommandLineHelpWriter writer(options);
268 /* TODO: Add corresponding tests to either the selection module, or as part of
269 * trajectoryanalysis tests.
270 * Tests help printing with selection options with values.
273 TEST_F(CommandLineHelpWriterTest, HandlesSelectionOptions)
275 using gmx::SelectionFileOption;
276 using gmx::SelectionOption;
278 gmx::Options options;
279 gmx::SelectionCollection selections;
280 gmx::SelectionOptionManager manager(&selections);
281 options.addManager(&manager);
282 options.addOption(SelectionFileOption("sf"));
283 options.addOption(SelectionOption("refsel").required()
284 .description("Reference selection option"));
285 options.addOption(SelectionOption("sel").required().valueCount(2)
286 .description("Selection option"));
288 manager.parseRequestedFromString(
290 "surface = within 0.5 of resname SOL;"
291 "group \"Protein\" and surface;"
292 "group \"Protein\" and not surface;");
294 gmx::CommandLineHelpWriter writer(options);
300 * Tests help output with option groups.
302 TEST_F(CommandLineHelpWriterTest, HandlesOptionGroups)
304 using gmx::IntegerOption;
306 gmx::Options options;
307 gmx::IOptionsContainer& group1 = options.addGroup();
308 gmx::IOptionsContainer& group2 = options.addGroup();
309 group2.addOption(IntegerOption("sub2").description("Option in group 2"));
310 group1.addOption(IntegerOption("sub11").description("Option in group 1"));
311 options.addOption(IntegerOption("main").description("Option in root group"));
312 group1.addOption(IntegerOption("sub12").description("Option in group 1"));
314 gmx::CommandLineHelpWriter writer(options);
319 * Tests help output using a help text.
321 TEST_F(CommandLineHelpWriterTest, HandlesHelpText)
323 const char* const help[] = { "Help text", "for testing." };
324 using gmx::IntegerOption;
326 gmx::Options options;
327 options.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
329 gmx::CommandLineHelpWriter writer(options);
330 writer.setHelpText(help);
335 * Test known issue output.
337 TEST_F(CommandLineHelpWriterTest, HandlesKnownIssues)
339 const char* const bugs[] = { "This is a bug.", "And this is another one." };
340 using gmx::IntegerOption;
342 gmx::Options options;
343 options.addOption(IntegerOption("int").description("Integer option").defaultValue(2));
345 gmx::CommandLineHelpWriter writer(options);
346 writer.setKnownIssues(bugs);