Code for checking xvg files in testutils.
[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,2015, 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 ICommandLineModule;
59 class ICommandLineOptionsModule;
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 ICommandLineModule.
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(ICommandLineModule *module, CommandLine *commandLine);
220         /*! \brief
221          * Runs a command-line program that implements
222          * ICommandLineOptionsModule.
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(ICommandLineOptionsModule         *(*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          */
291         void setOutputFile(CommandLine *args, const char *option,
292                            const char *filename);
293         /*! \brief
294          * Sets an output file parameter.
295          *
296          * \param[in,out] args      CommandLine to which to add the option.
297          * \param[in]     option    Option to set.
298          * \param[in]     extension Extension for the file to create.
299          *
300          * This method:
301          *  - Adds \p option to \p args to point to a temporary file name with
302          *    extension \p extension.
303          *  - Marks the temporary file for removal at test teardown.
304          *
305          * This method provides the mechanism to set output files that are
306          * required to trigger computation of values that are required for
307          * the test.  The contents of the output file are not tested.
308          *
309          * Another use case is to mark files that are unconditionally produced
310          * by the code under test, but do not need to be tested.  This method
311          * makes the test code aware of those files such that it can remove
312          * them at the end of the test.
313          */
314         void setOutputFileNoTest(CommandLine *args, const char *option,
315                                  const char *extension);
316
317         /*! \brief
318          * Checks output files added with setOutputFile() against reference
319          * data.
320          *
321          * \param     checker  Reference data root location where the reference
322          *     data is stored.
323          *
324          * The file contents are tested verbatim, using direct string
325          * comparison.  The text can be found verbatim in the reference data
326          * XML files for manual inspection.
327          *
328          * Generates non-fatal test failures if some output file contents do
329          * not match the reference data.
330          */
331         void checkOutputFiles(TestReferenceChecker checker) const;
332
333     private:
334         class Impl;
335
336         PrivateImplPointer<Impl> impl_;
337 };
338
339 /*! \libinternal \brief
340  * Test fixture for tests that call a single command-line program with
341  * input/output files.
342  *
343  * This class provides a convenient package for using CommandLineTestHelper in
344  * a test that do not need special customization.  It takes care of creating
345  * the other necessary objects (like TestFileManager, TestReferenceData, and
346  * CommandLine) and wrapping the methods from CommandLineTestHelper such that
347  * extra parameters are not needed.  Additionally, it provides setInputFile()
348  * as a convenience function for adding a fixed input file, pointing to a file
349  * that resides in the source tree.
350  *
351  * \see CommandLineTestHelper
352  * \inlibraryapi
353  * \ingroup module_testutils
354  */
355 class CommandLineTestBase : public ::testing::Test
356 {
357     public:
358         CommandLineTestBase();
359         ~CommandLineTestBase();
360
361         /*! \brief
362          * Sets an input file.
363          *
364          * \param[in]     option    Option to set.
365          * \param[in]     filename  Name of the input file.
366          *
367          * \see TestFileManager::getInputFilePath()
368          */
369         void setInputFile(const char *option, const char *filename);
370         /*! \brief
371          * Generates and sets an input file.
372          *
373          * \see CommandLineTestHelper::setInputFileContents()
374          */
375         void setInputFileContents(const char        *option,
376                                   const char        *extension,
377                                   const std::string &contents);
378         /*! \brief
379          * Generates and sets an input file.
380          *
381          * \see CommandLineTestHelper::setInputFileContents()
382          */
383         void setInputFileContents(const char                        *option,
384                                   const char                        *extension,
385                                   const ConstArrayRef<const char *> &contents);
386         /*! \brief
387          * Sets an output file parameter and adds it to the set of tested files.
388          *
389          * \see CommandLineTestHelper::setOutputFile()
390          */
391         void setOutputFile(const char *option, const char *filename);
392         /*! \brief
393          * Sets an output file parameter.
394          *
395          * \see CommandLineTestHelper::setOutputFileNoTest()
396          */
397         void setOutputFileNoTest(const char *option, const char *extension);
398
399         /*! \brief
400          * Returns the internal CommandLine object used to construct the
401          * command line for the test.
402          *
403          * Derived test fixtures can use this to add additional options, and
404          * to access the final command line to do the actual call that is being
405          * tested.
406          *
407          * Does not throw.
408          */
409         CommandLine &commandLine();
410         /*! \brief
411          * Returns the internal TestFileManager object used to manage the
412          * files.
413          *
414          * Derived test fixtures can use this to manage files in cases the
415          * canned methods are not sufficient.
416          *
417          * Does not throw.
418          */
419         TestFileManager &fileManager();
420         /*! \brief
421          * Returns the root reference data checker.
422          *
423          * Derived test fixtures can use this to check other things than output
424          * file contents.
425          */
426         TestReferenceChecker rootChecker();
427
428         /*! \brief
429          * Checks output files added with setOutputFile() against reference
430          * data.
431          *
432          * \see CommandLineTestHelper::checkOutputFiles()
433          */
434         void checkOutputFiles();
435
436     private:
437         class Impl;
438
439         PrivateImplPointer<Impl> impl_;
440 };
441
442 } // namespace test
443 } // namespace gmx
444
445 #endif