e99f5e893546eb81c7c96ad21596e5743bd673b3
[alexxy/gromacs.git] / src / gromacs / analysisdata / tests / mock_datamodule.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team.
5  * Copyright (c) 2017,2019,2020, 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 /*! \internal \file
37  * \brief
38  * Implements classes in mock_datamodule.h.
39  *
40  * \author Teemu Murtola <teemu.murtola@gmail.com>
41  * \ingroup module_analysisdata
42  */
43 #include "gmxpre.h"
44
45 #include "mock_datamodule.h"
46
47 #include <gmock/gmock.h>
48 #include <gtest/gtest.h>
49
50 #include "gromacs/analysisdata/analysisdata.h"
51 #include "gromacs/analysisdata/dataframe.h"
52 #include "gromacs/utility/gmxassert.h"
53 #include "gromacs/utility/stringutil.h"
54
55 #include "gromacs/analysisdata/tests/datatest.h"
56 #include "testutils/refdata.h"
57 #include "testutils/testasserts.h"
58
59 namespace gmx
60 {
61 namespace test
62 {
63
64 /********************************************************************
65  * MockAnalysisDataModule::Impl
66  */
67
68 /*! \internal \brief
69  * Private implementation class for gmx::test::MockAnalysisDataModule.
70  *
71  * \ingroup module_analysisdata
72  */
73 class MockAnalysisDataModule::Impl
74 {
75 public:
76     //! Initializes a mock object with the given flags.
77     explicit Impl(int flags);
78
79     /*! \brief
80      * Callback used to initialize reference data checks
81      *
82      * Called in response to dataStarted().
83      * Records the source data for later use (for access to data properties).
84      */
85     void startReferenceData(AbstractAnalysisData* data);
86     /*! \brief
87      * Callback used to check frame start against reference data.
88      *
89      * Called to check parameters and order of calls to frameStarted().
90      * In addition to reference data checks, this method checks statically
91      * that the new frame matches \a frameIndex_.
92      */
93     void startReferenceFrame(const AnalysisDataFrameHeader& header);
94     /*! \brief
95      * Callback used to check frame points against reference data.
96      *
97      * Called to check parameters and order of calls to pointsAdded().
98      */
99     void checkReferencePoints(const AnalysisDataPointSetRef& points);
100     /*! \brief
101      * Callback used to check frame finish against reference data.
102      *
103      * Called to check parameters and order of calls to frameFinished().
104      */
105     void finishReferenceFrame(const AnalysisDataFrameHeader& header);
106     /*! \brief
107      * Callback used to check serial frame finish with reference data.
108      *
109      * Called to check parameters and order of calls to
110      * frameFinishedSerial().
111      * \a frameIndex_ is incremented here.
112      */
113     void finishReferenceFrameSerial(int frameIndex);
114
115     /*! \brief
116      * Reference data checker to use for checking frames.
117      *
118      * Must be initialized if startReferenceFrame() is called.
119      */
120     TestReferenceChecker rootChecker_;
121     /*! \brief
122      * Reference data checker to use to check the current frame.
123      *
124      * Initialized between startReferenceFrame() and finishReferenceFrame()
125      * calls.
126      */
127     TestReferenceChecker frameChecker_;
128     //! Source data.
129     const AbstractAnalysisData* source_;
130     //! Flags that will be returned by the mock module.
131     int flags_;
132     //! Index of the current/next frame.
133     int frameIndex_;
134 };
135
136 namespace
137 {
138
139 /*! \internal \brief
140  * Checks a single AnalysisDataValue.
141  *
142  * \ingroup module_analysisdata
143  */
144 void checkReferenceDataPoint(TestReferenceChecker* checker, const AnalysisDataValue& value)
145 {
146     TestReferenceChecker compound(checker->checkCompound("DataValue", nullptr));
147     compound.checkReal(value.value(), "Value");
148     if (compound.checkPresent(value.hasError(), "Error"))
149     {
150         compound.checkReal(value.error(), "Error");
151     }
152     if (compound.checkPresent(!value.isPresent(), "Present"))
153     {
154         compound.checkBoolean(value.isPresent(), "Present");
155     }
156 }
157
158 } // namespace
159
160 MockAnalysisDataModule::Impl::Impl(int flags) : source_(nullptr), flags_(flags), frameIndex_(0) {}
161
162
163 void MockAnalysisDataModule::Impl::startReferenceData(AbstractAnalysisData* data)
164 {
165     source_ = data;
166 }
167
168
169 void MockAnalysisDataModule::Impl::startReferenceFrame(const AnalysisDataFrameHeader& header)
170 {
171     GMX_RELEASE_ASSERT(rootChecker_, "Root checker not set, but reference data used");
172     EXPECT_FALSE(frameChecker_.isValid());
173     EXPECT_EQ(frameIndex_, header.index());
174     frameChecker_ =
175             rootChecker_.checkCompound("DataFrame", formatString("Frame%d", frameIndex_).c_str());
176     frameChecker_.checkReal(header.x(), "X");
177 }
178
179
180 void MockAnalysisDataModule::Impl::checkReferencePoints(const AnalysisDataPointSetRef& points)
181 {
182     EXPECT_TRUE(frameChecker_.isValid());
183     if (frameChecker_)
184     {
185         TestReferenceChecker checker(frameChecker_.checkCompound("DataValues", nullptr));
186         checker.checkInteger(points.columnCount(), "Count");
187         if (checker.checkPresent(source_->dataSetCount() > 1, "DataSet"))
188         {
189             checker.checkInteger(points.dataSetIndex(), "DataSet");
190         }
191         const int sourceColumnCount = source_->columnCount(points.dataSetIndex());
192         const bool bAllColumns = (points.firstColumn() == 0 && points.columnCount() == sourceColumnCount);
193         if (checker.checkPresent(!bAllColumns, "FirstColumn"))
194         {
195             checker.checkInteger(points.firstColumn(), "FirstColumn");
196             checker.checkInteger(points.lastColumn(), "LastColumn");
197         }
198
199         AnalysisDataValuesRef::const_iterator value;
200         for (value = points.values().begin(); value != points.values().end(); ++value)
201         {
202             checkReferenceDataPoint(&checker, *value);
203         }
204     }
205 }
206
207
208 void MockAnalysisDataModule::Impl::finishReferenceFrame(const AnalysisDataFrameHeader& header)
209 {
210     EXPECT_TRUE(frameChecker_.isValid());
211     EXPECT_EQ(frameIndex_, header.index());
212     frameChecker_ = TestReferenceChecker();
213 }
214
215
216 void MockAnalysisDataModule::Impl::finishReferenceFrameSerial(int frameIndex)
217 {
218     EXPECT_FALSE(frameChecker_.isValid());
219     EXPECT_EQ(frameIndex_, frameIndex);
220     ++frameIndex_;
221 }
222
223
224 /********************************************************************
225  * MockAnalysisDataModule
226  */
227
228 namespace
229 {
230
231 /*! \brief
232  * Helper function for checking the data frame header against static data.
233  *
234  * \param[in] header    Frame header to check.
235  * \param[in] refFrame  Data to check against.
236  */
237 void checkHeader(const AnalysisDataFrameHeader& header, const AnalysisDataTestInputFrame& refFrame)
238 {
239     EXPECT_EQ(refFrame.index(), header.index());
240     EXPECT_FLOAT_EQ(refFrame.x(), header.x());
241     EXPECT_FLOAT_EQ(refFrame.dx(), header.dx());
242 }
243
244 /*! \brief
245  * Helper function for checking a point set against static data.
246  *
247  * \param[in] points       Point set to check.
248  * \param[in] refPoints    Data to check against.
249  * \param[in] columnOffset Offset of first column of \p points in \p refPoints.
250  */
251 void checkPoints(const AnalysisDataPointSetRef&       points,
252                  const AnalysisDataTestInputPointSet& refPoints,
253                  int                                  columnOffset)
254 {
255     for (int i = 0; i < points.columnCount(); ++i)
256     {
257         const int column = points.firstColumn() - refPoints.firstColumn() + i + columnOffset;
258         EXPECT_FLOAT_EQ(refPoints.y(column), points.y(i))
259                 << "  Column: " << i + 1 << " / " << points.columnCount() << " (+"
260                 << points.firstColumn() << ")\n"
261                 << "Ref. col: " << column + 1 << " / " << refPoints.size() << " (+"
262                 << refPoints.firstColumn() << ", offs " << columnOffset << ")";
263     }
264 }
265
266 /*! \brief
267  * Helper function for checking a full frame against static data.
268  *
269  * \param[in] frame     Frame to check.
270  * \param[in] refFrame  Data to check against.
271  */
272 void checkFrame(const AnalysisDataFrameRef& frame, const AnalysisDataTestInputFrame& refFrame)
273 {
274     checkHeader(frame.header(), refFrame);
275     ASSERT_EQ(refFrame.pointSetCount(), frame.pointSetCount());
276     for (int i = 0; i < frame.pointSetCount(); ++i)
277     {
278         const AnalysisDataPointSetRef&       points    = frame.pointSet(i);
279         const AnalysisDataTestInputPointSet& refPoints = refFrame.pointSet(i);
280         EXPECT_EQ(refPoints.firstColumn(), points.firstColumn());
281         checkPoints(points, refPoints, 0);
282     }
283 }
284
285 /*! \brief
286  * Functor for checking data frame header against static test input data.
287  *
288  * This functor is designed to be invoked as a handled for
289  * IAnalysisDataModule::frameStarted().
290  */
291 class StaticDataFrameHeaderChecker
292 {
293 public:
294     /*! \brief
295      * Constructs a checker against a given input data frame.
296      *
297      * \param[in] frame Frame to check against.
298      *
299      * \p frame must exist for the lifetime of this object.
300      */
301     StaticDataFrameHeaderChecker(const AnalysisDataTestInputFrame* frame) : frame_(frame) {}
302
303     //! Function call operator for the functor.
304     void operator()(const AnalysisDataFrameHeader& header) const
305     {
306         SCOPED_TRACE(formatString("Frame %d", frame_->index()));
307         checkHeader(header, *frame_);
308     }
309
310 private:
311     const AnalysisDataTestInputFrame* frame_;
312 };
313
314 /*! \brief
315  * Functor for checking data frame points against static test input data.
316  *
317  * This functor is designed to be invoked as a handled for
318  * IAnalysisDataModule::pointsAdded().
319  */
320 class StaticDataPointsChecker
321 {
322 public:
323     /*! \brief
324      * Constructs a checker against a given input data frame and point set.
325      *
326      * \param[in] frame    Frame to check against.
327      * \param[in] points   Point set in \p frame to check against.
328      * \param[in] firstcol Expected first column.
329      * \param[in] n        Expected number of columns.
330      *
331      * \p firstcol and \p n are used to create a checker that only expects
332      * to be called for a subset of columns.
333      * \p frame and \p points must exist for the lifetime of this object.
334      */
335     StaticDataPointsChecker(const AnalysisDataTestInputFrame*    frame,
336                             const AnalysisDataTestInputPointSet* points,
337                             int                                  firstcol,
338                             int                                  n) :
339         frame_(frame),
340         points_(points),
341         firstcol_(firstcol),
342         n_(n)
343     {
344     }
345
346     //! Function call operator for the functor.
347     void operator()(const AnalysisDataPointSetRef& points) const
348     {
349         SCOPED_TRACE(formatString("Frame %d, point set %d", frame_->index(), points_->index()));
350         EXPECT_EQ(points_->dataSetIndex(), points.dataSetIndex());
351         const int expectedFirstColumn = std::max(0, points_->firstColumn() - firstcol_);
352         const int expectedLastColumn  = std::min(n_ - 1, points_->lastColumn() - firstcol_);
353         EXPECT_EQ(expectedFirstColumn, points.firstColumn());
354         EXPECT_EQ(expectedLastColumn, points.lastColumn());
355         checkHeader(points.header(), *frame_);
356         checkPoints(points, *points_, firstcol_);
357     }
358
359 private:
360     const AnalysisDataTestInputFrame*    frame_;
361     const AnalysisDataTestInputPointSet* points_;
362     int                                  firstcol_;
363     int                                  n_;
364 };
365
366 /*! \brief
367  * Functor for requesting data storage.
368  *
369  * This functor is designed to be invoked as a handled for
370  * IAnalysisDataModule::dataStarted().
371  */
372 class DataStorageRequester
373 {
374 public:
375     /*! \brief
376      * Constructs a functor that requests the given amount of storage.
377      *
378      * \param[in] count  Number of frames of storage to request, or
379      *      -1 for all frames.
380      *
381      * \see AbstractAnalysisData::requestStorage()
382      */
383     explicit DataStorageRequester(int count) : count_(count) {}
384
385     //! Function call operator for the functor.
386     void operator()(AbstractAnalysisData* data) const { EXPECT_TRUE(data->requestStorage(count_)); }
387
388 private:
389     int count_;
390 };
391
392 /*! \brief
393  * Functor for checking data frame points and storage against static test input
394  * data.
395  *
396  * This functor is designed to be invoked as a handled for
397  * IAnalysisDataModule::pointsAdded().
398  */
399 class StaticDataPointsStorageChecker
400 {
401 public:
402     /*! \brief
403      * Constructs a checker for a given frame.
404      *
405      * \param[in] source     Data object that is being checked.
406      * \param[in] data       Test input data to check against.
407      * \param[in] frameIndex Frame index for which this functor expects
408      *      to be called.
409      * \param[in] pointSetIndex Point set for which this functor expects
410      *      to be called.
411      * \param[in] storageCount How many past frames should be checked for
412      *      storage (-1 = check all frames).
413      *
414      * This checker works as StaticDataPointsChecker, but additionally
415      * checks that previous frames can be accessed using access methods
416      * in AbstractAnalysisData and that correct data is returned.
417      *
418      * \p source and \p data must exist for the lifetime of this object.
419      */
420     StaticDataPointsStorageChecker(AbstractAnalysisData*        source,
421                                    const AnalysisDataTestInput* data,
422                                    int                          frameIndex,
423                                    int                          pointSetIndex,
424                                    int                          storageCount) :
425         source_(source),
426         data_(data),
427         frameIndex_(frameIndex),
428         pointSetIndex_(pointSetIndex),
429         storageCount_(storageCount)
430     {
431     }
432
433     //! Function call operator for the functor.
434     void operator()(const AnalysisDataPointSetRef& points) const
435     {
436         SCOPED_TRACE(formatString("Frame %d", frameIndex_));
437         const AnalysisDataTestInputFrame&    refFrame  = data_->frame(frameIndex_);
438         const AnalysisDataTestInputPointSet& refPoints = refFrame.pointSet(pointSetIndex_);
439         EXPECT_EQ(refPoints.firstColumn(), points.firstColumn());
440         EXPECT_EQ(refPoints.size(), points.columnCount());
441         checkHeader(points.header(), refFrame);
442         checkPoints(points, refPoints, 0);
443         for (int past = 1; (storageCount_ < 0 || past <= storageCount_) && past <= frameIndex_; ++past)
444         {
445             int index = frameIndex_ - past;
446             SCOPED_TRACE(formatString("Checking storage of frame %d", index));
447             ASSERT_NO_THROW_GMX({
448                 AnalysisDataFrameRef frame = source_->getDataFrame(index);
449                 ASSERT_TRUE(frame.isValid());
450                 checkFrame(frame, data_->frame(index));
451             });
452         }
453     }
454
455 private:
456     AbstractAnalysisData*        source_;
457     const AnalysisDataTestInput* data_;
458     int                          frameIndex_;
459     int                          pointSetIndex_;
460     int                          storageCount_;
461 };
462
463 /*! \brief
464  * Sets the mock object expectation to mimick AnalysisDataModuleSerial.
465  *
466  * Makes MockAnalysisDataModule::parallelDataStarted() behave as if the mock
467  * object was an AnalysisDataModuleSerial object: forward the call to
468  * MockAnalysisDataModule::dataStarted() and return false.
469  */
470 void setSerialExpectationForParallelDataStarted(MockAnalysisDataModule* mock)
471 {
472     using ::testing::_;
473     using ::testing::AtMost;
474     using ::testing::DoAll;
475     using ::testing::Invoke;
476     using ::testing::Return;
477     using ::testing::WithArg;
478     EXPECT_CALL(*mock, parallelDataStarted(_, _))
479             .Times(AtMost(1))
480             .WillOnce(DoAll(WithArg<0>(Invoke(mock, &MockAnalysisDataModule::dataStarted)), Return(false)));
481 }
482
483 } // anonymous namespace
484
485
486 MockAnalysisDataModule::MockAnalysisDataModule(int flags) : impl_(new Impl(flags)) {}
487
488
489 MockAnalysisDataModule::~MockAnalysisDataModule() {}
490
491
492 int MockAnalysisDataModule::flags() const
493 {
494     return impl_->flags_;
495 }
496
497
498 void MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput& data,
499                                               AbstractAnalysisData*        source,
500                                               bool                         bParallel)
501 {
502     impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
503
504     using ::testing::_;
505     using ::testing::Invoke;
506     using ::testing::Property;
507     using ::testing::Return;
508
509     if (bParallel)
510     {
511 #ifndef __clang_analyzer__
512         ::testing::Expectation init =
513                 EXPECT_CALL(*this, parallelDataStarted(source, _)).WillOnce(Return(true));
514         ::testing::ExpectationSet framesFinished;
515         ::testing::Expectation    prevFinish;
516         for (int row = 0; row < data.frameCount(); ++row)
517         {
518             ::testing::InSequence             frameSequence;
519             const AnalysisDataTestInputFrame& frame = data.frame(row);
520             EXPECT_CALL(*this, frameStarted(Property(&AnalysisDataFrameHeader::index, row)))
521                     .After(init)
522                     .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
523             for (int ps = 0; ps < frame.pointSetCount(); ++ps)
524             {
525                 const AnalysisDataTestInputPointSet& points = frame.pointSet(ps);
526                 StaticDataPointsChecker              checker(
527                         &frame, &points, 0, data.columnCount(points.dataSetIndex()));
528                 EXPECT_CALL(*this, pointsAdded(Property(&AnalysisDataPointSetRef::frameIndex, row)))
529                         .WillOnce(Invoke(checker));
530             }
531             EXPECT_CALL(*this, frameFinished(Property(&AnalysisDataFrameHeader::index, row)))
532                     .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
533             ::testing::Expectation finish;
534             if (row > 0)
535             {
536                 finish = EXPECT_CALL(*this, frameFinishedSerial(row)).After(prevFinish);
537             }
538             else
539             {
540                 finish = EXPECT_CALL(*this, frameFinishedSerial(row));
541             }
542             framesFinished += finish;
543             prevFinish = finish;
544         }
545         EXPECT_CALL(*this, dataFinished()).After(framesFinished);
546 #endif
547     }
548     else
549     {
550         ::testing::InSequence dummy;
551         setSerialExpectationForParallelDataStarted(this);
552         EXPECT_CALL(*this, dataStarted(source));
553         for (int row = 0; row < data.frameCount(); ++row)
554         {
555             const AnalysisDataTestInputFrame& frame = data.frame(row);
556             EXPECT_CALL(*this, frameStarted(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
557             for (int ps = 0; ps < frame.pointSetCount(); ++ps)
558             {
559                 const AnalysisDataTestInputPointSet& points = frame.pointSet(ps);
560                 StaticDataPointsChecker              checker(
561                         &frame, &points, 0, data.columnCount(points.dataSetIndex()));
562                 EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
563             }
564             EXPECT_CALL(*this, frameFinished(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
565             EXPECT_CALL(*this, frameFinishedSerial(row));
566         }
567         EXPECT_CALL(*this, dataFinished());
568     }
569 }
570
571
572 void MockAnalysisDataModule::setupStaticColumnCheck(const AnalysisDataTestInput& data,
573                                                     int                          firstcol,
574                                                     int                          n,
575                                                     AbstractAnalysisData* /*source*/)
576 {
577     impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
578
579     ::testing::InSequence dummy;
580     using ::testing::_;
581     using ::testing::Invoke;
582
583     setSerialExpectationForParallelDataStarted(this);
584     EXPECT_CALL(*this, dataStarted(_));
585     for (int row = 0; row < data.frameCount(); ++row)
586     {
587         const AnalysisDataTestInputFrame& frame = data.frame(row);
588         EXPECT_CALL(*this, frameStarted(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
589         for (int ps = 0; ps < frame.pointSetCount(); ++ps)
590         {
591             const AnalysisDataTestInputPointSet& points = frame.pointSet(ps);
592             if (points.lastColumn() >= firstcol && points.firstColumn() <= firstcol + n - 1)
593             {
594                 EXPECT_CALL(*this, pointsAdded(_))
595                         .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, firstcol, n)));
596             }
597         }
598         EXPECT_CALL(*this, frameFinished(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
599         EXPECT_CALL(*this, frameFinishedSerial(row));
600     }
601     EXPECT_CALL(*this, dataFinished());
602 }
603
604
605 void MockAnalysisDataModule::setupStaticStorageCheck(const AnalysisDataTestInput& data,
606                                                      int                          storageCount,
607                                                      AbstractAnalysisData*        source)
608 {
609     GMX_RELEASE_ASSERT(data.isMultipoint() == source->isMultipoint(),
610                        "Mismatching multipoint properties");
611     impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
612
613     ::testing::InSequence dummy;
614     using ::testing::_;
615     using ::testing::Invoke;
616
617     setSerialExpectationForParallelDataStarted(this);
618     EXPECT_CALL(*this, dataStarted(source)).WillOnce(Invoke(DataStorageRequester(storageCount)));
619     for (int row = 0; row < data.frameCount(); ++row)
620     {
621         const AnalysisDataTestInputFrame& frame = data.frame(row);
622         EXPECT_CALL(*this, frameStarted(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
623         for (int pointSet = 0; pointSet < frame.pointSetCount(); ++pointSet)
624         {
625             StaticDataPointsStorageChecker checker(source, &data, row, pointSet, storageCount);
626             EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
627         }
628         EXPECT_CALL(*this, frameFinished(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
629         EXPECT_CALL(*this, frameFinishedSerial(row));
630     }
631     EXPECT_CALL(*this, dataFinished());
632 }
633
634
635 void MockAnalysisDataModule::setupReferenceCheck(const TestReferenceChecker& checker,
636                                                  AbstractAnalysisData*       source)
637 {
638     impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMissing | efAllowMultipleDataSets;
639
640     impl_->rootChecker_ = TestReferenceChecker(checker);
641     // Google Mock does not support checking the order fully, because
642     // the number of frames is not known.
643     // Order of the frameStarted(), pointsAdded() and frameFinished()
644     // calls is checked using Google Test assertions in the invoked methods.
645     using ::testing::_;
646     using ::testing::AnyNumber;
647     using ::testing::Expectation;
648     using ::testing::Invoke;
649
650     setSerialExpectationForParallelDataStarted(this);
651     Expectation dataStart =
652             EXPECT_CALL(*this, dataStarted(source)).WillOnce(Invoke(impl_.get(), &Impl::startReferenceData));
653     Expectation frameStart = EXPECT_CALL(*this, frameStarted(_))
654                                      .After(dataStart)
655                                      .WillRepeatedly(Invoke(impl_.get(), &Impl::startReferenceFrame));
656     Expectation pointsAdd = EXPECT_CALL(*this, pointsAdded(_))
657                                     .After(dataStart)
658                                     .WillRepeatedly(Invoke(impl_.get(), &Impl::checkReferencePoints));
659     Expectation frameFinish = EXPECT_CALL(*this, frameFinished(_))
660                                       .After(dataStart)
661                                       .WillRepeatedly(Invoke(impl_.get(), &Impl::finishReferenceFrame));
662     Expectation frameFinishSerial =
663             EXPECT_CALL(*this, frameFinishedSerial(_))
664                     .After(dataStart)
665                     .WillRepeatedly(Invoke(impl_.get(), &Impl::finishReferenceFrameSerial));
666     EXPECT_CALL(*this, dataFinished()).After(frameStart, pointsAdd, frameFinish, frameFinishSerial);
667 }
668
669 } // namespace test
670 } // namespace gmx