Improve AbstractAnalysisData data access interface.
[alexxy/gromacs.git] / src / gromacs / analysisdata / tests / analysisdata.cpp
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 /*! \internal \file
32  * \brief
33  * Tests for analysis data functionality.
34  *
35  * These tests check the functionality of gmx::AnalysisData, as well as its
36  * base classes gmx::AbstractAnalysisData and gmx::AbstractAnalysisDataStored.
37  * Most checking is done using gmx::test::AnalysisDataTestFixture and mock
38  * modules that implement gmx::AnalysisDataModuleInterface.
39  *
40  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
41  * \ingroup module_analysisdata
42  */
43 #include <memory>
44
45 #include <gmock/gmock.h>
46 #include <gtest/gtest.h>
47
48 #include "gromacs/analysisdata/analysisdata.h"
49 #include "gromacs/fatalerror/exceptions.h"
50
51 #include "datatest.h"
52 #include "mock_module.h"
53
54 using gmx::test::MockAnalysisModule;
55
56 namespace
57 {
58
59 /********************************************************************
60  * Tests for gmx::AnalysisData.
61  */
62
63 /*
64  * Tests that simple initialization works.
65  */
66 TEST(AnalysisDataInitializationTest, BasicInitialization)
67 {
68     gmx::AnalysisData data;
69     EXPECT_EQ(0, data.columnCount());
70     EXPECT_FALSE(data.isMultipoint());
71     EXPECT_EQ(0, data.frameCount());
72
73     data.setColumns(1);
74     EXPECT_EQ(1, data.columnCount());
75     EXPECT_FALSE(data.isMultipoint());
76
77     data.setColumns(3, true);
78     EXPECT_EQ(3, data.columnCount());
79     EXPECT_TRUE(data.isMultipoint());
80
81     data.setColumns(1);
82     EXPECT_EQ(1, data.columnCount());
83     EXPECT_FALSE(data.isMultipoint());
84 }
85
86 /*
87  * Tests that checking for compatibility of modules with multicolumn data
88  * works.
89  */
90 TEST(AnalysisDataInitializationTest, ChecksMultiColumnModules)
91 {
92     gmx::AnalysisData data;
93     data.setColumns(2);
94
95     std::auto_ptr<MockAnalysisModule> mod(new MockAnalysisModule(0));
96     EXPECT_THROW(data.addModule(mod.release()), gmx::APIError);
97
98     mod.reset(new MockAnalysisModule(gmx::AnalysisDataModuleInterface::efAllowMulticolumn));
99     EXPECT_NO_THROW(data.addModule(mod.release()));
100 }
101
102 /*
103  * Tests that checking for compatibility of modules with multipoint data
104  * works.
105  */
106 TEST(AnalysisDataInitializationTest, ChecksMultiPointModules)
107 {
108     gmx::AnalysisData data;
109     data.setColumns(1, true);
110
111     std::auto_ptr<MockAnalysisModule> mod(new MockAnalysisModule(0));
112     EXPECT_THROW(data.addModule(mod.release()), gmx::APIError);
113
114     mod.reset(new MockAnalysisModule(gmx::AnalysisDataModuleInterface::efAllowMultipoint));
115     EXPECT_NO_THROW(data.addModule(mod.release()));
116 }
117
118
119 typedef gmx::test::AnalysisDataTestFixture AnalysisDataTest;
120
121 // Input data for the tests below.
122 using gmx::test::END_OF_DATA;
123 using gmx::test::END_OF_FRAME;
124 using gmx::test::MPSTOP;
125 static const real inputdata[] = {
126     1.0,  0.0, 1.0, 2.0, END_OF_FRAME,
127     2.0,  1.0, 1.0, 1.0, END_OF_FRAME,
128     3.0,  2.0, 0.0, 0.0, END_OF_FRAME,
129     END_OF_DATA
130 };
131
132 /*
133  * Tests that data is forwarded correctly to modules using two independent
134  * modules.
135  */
136 TEST_F(AnalysisDataTest, CallsModuleCorrectly)
137 {
138     gmx::test::AnalysisDataTestInput input(inputdata);
139     gmx::AnalysisData data;
140     data.setColumns(input.columnCount());
141
142     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
143     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
144     ASSERT_NO_THROW(presentAllData(input, &data));
145 }
146
147 /*
148  * Tests that data is forwarded correctly to modules that are added using
149  * addColumnModule().
150  * Uses two independent modules.
151  */
152 TEST_F(AnalysisDataTest, CallsColumnModuleCorrectly)
153 {
154     gmx::test::AnalysisDataTestInput input(inputdata);
155     gmx::AnalysisData data;
156     data.setColumns(input.columnCount());
157
158     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 0, 2, &data));
159     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 2, 1, &data));
160     ASSERT_NO_THROW(presentAllData(input, &data));
161 }
162
163 /*
164  * Tests that data is forwarded correctly to modules when the data is added as
165  * individual points and not as full frames.
166  */
167 TEST_F(AnalysisDataTest, CallsModuleCorrectlyWithIndividualPoints)
168 {
169     gmx::test::AnalysisDataTestInput input(inputdata);
170     gmx::AnalysisData data;
171     data.setColumns(input.columnCount());
172
173     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
174     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 1, 2, &data));
175     gmx::AnalysisDataHandle *handle = NULL;
176     ASSERT_NO_THROW(handle = data.startData(NULL));
177     for (int row = 0; row < input.frameCount(); ++row)
178     {
179         const gmx::test::AnalysisDataTestInputFrame &frame = input.frame(row);
180         const gmx::test::AnalysisDataTestInputPointSet &points = frame.points();
181         ASSERT_NO_THROW(handle->startFrame(row, frame.x(), frame.dx()));
182         for (int column = 0; column < input.columnCount(); ++column)
183         {
184             ASSERT_NO_THROW(handle->addPoint(column, points.y(column)));
185         }
186         ASSERT_NO_THROW(handle->finishFrame());
187         EXPECT_EQ(row + 1, data.frameCount());
188     }
189     ASSERT_NO_THROW(handle->finishData());
190 }
191
192 /*
193  * Tests that data is forwarded correctly (in frame order) to modules when the
194  * data is added through multiple handles in non-increasing order.
195  */
196 TEST_F(AnalysisDataTest, CallsModuleCorrectlyWithOutOfOrderFrames)
197 {
198     gmx::test::AnalysisDataTestInput input(inputdata);
199     gmx::AnalysisData data;
200     data.setColumns(input.columnCount());
201
202     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
203     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 1, 2, &data));
204     gmx::AnalysisDataHandle *handle1 = NULL;
205     gmx::AnalysisDataHandle *handle2 = NULL;
206     ASSERT_NO_THROW(handle1 = data.startData(NULL));
207     ASSERT_NO_THROW(handle2 = data.startData(NULL));
208     ASSERT_NO_THROW(presentDataFrame(input, 1, handle1));
209     ASSERT_NO_THROW(presentDataFrame(input, 0, handle2));
210     ASSERT_NO_THROW(presentDataFrame(input, 2, handle1));
211     ASSERT_NO_THROW(handle1->finishData());
212     ASSERT_NO_THROW(handle2->finishData());
213 }
214
215 /*
216  * Tests that data can be accessed correctly from a module that requests
217  * storage using AbstractAnalysisData::requestStorage() with parameter -1.
218  */
219 TEST_F(AnalysisDataTest, FullStorageWorks)
220 {
221     gmx::test::AnalysisDataTestInput input(inputdata);
222     gmx::AnalysisData data;
223     data.setColumns(input.columnCount());
224
225     ASSERT_NO_THROW(addStaticStorageCheckerModule(input, -1, &data));
226     ASSERT_NO_THROW(presentAllData(input, &data));
227 }
228
229 /*
230  * Tests that a data module can be added to an AnalysisData object after data
231  * has been added if all data is still available in storage.
232  */
233 TEST_F(AnalysisDataTest, CanAddModuleAfterStoredData)
234 {
235     gmx::test::AnalysisDataTestInput input(inputdata);
236     gmx::AnalysisData data;
237     data.setColumns(input.columnCount());
238     ASSERT_TRUE(data.requestStorage(-1));
239
240     ASSERT_NO_THROW(presentAllData(input, &data));
241     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
242 }
243
244 /*
245  * Tests that data can be accessed correctly from a module that requests
246  * storage using AbstractAnalysisData::requestStorage() only for one frame.
247  */
248 TEST_F(AnalysisDataTest, LimitedStorageWorks)
249 {
250     gmx::test::AnalysisDataTestInput input(inputdata);
251     gmx::AnalysisData data;
252     data.setColumns(input.columnCount());
253
254     ASSERT_NO_THROW(addStaticStorageCheckerModule(input, 1, &data));
255     ASSERT_NO_THROW(presentAllData(input, &data));
256 }
257
258 // Input data for the tests below.
259 static const real multipointinputdata[] = {
260     1.0,  0.0, 1.0, 2.0, MPSTOP, 1.1, 2.1, 1.1, MPSTOP, 2.2, 1.2, 0.2, END_OF_FRAME,
261     2.0,  1.0, 1.0, 1.0, MPSTOP, 2.1, 1.1, 0.1, MPSTOP, 1.2, 0.2, 1.2, END_OF_FRAME,
262     3.0,  2.0, 0.0, 0.0, MPSTOP, 3.1, 2.1, 1.1, MPSTOP, 0.2, 2.2, 1.2, END_OF_FRAME,
263     END_OF_DATA
264 };
265
266 /*
267  * Tests that multipoint data is forwarded correctly to modules using two
268  * independent modules.
269  */
270 TEST_F(AnalysisDataTest, MultipointCallsModuleCorrectly)
271 {
272     gmx::test::AnalysisDataTestInput input(multipointinputdata);
273     gmx::AnalysisData data;
274     data.setColumns(input.columnCount(), true);
275
276     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
277     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
278     ASSERT_NO_THROW(presentAllData(input, &data));
279 }
280
281 /*
282  * Tests that multipoint data is forwarded correctly to modules that are added
283  * using addColumnModule().
284  * Uses two independent modules.
285  */
286 TEST_F(AnalysisDataTest, MultipointCallsColumnModuleCorrectly)
287 {
288     gmx::test::AnalysisDataTestInput input(multipointinputdata);
289     gmx::AnalysisData data;
290     data.setColumns(input.columnCount(), true);
291
292     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 0, 2, &data));
293     ASSERT_NO_THROW(addStaticColumnCheckerModule(input, 2, 1, &data));
294     ASSERT_NO_THROW(presentAllData(input, &data));
295 }
296
297 } // namespace