SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / testutils / include / testutils / cmdlinetest.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
5  * Copyright (c) 2017,2018,2019,2020,2021, 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.
9  *
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.
14  *
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.
19  *
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.
24  *
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.
32  *
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.
35  */
36 /*! \libinternal \file
37  * \brief
38  * Declares utilities testing command-line programs.
39  *
40  * \author Teemu Murtola <teemu.murtola@gmail.com>
41  * \inlibraryapi
42  * \ingroup module_testutils
43  */
44 #ifndef GMX_TESTUTILS_CMDLINETEST_H
45 #define GMX_TESTUTILS_CMDLINETEST_H
46
47 #include <functional>
48 #include <memory>
49 #include <string>
50
51 #include <gtest/gtest.h>
52
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
57 namespace gmx
58 {
59
60 class ICommandLineModule;
61 class ICommandLineOptionsModule;
62
63 namespace test
64 {
65
66 class FloatingPointTolerance;
67 class IFileMatcherSettings;
68 class ITextBlockMatcherSettings;
69 class TestFileManager;
70 class TestReferenceChecker;
71
72 /*! \libinternal \brief
73  * Helper class for tests that need to construct command lines.
74  *
75  * This class helps in writing tests for command-line handling.
76  * The constructor method takes an array of const char pointers, specifying the
77  * command-line arguments, each as one array element.  It is also possible to
78  * construct the command line by adding individual arguments with append() and
79  * addOption().
80  * The argc() and argv() methods can then be used to obtain `argc` and `argv`
81  * (non-const char pointers) arrays for passing into methods that expect these.
82  *
83  * Note that although the interface allows passing the argc and argv pointers
84  * to methods that modify them (typically as \p f(&argc(), argv())), currently
85  * the CommandLine object is not in a consistent state internally if the
86  * parameters are actually modified.  Reading the command line is possible
87  * afterwards, but modification is not.
88  *
89  * If you need to construct command lines that refer to files on the file
90  * system, see CommandLineTestHelper and CommandLineTestBase for additional
91  * convenience utilities.
92  *
93  * All constructors and methods that modify this class may throw an
94  * std::bad_alloc.  Const methods and accessors do not throw.
95  *
96  * \inlibraryapi
97  * \ingroup module_testutils
98  */
99 class CommandLine
100 {
101 public:
102     //! Initializes an empty command-line object.
103     CommandLine();
104     /*! \brief
105      * Initializes a command-line object from an array.
106      *
107      * \param[in] cmdline  Array of command-line arguments.
108      *
109      * \p cmdline should include the binary name as the first element if
110      * that is desired in the output.
111      *
112      * This constructor is not explicit to make it possible to create a
113      * CommandLine object directly from a C array.
114      */
115     CommandLine(const ArrayRef<const char* const>& cmdline);
116     //! \copydoc CommandLine(const ArrayRef<const char *const> &)
117     CommandLine(const ArrayRef<const std::string>& cmdline);
118     //! Creates a deep copy of a command-line object.
119     CommandLine(const CommandLine& other);
120     ~CommandLine();
121
122     /*! \brief
123      * Initializes a command-line object in-place from an array.
124      *
125      * \param[in] cmdline  Array of command-line arguments.
126      *
127      * \p cmdline should include the binary name as the first element if
128      * that is desired in the output.
129      *
130      * This function does the same as the constructor that takes a
131      * ArrayRef.  Any earlier contents of the object are discarded.
132      *
133      * Strong exception safety.
134      */
135     void initFromArray(const ArrayRef<const char* const>& cmdline);
136
137     /*! \brief
138      * Appends an argument to the command line.
139      *
140      * \param[in] arg  Argument to append.
141      *
142      * Strong exception safety.
143      */
144     void append(const char* arg);
145     //! Convenience overload taking a std::string.
146     void append(const std::string& arg) { append(arg.c_str()); }
147     /*! \brief
148      * Adds an option to the command line, typically a boolean.
149      *
150      * \param[in] name   Name of the option to append, which
151      *                   should start with "-".
152      */
153     void addOption(const char* name);
154     /*! \brief
155      * Adds an option-value pair to the command line.
156      *
157      * \param[in] name   Name of the option to append, which
158      *                   should start with "-".
159      * \param[in] value  Value of the argument to append.
160      */
161     void addOption(const char* name, const char* value);
162     //! Convenience overload taking a std::string.
163     void addOption(const char* name, const std::string& value);
164     //! Overload taking an int.
165     void addOption(const char* name, int value);
166     //! Overload taking a double.
167     void addOption(const char* name, double value);
168     /*! \brief
169      * Appends all arguments from \p args to the command line.
170      *
171      * If the first argument of \p args does not start with a `-`, it is
172      * skipped, assuming it is a gmx module name and thus useless.
173      */
174     void merge(const CommandLine& args);
175
176     //! Returns argc for passing into C-style command-line handling.
177     int& argc();
178     //! Returns argv for passing into C-style command-line handling.
179     char** argv();
180     //! Returns argc for passing into C-style command-line handling.
181     int argc() const;
182     //! Returns argv for passing into C-style command-line handling.
183     const char* const* argv() const;
184     //! Returns a single argument.
185     const char* arg(int i) const;
186
187     //! Returns the command line formatted as a single string.
188     std::string toString() const;
189
190     //! Whether the command line contains the given option.
191     bool contains(const char* name) const;
192
193 private:
194     class Impl;
195
196     std::unique_ptr<Impl> impl_;
197 };
198
199 /*! \libinternal \brief
200  * Helper class for tests that construct command lines that need to reference
201  * existing files.
202  *
203  * This class provides helper methods for:
204  *
205  *   1. Adding input files to a CommandLine instance by generating them from a
206  *      string provided in the test (setInputFileContents()).
207  *   2. Adding output files to a CommandLine instance (setOutputFile()).
208  *   3. Checking the contents of some of the output files using
209  *      TestReferenceData (setOutputFile() and checkOutputFiles()).
210  *   4. Static methods for easily executing command-line modules
211  *      (various overloads of runModule()).
212  *
213  * All files created during the test are cleaned up at the end of the test.
214  *
215  * All methods can throw std::bad_alloc.
216  *
217  * \see TestFileManager
218  * \inlibraryapi
219  * \ingroup module_testutils
220  */
221 class CommandLineTestHelper
222 {
223 public:
224     /*! \brief
225      * Runs a command-line program that implements ICommandLineModule.
226      *
227      * \param[in,out] module       Module to run.
228      *     The function does not take ownership.
229      * \param[in,out] commandLine  Command line parameters to pass.
230      *     This is only modified if \p module modifies it.
231      * \returns The return value of the module.
232      * \throws  unspecified  Any exception thrown by the module.
233      */
234     static int runModuleDirect(ICommandLineModule* module, CommandLine* commandLine);
235     /*! \brief
236      * Runs a command-line program that implements
237      * ICommandLineOptionsModule.
238      *
239      * \param[in,out] module       Module to run.
240      * \param[in,out] commandLine  Command line parameters to pass.
241      *     This is only modified if \p module modifies it.
242      * \returns The return value of the module.
243      * \throws  unspecified  Any exception thrown by the module.
244      */
245     static int runModuleDirect(std::unique_ptr<ICommandLineOptionsModule> module, CommandLine* commandLine);
246     /*! \brief
247      * Runs a command-line program that implements
248      * ICommandLineOptionsModule.
249      *
250      * \param[in] factory          Factory method for the module to run.
251      * \param[in,out] commandLine  Command line parameters to pass.
252      *     This is only modified if the module modifies it.
253      * \returns The return value of the module.
254      * \throws  unspecified  Any exception thrown by the factory or the
255      *     module.
256      */
257     static int runModuleFactory(const std::function<std::unique_ptr<ICommandLineOptionsModule>()>& factory,
258                                 CommandLine* commandLine);
259
260     /*! \brief
261      * Initializes an instance.
262      *
263      * \param  fileManager  File manager to use for generating temporary
264      *     file names and to track temporary files.
265      */
266     explicit CommandLineTestHelper(TestFileManager* fileManager);
267     ~CommandLineTestHelper();
268
269     /*! \brief
270      * Generates and sets an input file.
271      *
272      * \param[in,out] args      CommandLine to which to add the option.
273      * \param[in]     option    Option to set.
274      * \param[in]     extension Extension for the file to create.
275      * \param[in]     contents  Text to write to the input file.
276      *
277      * Creates a temporary file with contents from \p contents, and adds
278      * \p option to \p args with a value that points to the generated file.
279      */
280     void setInputFileContents(CommandLine*       args,
281                               const char*        option,
282                               const char*        extension,
283                               const std::string& contents);
284     /*! \brief
285      * Generates and sets an input file.
286      *
287      * \param[in,out] args      CommandLine to which to add the option.
288      * \param[in]     option    Option to set.
289      * \param[in]     extension Extension for the file to create.
290      * \param[in]     contents  Text to write to the input file.
291      *
292      * Creates a temporary file with contents from \p contents (each array
293      * entry on its own line), and adds \p option to \p args with a value
294      * that points to the generated file.
295      */
296     void setInputFileContents(CommandLine*                       args,
297                               const char*                        option,
298                               const char*                        extension,
299                               const ArrayRef<const char* const>& contents);
300     /*! \brief
301      * Sets an output file parameter and adds it to the set of tested files.
302      *
303      * \param[in,out] args      CommandLine to which to add the option.
304      * \param[in]     option    Option to set.
305      * \param[in]     filename  Name of the output file.
306      * \param[in]     matcher   Specifies how the contents of the file are
307      *     tested.
308      *
309      * This method does the following:
310      *  - Adds \p option to \p args to point a temporary file name
311      *    constructed from \p filename.
312      *  - Makes checkOutputFiles() to check the contents of the file
313      *    against reference data, using \p matcher.
314      *  - Marks the temporary file for removal at test teardown.
315      *
316      * \p filename is given to TestTemporaryFileManager to make a unique
317      * filename for the temporary file.
318      * If \p filename starts with a dot, a unique number is prefixed (such
319      * that it is possible to create multiple files with the same extension
320      * by just specifying the extension for every call of setOutputFile()).
321      *
322      * If the output file is needed to trigger some computation, or is
323      * unconditionally produced by the code under test, but the contents
324      * are not interesting for the test, use NoContentsMatch as the matcher.
325      * Note that the existence of the output file is still verified.
326      */
327     void setOutputFile(CommandLine*                     args,
328                        const char*                      option,
329                        const char*                      filename,
330                        const ITextBlockMatcherSettings& matcher);
331     //! \copydoc setOutputFile(CommandLine *, const char *, const char *, const ITextBlockMatcherSettings &)
332     void setOutputFile(CommandLine*                args,
333                        const char*                 option,
334                        const char*                 filename,
335                        const IFileMatcherSettings& matcher);
336     /*! \brief As for \c setOutputFile() but does not create an option
337      *
338      * This method is useful when a tool generates a series of output
339      * files by modifying a common base name. Call this method with
340      * every file name that is expected to be generated by the tool. */
341     void setOutputFileWithGeneratedName(const char* filename, const ITextBlockMatcherSettings& matcher);
342     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
343     void setOutputFileWithGeneratedName(std::string&& filename, const ITextBlockMatcherSettings& matcher);
344     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
345     void setOutputFileWithGeneratedName(const char* filename, const IFileMatcherSettings& matcher);
346     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
347     void setOutputFileWithGeneratedName(std::string&& filename, const IFileMatcherSettings& matcher);
348
349     /*! \brief
350      * Checks output files added with setOutputFile() against reference
351      * data.
352      *
353      * \param     checker  Reference data root location where the reference
354      *     data is stored.
355      *
356      * The file contents are tested verbatim, using direct string
357      * comparison.  The text can be found verbatim in the reference data
358      * XML files for manual inspection.
359      *
360      * Generates non-fatal test failures if some output file contents do
361      * not match the reference data.
362      */
363     void checkOutputFiles(TestReferenceChecker checker) const;
364
365 private:
366     class Impl;
367
368     std::unique_ptr<Impl> impl_;
369 };
370
371 /*! \libinternal \brief
372  * Test fixture for tests that call a single command-line program with
373  * input/output files.
374  *
375  * This class provides a convenient package for using CommandLineTestHelper in
376  * a test that do not need special customization.  It takes care of creating
377  * the other necessary objects (like TestFileManager, TestReferenceData, and
378  * CommandLine) and wrapping the methods from CommandLineTestHelper such that
379  * extra parameters are not needed.  Additionally, it provides setInputFile()
380  * as a convenience function for adding a fixed input file, pointing to a file
381  * that resides in the source tree.
382  *
383  * \see CommandLineTestHelper
384  * \inlibraryapi
385  * \ingroup module_testutils
386  */
387 class CommandLineTestBase : public ::testing::Test
388 {
389 public:
390     CommandLineTestBase();
391     ~CommandLineTestBase() override;
392
393     /*! \brief
394      * Sets an input file.
395      *
396      * \param[in]     option    Option to set.
397      * \param[in]     filename  Name of the input file.
398      *
399      * \see TestFileManager::getInputFilePath()
400      */
401     void setInputFile(const char* option, const char* filename);
402     //! \copydoc setInputFile(const char *, const char *);
403     void setInputFile(const char* option, const std::string& filename);
404     /*! \brief
405      * Sets an input file that may be modified. The file is copied to a
406      * temporary file, which is used as the test input
407      *
408      * \param[in]     option    Option to set.
409      * \param[in]     filename  Name of the input file.
410      *
411      */
412     void setModifiableInputFile(const char* option, const char* filename);
413     //! \copydoc setModifiableInputFile(const char *, const char *);
414     void setModifiableInputFile(const char* option, const std::string& filename);
415     /*! \brief
416      * Generates and sets an input file.
417      *
418      * \see CommandLineTestHelper::setInputFileContents()
419      */
420     void setInputFileContents(const char* option, const char* extension, const std::string& contents);
421     /*! \brief
422      * Generates and sets an input file.
423      *
424      * \see CommandLineTestHelper::setInputFileContents()
425      */
426     void setInputFileContents(const char*                        option,
427                               const char*                        extension,
428                               const ArrayRef<const char* const>& contents);
429     /*! \brief
430      * Sets an output file whose name is passed via an option and adds it to the set of tested files.
431      *
432      * \see CommandLineTestHelper::setOutputFile()
433      */
434     void setOutputFile(const char* option, const char* filename, const ITextBlockMatcherSettings& matcher);
435     //! \copydoc setOutputFile(const char *, const ITextBlockMatcherSettings &)
436     void setOutputFile(const char* option, const char* filename, const IFileMatcherSettings& matcher);
437     /*! \brief
438      * Sets an output file whose name is generated by the tool and adds it to the set of tested files.
439      *
440      * This method is useful when a tool generates a series of output
441      * files by modifying a common base name. Call this method with
442      * every file name that is expected to be generated by the tool.
443      *
444      * \see CommandLineTestHelper::setOutputFileWithGeneratedName() */
445     void setOutputFileWithGeneratedName(const char* filename, const ITextBlockMatcherSettings& matcher);
446     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
447     void setOutputFileWithGeneratedName(std::string&& filename, const ITextBlockMatcherSettings& matcher);
448     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
449     void setOutputFileWithGeneratedName(const char* filename, const IFileMatcherSettings& matcher);
450     //! \copydoc setOutputFileWithGeneratedName(const char *, const ITextBlockMatcherSettings &)
451     void setOutputFileWithGeneratedName(std::string&& filename, const IFileMatcherSettings& matcher);
452     /*! \brief
453      * Sets a file parameter that is used for input and modified as output. The input file
454      * is copied to a temporary file that is used as input and can be modified.
455      */
456     void setInputAndOutputFile(const char*                      option,
457                                const char*                      filename,
458                                const ITextBlockMatcherSettings& matcher);
459     //! \copydoc setInputAndOutputFile(const char *, const char *, const ITextBlockMatcherSettings&);
460     void setInputAndOutputFile(const char* option, const char* filename, const IFileMatcherSettings& matcher);
461
462     /*! \brief
463      * Returns the internal CommandLine object used to construct the
464      * command line for the test.
465      *
466      * Derived test fixtures can use this to add additional options, and
467      * to access the final command line to do the actual call that is being
468      * tested.
469      *
470      * Does not throw.
471      */
472     CommandLine& commandLine();
473     /*! \brief
474      * Returns the internal TestFileManager object used to manage the
475      * files.
476      *
477      * Derived test fixtures can use this to manage files in cases the
478      * canned methods are not sufficient.
479      *
480      * Does not throw.
481      */
482     TestFileManager& fileManager();
483     /*! \brief
484      * Returns the root reference data checker.
485      *
486      * Derived test fixtures can use this to check other things than output
487      * file contents.
488      */
489     TestReferenceChecker rootChecker();
490     /*! \brief
491      * Sets the tolerance for floating-point comparisons.
492      *
493      * All following floating-point comparisons using the checker will use
494      * the new tolerance.
495      *
496      * Does not throw.
497      */
498     void setDefaultTolerance(const FloatingPointTolerance& tolerance);
499     /*! \brief
500      * Checks the output of writeHelp() against reference data.
501      */
502     void testWriteHelp(ICommandLineModule* module);
503     /*! \brief
504      * Checks output files added with setOutputFile() against reference
505      * data.
506      *
507      * \see CommandLineTestHelper::checkOutputFiles()
508      */
509     void checkOutputFiles();
510
511 private:
512     class Impl;
513
514     std::unique_ptr<Impl> impl_;
515 };
516
517 } // namespace test
518 } // namespace gmx
519
520 #endif