Simplified uniform GPU selection in CMake
[gromacs.git] / src / testutils / cmdlinetest.h
bloba06ddc913eb4f50c371fc51b6124ec81205170ef
1 /*
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,2018,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.
36 /*! \libinternal \file
37 * \brief
38 * Declares utilities testing command-line programs.
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
41 * \inlibraryapi
42 * \ingroup module_testutils
44 #ifndef GMX_TESTUTILS_CMDLINETEST_H
45 #define GMX_TESTUTILS_CMDLINETEST_H
47 #include <functional>
48 #include <memory>
49 #include <string>
51 #include <gtest/gtest.h>
53 // arrayref.h is not strictly necessary for this header, but nearly all
54 // callers will need it to use the constructor that takes ArrayRef.
55 #include "gromacs/utility/arrayref.h"
56 #include "gromacs/utility/classhelpers.h"
58 namespace gmx
61 class ICommandLineModule;
62 class ICommandLineOptionsModule;
64 namespace test
67 class FloatingPointTolerance;
68 class IFileMatcherSettings;
69 class ITextBlockMatcherSettings;
70 class TestFileManager;
71 class TestReferenceChecker;
73 /*! \libinternal \brief
74 * Helper class for tests that need to construct command lines.
76 * This class helps in writing tests for command-line handling.
77 * The constructor method takes an array of const char pointers, specifying the
78 * command-line arguments, each as one array element. It is also possible to
79 * construct the command line by adding individual arguments with append() and
80 * addOption().
81 * The argc() and argv() methods can then be used to obtain `argc` and `argv`
82 * (non-const char pointers) arrays for passing into methods that expect these.
84 * Note that although the interface allows passing the argc and argv pointers
85 * to methods that modify them (typically as \p f(&argc(), argv())), currently
86 * the CommandLine object is not in a consistent state internally if the
87 * parameters are actually modified. Reading the command line is possible
88 * afterwards, but modification is not.
90 * If you need to construct command lines that refer to files on the file
91 * system, see CommandLineTestHelper and CommandLineTestBase for additional
92 * convenience utilities.
94 * All constructors and methods that modify this class may throw an
95 * std::bad_alloc. Const methods and accessors do not throw.
97 * \inlibraryapi
98 * \ingroup module_testutils
100 class CommandLine
102 public:
103 //! Initializes an empty command-line object.
104 CommandLine();
105 /*! \brief
106 * Initializes a command-line object from an array.
108 * \param[in] cmdline Array of command-line arguments.
110 * \p cmdline should include the binary name as the first element if
111 * that is desired in the output.
113 * This constructor is not explicit to make it possible to create a
114 * CommandLine object directly from a C array.
116 CommandLine(const ArrayRef<const char* const>& cmdline);
117 //! \copydoc CommandLine(const ArrayRef<const char *const> &)
118 CommandLine(const ArrayRef<const std::string>& cmdline);
119 //! Creates a deep copy of a command-line object.
120 CommandLine(const CommandLine& other);
121 ~CommandLine();
123 /*! \brief
124 * Initializes a command-line object in-place from an array.
126 * \param[in] cmdline Array of command-line arguments.
128 * \p cmdline should include the binary name as the first element if
129 * that is desired in the output.
131 * This function does the same as the constructor that takes a
132 * ArrayRef. Any earlier contents of the object are discarded.
134 * Strong exception safety.
136 void initFromArray(const ArrayRef<const char* const>& cmdline);
138 /*! \brief
139 * Appends an argument to the command line.
141 * \param[in] arg Argument to append.
143 * Strong exception safety.
145 void append(const char* arg);
146 //! Convenience overload taking a std::string.
147 void append(const std::string& arg) { append(arg.c_str()); }
148 /*! \brief
149 * Adds an option to the command line, typically a boolean.
151 * \param[in] name Name of the option to append, which
152 * should start with "-".
154 void addOption(const char* name);
155 /*! \brief
156 * Adds an option-value pair to the command line.
158 * \param[in] name Name of the option to append, which
159 * should start with "-".
160 * \param[in] value Value of the argument to append.
162 void addOption(const char* name, const char* value);
163 //! Convenience overload taking a std::string.
164 void addOption(const char* name, const std::string& value);
165 //! Overload taking an int.
166 void addOption(const char* name, int value);
167 //! Overload taking a double.
168 void addOption(const char* name, double value);
169 /*! \brief
170 * Appends all arguments from \p args to the command line.
172 * If the first argument of \p args does not start with a `-`, it is
173 * skipped, assuming it is a gmx module name and thus useless.
175 void merge(const CommandLine& args);
177 //! Returns argc for passing into C-style command-line handling.
178 int& argc();
179 //! Returns argv for passing into C-style command-line handling.
180 char** argv();
181 //! Returns argc for passing into C-style command-line handling.
182 int argc() const;
183 //! Returns argv for passing into C-style command-line handling.
184 const char* const* argv() const;
185 //! Returns a single argument.
186 const char* arg(int i) const;
188 //! Returns the command line formatted as a single string.
189 std::string toString() const;
191 //! Whether the command line contains the given option.
192 bool contains(const char* name) const;
194 private:
195 class Impl;
197 PrivateImplPointer<Impl> impl_;
200 /*! \libinternal \brief
201 * Helper class for tests that construct command lines that need to reference
202 * existing files.
204 * This class provides helper methods for:
206 * 1. Adding input files to a CommandLine instance by generating them from a
207 * string provided in the test (setInputFileContents()).
208 * 2. Adding output files to a CommandLine instance (setOutputFile()).
209 * 3. Checking the contents of some of the output files using
210 * TestReferenceData (setOutputFile() and checkOutputFiles()).
211 * 4. Static methods for easily executing command-line modules
212 * (various overloads of runModule()).
214 * All files created during the test are cleaned up at the end of the test.
216 * All methods can throw std::bad_alloc.
218 * \see TestFileManager
219 * \inlibraryapi
220 * \ingroup module_testutils
222 class CommandLineTestHelper
224 public:
225 /*! \brief
226 * Runs a command-line program that implements ICommandLineModule.
228 * \param[in,out] module Module to run.
229 * The function does not take ownership.
230 * \param[in,out] commandLine Command line parameters to pass.
231 * This is only modified if \p module modifies it.
232 * \returns The return value of the module.
233 * \throws unspecified Any exception thrown by the module.
235 static int runModuleDirect(ICommandLineModule* module, CommandLine* commandLine);
236 /*! \brief
237 * Runs a command-line program that implements
238 * ICommandLineOptionsModule.
240 * \param[in,out] module Module to run.
241 * \param[in,out] commandLine Command line parameters to pass.
242 * This is only modified if \p module modifies it.
243 * \returns The return value of the module.
244 * \throws unspecified Any exception thrown by the module.
246 static int runModuleDirect(std::unique_ptr<ICommandLineOptionsModule> module, CommandLine* commandLine);
247 /*! \brief
248 * Runs a command-line program that implements
249 * ICommandLineOptionsModule.
251 * \param[in] factory Factory method for the module to run.
252 * \param[in,out] commandLine Command line parameters to pass.
253 * This is only modified if the module modifies it.
254 * \returns The return value of the module.
255 * \throws unspecified Any exception thrown by the factory or the
256 * module.
258 static int runModuleFactory(const std::function<std::unique_ptr<ICommandLineOptionsModule>()>& factory,
259 CommandLine* commandLine);
261 /*! \brief
262 * Initializes an instance.
264 * \param fileManager File manager to use for generating temporary
265 * file names and to track temporary files.
267 explicit CommandLineTestHelper(TestFileManager* fileManager);
268 ~CommandLineTestHelper();
270 /*! \brief
271 * Generates and sets an input file.
273 * \param[in,out] args CommandLine to which to add the option.
274 * \param[in] option Option to set.
275 * \param[in] extension Extension for the file to create.
276 * \param[in] contents Text to write to the input file.
278 * Creates a temporary file with contents from \p contents, and adds
279 * \p option to \p args with a value that points to the generated file.
281 void setInputFileContents(CommandLine* args,
282 const char* option,
283 const char* extension,
284 const std::string& contents);
285 /*! \brief
286 * Generates and sets an input file.
288 * \param[in,out] args CommandLine to which to add the option.
289 * \param[in] option Option to set.
290 * \param[in] extension Extension for the file to create.
291 * \param[in] contents Text to write to the input file.
293 * Creates a temporary file with contents from \p contents (each array
294 * entry on its own line), and adds \p option to \p args with a value
295 * that points to the generated file.
297 void setInputFileContents(CommandLine* args,
298 const char* option,
299 const char* extension,
300 const ArrayRef<const char* const>& contents);
301 /*! \brief
302 * Sets an output file parameter and adds it to the set of tested files.
304 * \param[in,out] args CommandLine to which to add the option.
305 * \param[in] option Option to set.
306 * \param[in] filename Name of the output file.
307 * \param[in] matcher Specifies how the contents of the file are
308 * tested.
310 * This method does the following:
311 * - Adds \p option to \p args to point a temporary file name
312 * constructed from \p filename.
313 * - Makes checkOutputFiles() to check the contents of the file
314 * against reference data, using \p matcher.
315 * - Marks the temporary file for removal at test teardown.
317 * \p filename is given to TestTemporaryFileManager to make a unique
318 * filename for the temporary file.
319 * If \p filename starts with a dot, a unique number is prefixed (such
320 * that it is possible to create multiple files with the same extension
321 * by just specifying the extension for every call of setOutputFile()).
323 * If the output file is needed to trigger some computation, or is
324 * unconditionally produced by the code under test, but the contents
325 * are not interesting for the test, use NoContentsMatch as the matcher.
326 * Note that the existence of the output file is still verified.
328 void setOutputFile(CommandLine* args,
329 const char* option,
330 const char* filename,
331 const ITextBlockMatcherSettings& matcher);
332 //! \copydoc setOutputFile(CommandLine *, const char *, const char *, const ITextBlockMatcherSettings &)
333 void setOutputFile(CommandLine* args,
334 const char* option,
335 const char* filename,
336 const IFileMatcherSettings& matcher);
338 /*! \brief
339 * Checks output files added with setOutputFile() against reference
340 * data.
342 * \param checker Reference data root location where the reference
343 * data is stored.
345 * The file contents are tested verbatim, using direct string
346 * comparison. The text can be found verbatim in the reference data
347 * XML files for manual inspection.
349 * Generates non-fatal test failures if some output file contents do
350 * not match the reference data.
352 void checkOutputFiles(TestReferenceChecker checker) const;
354 private:
355 class Impl;
357 PrivateImplPointer<Impl> impl_;
360 /*! \libinternal \brief
361 * Test fixture for tests that call a single command-line program with
362 * input/output files.
364 * This class provides a convenient package for using CommandLineTestHelper in
365 * a test that do not need special customization. It takes care of creating
366 * the other necessary objects (like TestFileManager, TestReferenceData, and
367 * CommandLine) and wrapping the methods from CommandLineTestHelper such that
368 * extra parameters are not needed. Additionally, it provides setInputFile()
369 * as a convenience function for adding a fixed input file, pointing to a file
370 * that resides in the source tree.
372 * \see CommandLineTestHelper
373 * \inlibraryapi
374 * \ingroup module_testutils
376 class CommandLineTestBase : public ::testing::Test
378 public:
379 CommandLineTestBase();
380 ~CommandLineTestBase() override;
382 /*! \brief
383 * Sets an input file.
385 * \param[in] option Option to set.
386 * \param[in] filename Name of the input file.
388 * \see TestFileManager::getInputFilePath()
390 void setInputFile(const char* option, const char* filename);
391 //! \copydoc setInputFile(const char *, const char *);
392 void setInputFile(const char* option, const std::string& filename);
393 /*! \brief
394 * Sets an input file that may be modified. The file is copied to a
395 * temporary file, which is used as the test input
397 * \param[in] option Option to set.
398 * \param[in] filename Name of the input file.
401 void setModifiableInputFile(const char* option, const char* filename);
402 //! \copydoc setModifiableInputFile(const char *, const char *);
403 void setModifiableInputFile(const char* option, const std::string& filename);
404 /*! \brief
405 * Generates and sets an input file.
407 * \see CommandLineTestHelper::setInputFileContents()
409 void setInputFileContents(const char* option, const char* extension, const std::string& contents);
410 /*! \brief
411 * Generates and sets an input file.
413 * \see CommandLineTestHelper::setInputFileContents()
415 void setInputFileContents(const char* option,
416 const char* extension,
417 const ArrayRef<const char* const>& contents);
418 /*! \brief
419 * Sets an output file parameter and adds it to the set of tested files.
421 * \see CommandLineTestHelper::setOutputFile()
423 void setOutputFile(const char* option, const char* filename, const ITextBlockMatcherSettings& matcher);
424 /*! \brief
425 * Sets an output file parameter and adds it to the set of tested files.
427 * \see CommandLineTestHelper::setOutputFile()
429 void setOutputFile(const char* option, const char* filename, const IFileMatcherSettings& matcher);
430 /*! \brief
431 * Sets a file parameter that is used for input and modified as output. The input file
432 * is copied to a temporary file that is used as input and can be modified.
434 void setInputAndOutputFile(const char* option,
435 const char* filename,
436 const ITextBlockMatcherSettings& matcher);
437 //! \copydoc setInputAndOutputFile(const char *, const char *, const ITextBlockMatcherSettings&);
438 void setInputAndOutputFile(const char* option, const char* filename, const IFileMatcherSettings& matcher);
440 /*! \brief
441 * Returns the internal CommandLine object used to construct the
442 * command line for the test.
444 * Derived test fixtures can use this to add additional options, and
445 * to access the final command line to do the actual call that is being
446 * tested.
448 * Does not throw.
450 CommandLine& commandLine();
451 /*! \brief
452 * Returns the internal TestFileManager object used to manage the
453 * files.
455 * Derived test fixtures can use this to manage files in cases the
456 * canned methods are not sufficient.
458 * Does not throw.
460 TestFileManager& fileManager();
461 /*! \brief
462 * Returns the root reference data checker.
464 * Derived test fixtures can use this to check other things than output
465 * file contents.
467 TestReferenceChecker rootChecker();
468 /*! \brief
469 * Sets the tolerance for floating-point comparisons.
471 * All following floating-point comparisons using the checker will use
472 * the new tolerance.
474 * Does not throw.
476 void setDefaultTolerance(const FloatingPointTolerance& tolerance);
477 /*! \brief
478 * Checks the output of writeHelp() against reference data.
480 void testWriteHelp(ICommandLineModule* module);
481 /*! \brief
482 * Checks output files added with setOutputFile() against reference
483 * data.
485 * \see CommandLineTestHelper::checkOutputFiles()
487 void checkOutputFiles();
489 private:
490 class Impl;
492 PrivateImplPointer<Impl> impl_;
495 } // namespace test
496 } // namespace gmx
498 #endif