Added some more analysisdata unit tests.
[alexxy/gromacs.git] / src / gromacs / analysisdata / tests / datatest.h
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \libinternal \file
32  * \brief
33  * Helper classes for testing classes that derive from AbstractAnalysisData.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \inlibraryapi
37  * \ingroup module_analysisdata
38  */
39 #ifndef GMX_ANALYSISDATA_TESTS_DATATEST_H
40 #define GMX_ANALYSISDATA_TESTS_DATATEST_H
41
42 #include <limits>
43 #include <vector>
44
45 #include <gtest/gtest.h>
46
47 #include "gromacs/legacyheaders/types/simple.h"
48 #include "gromacs/fatalerror/gmxassert.h"
49
50 #include "testutils/refdata.h"
51
52 namespace gmx
53 {
54
55 class AbstractAnalysisData;
56 class AnalysisData;
57 class AnalysisDataHandle;
58
59 namespace test
60 {
61
62 class MockAnalysisModule;
63
64 //! Constant to use to signify end of data for AnalysisDataTestInput.
65 const real END_OF_DATA = std::numeric_limits<real>::max();
66 //! Constant to use to signify end of one data frame for AnalysisDataTestInput.
67 const real END_OF_FRAME = std::numeric_limits<real>::min();
68 //! Constant to use to signify end of one multipoint set for AnalysisDataTestInput.
69 const real MPSTOP = -std::numeric_limits<real>::max();
70
71 /*! \libinternal \brief
72  * Represents a single set of points in AnalysisDataTestInputFrame structure.
73  *
74  * If the data is not multipoint, each frame contains exactly one set of
75  * points.  If there is more than one set of points, each of these sets is
76  * passed separately to AnalysisDataHandle::addPoints().
77  *
78  * \ingroup module_analysisdata
79  */
80 class AnalysisDataTestInputPointSet
81 {
82     public:
83         AnalysisDataTestInputPointSet();
84
85         int size() const { return y_.size(); }
86         real y(int i) const { return y_[i]; }
87         const std::vector<real> &yvector() const { return y_; }
88         const real *yptr() const { return &y_[0]; }
89         const real *dyptr() const { return NULL; }
90         const bool *presentptr() const { return NULL; }
91
92     private:
93         std::vector<real>       y_;
94
95         friend class AnalysisDataTestInput;
96 };
97
98 /*! \libinternal \brief
99  * Represents a single frame in AnalysisDataTestInput structure.
100  *
101  * \ingroup module_analysisdata
102  */
103 class AnalysisDataTestInputFrame
104 {
105     public:
106         AnalysisDataTestInputFrame();
107
108         bool isMultipoint() const { return points_.size() > 1; }
109
110         int index() const { return index_; }
111         real x() const { return x_; }
112         real dx() const { return 0.0; }
113
114         int pointSetCount() const { return points_.size(); }
115         const AnalysisDataTestInputPointSet &points(int index = 0) const
116         {
117             GMX_ASSERT(index >= 0 && static_cast<size_t>(index) < points_.size(),
118                        "Point set index out of range");
119             return points_[index];
120         }
121
122     private:
123         int                     index_;
124         real                    x_;
125         std::vector<AnalysisDataTestInputPointSet>  points_;
126
127         friend class AnalysisDataTestInput;
128 };
129
130 /*! \libinternal \brief
131  * Represents static input data for AbstractAnalysisData tests.
132  *
133  * Used to construct structured test input data from a static array of reals,
134  * and then typically used as input to methods in AnalysisDataTestFixture.
135  *
136  * \see AnalysisDataTestFixture
137  *
138  * \ingroup module_analysisdata
139  */
140 class AnalysisDataTestInput
141 {
142     public:
143         /*! \brief
144          * Constructs data representation from a simple array.
145          *
146          * \param[in] data  Array to construct data from.
147          *
148          * The input array should consist of a set of frames, separated by a
149          * END_OF_FRAME marker.  The first value for a frame is the X value,
150          * all following values are Y values.
151          * For multipoint data, one frame can contain several point sets,
152          * separated by MPSTOP markers.  There should be no MPSTOP marker after
153          * the last point set, only an END_OF_FRAME marker.  All point sets are
154          * assumed to start from column zero, but the sets may contain
155          * different number of columns.  For non-multipoint data, all frames
156          * must containt the same number of columns.
157          * The final element in the array (after the last END_OF_FRAME) should
158          * be END_OF_DATA.
159          */
160         explicit AnalysisDataTestInput(const real *data);
161         ~AnalysisDataTestInput();
162
163         int frameCount() const { return frames_.size(); }
164         int columnCount() const { return columnCount_; }
165         bool isMultipoint() const { return bMultipoint_; }
166         const AnalysisDataTestInputFrame &frame(int index) const;
167
168     private:
169         int                     columnCount_;
170         bool                    bMultipoint_;
171         std::vector<AnalysisDataTestInputFrame> frames_;
172 };
173
174 /*! \libinternal \brief
175  * Test fixture for AbstractAnalysisData testing.
176  *
177  * This test fixture is designed to help writing tests for objects that
178  * derive from the AbstractAnalysisData class.  Typical flow in such tests is
179  * that first the test creates the required data objects, then call static
180  * methods in this class to add mock modules (using
181  * AbstractAnalysisData::addModule()) to the data objects to check that they
182  * produce the correct data, and then invokes methods in the data object to
183  * produce the data to be checked.  Static methods are also provided for
184  * pushing data from an AnalysisDataTestInput object to some generic types
185  * derived from AbstractAnalysisData.
186  *
187  * Methods addStaticCheckerModule(), addStaticColumnCheckerModule() and
188  * addStaticStorageCheckerModule() create and add mock modules that check the
189  * data against a given AnalysisDataTestInput instance.
190  *
191  * Method addReferenceCheckerModule() creates and adds a mock module that
192  * checks the output against reference data produced by a previous test
193  * execution (see TestReferenceData).  Two versions are provided, a static
194  * method to be used with any TestReferenceChecker, and a non-static method
195  * that uses the protected \p data_ member.
196  *
197  * presentAllData() and presentDataFrame() are provided to push data from an
198  * AnalysisDataTestInput into an AnalysisData object.  In typical tests, most
199  * checks are done during the these methods, by the added mock modules.
200  *
201  * \todo
202  * Support for errors and for arbitrary multipoint data.
203  *
204  * \see AnalysisDataTestInput
205  *
206  * \ingroup module_analysisdata
207  */
208 class AnalysisDataTestFixture : public ::testing::Test
209 {
210     public:
211         AnalysisDataTestFixture();
212
213         /*! \brief
214          * Adds all data from AnalysisDataTestInput into an AnalysisData.
215          */
216         static void presentAllData(const AnalysisDataTestInput &input,
217                                    AnalysisData *data);
218         /*! \brief
219          * Adds a single frame from AnalysisDataTestInput into an AnalysisData.
220          */
221         static void presentDataFrame(const AnalysisDataTestInput &input, int row,
222                                      AnalysisDataHandle *handle);
223
224         /*! \brief
225          * Adds a mock module that verifies output against
226          * AnalysisDataTestInput.
227          *
228          * \param[in]  data     Data to compare against.
229          * \param      source   Data object to verify.
230          *
231          * Creates a mock module that verifies that the
232          * AnalysisDataModuleInterface methods are called correctly by
233          * \p source.  Parameters for the calls are verified against \p data.
234          * Adds the created module to \p source using \p data->addModule().
235          * Any exceptions from the called functions should be caught by the
236          * caller.
237          *
238          * \see AbstractAnalysisData::addModule()
239          */
240         static void addStaticCheckerModule(const AnalysisDataTestInput &data,
241                                            AbstractAnalysisData *source);
242         /*! \brief
243          * Adds a column mock module that verifies output against
244          * AnalysisDataTestInput.
245          *
246          * \param[in]  data     Data to compare against.
247          * \param[in]  firstcol First column to check.
248          * \param[in]  n        Number of columns to check.
249          * \param      source   Data object to verify.
250          *
251          * Creates a mock module that verifies that the
252          * AnalysisDataModuleInterface methods are called correctly by
253          * \p source.  Parameters for the calls are verified against \p data.
254          * Adds the created module to \p source using
255          * \p data->addColumnModule().
256          * Any exceptions from the called functions should be caught by the
257          * caller.
258          *
259          * \see AbstractAnalysisData::addColumnModule()
260          */
261         static void addStaticColumnCheckerModule(const AnalysisDataTestInput &data,
262                                                  int firstcol, int n,
263                                                  AbstractAnalysisData *source);
264         /*! \brief
265          * Adds a mock module that verifies output and storage against
266          * AnalysisDataTestInput.
267          *
268          * \param[in]  data     Data to compare against.
269          * \param[in]  storageCount  Number of previous frames to check
270          *                      (-1 = all).
271          * \param      source   Data object to verify.
272          *
273          * Works like addStaticCheckerModule(), except that in addition, for
274          * each frame, the mock module also checks that previous frames can be
275          * accessed using AbstractAnalysisData::getDataWErr().  In the
276          * AnalysisDataModuleInterface::dataStarted() callback, the mock module
277          * calls AbstractAnalysisData::requestStorage() with \p storageCount as
278          * the parameter.
279          */
280         static void addStaticStorageCheckerModule(const AnalysisDataTestInput &data,
281                                                   int storageCount,
282                                                   AbstractAnalysisData *source);
283         /*! \brief
284          * Adds a mock module that verifies output against reference data.
285          *
286          * \param[in]  checker  Reference data checker to use for comparison.
287          * \param      source   Data object to verify.
288          *
289          * Creates a mock module that verifies that the
290          * AnalysisDataModuleInterface methods are called correctly by
291          * \p source.  Parameters for the calls are verified against reference
292          * data using \p checker.
293          * Adds the created module to \p source using \p data->addModule().
294          * Any exceptions from the called functions should be caught by the
295          * caller.
296          *
297          * \see TestReferenceData
298          */
299         static void addReferenceCheckerModule(const TestReferenceChecker &checker,
300                                               AbstractAnalysisData *source);
301
302         /*! \brief
303          * Adds a mock module that verifies output against reference data.
304          *
305          * \param[in]  id       Identifier for reference data compound to use.
306          * \param      source   Data object to verify.
307          *
308          * Creates a reference checker module using a compound checker with id
309          * \p id at the root level of \p data_.
310          *
311          * See the static overload for other details.
312          */
313         void addReferenceCheckerModule(const char *id,
314                                        AbstractAnalysisData *source);
315
316     protected:
317         gmx::test::TestReferenceData  data_;
318 };
319
320 } // namespace test
321
322 } // namespace gmx
323
324 #endif