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