2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,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.
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.
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.
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.
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.
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.
37 * Implements classes in mock_datamodule.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_analysisdata
44 #include "mock_datamodule.h"
46 #include <gmock/gmock.h>
47 #include <gtest/gtest.h>
49 #include "gromacs/analysisdata/analysisdata.h"
50 #include "gromacs/analysisdata/dataframe.h"
51 #include "gromacs/utility/gmxassert.h"
52 #include "gromacs/utility/stringutil.h"
54 #include "gromacs/analysisdata/tests/datatest.h"
55 #include "testutils/refdata.h"
56 #include "testutils/testasserts.h"
63 /********************************************************************
64 * MockAnalysisDataModule::Impl
68 * Private implementation class for gmx::test::MockAnalysisDataModule.
70 * \ingroup module_analysisdata
72 class MockAnalysisDataModule::Impl
75 //! Initializes a mock object with the given flags.
76 explicit Impl(int flags);
79 * Callback used to initialize reference data checks
81 * Called in response to dataStarted().
82 * Records the source data for later use (for access to data properties).
84 void startReferenceData(AbstractAnalysisData *data);
86 * Callback used to check frame start against reference data.
88 * Called to check parameters and order of calls to frameStarted().
89 * In addition to reference data checks, this method checks statically
90 * that the new frame matches \a frameIndex_.
92 void startReferenceFrame(const AnalysisDataFrameHeader &header);
94 * Callback used to check frame points against reference data.
96 * Called to check parameters and order of calls to pointsAdded().
98 void checkReferencePoints(const AnalysisDataPointSetRef &points);
100 * Callback used to check frame finish against reference data.
102 * Called to check parameters and order of calls to frameFinished().
104 void finishReferenceFrame(const AnalysisDataFrameHeader &header);
106 * Callback used to check serial frame finish with reference data.
108 * Called to check parameters and order of calls to
109 * frameFinishedSerial().
110 * \a frameIndex_ is incremented here.
112 void finishReferenceFrameSerial(int frameIndex);
115 * Reference data checker to use for checking frames.
117 * Must be non-NULL if startReferenceFrame() is called.
119 boost::scoped_ptr<TestReferenceChecker> rootChecker_;
121 * Reference data checker to use to check the current frame.
123 * Non-NULL between startReferenceFrame() and finishReferenceFrame()
126 boost::scoped_ptr<TestReferenceChecker> frameChecker_;
128 const AbstractAnalysisData *source_;
129 //! Flags that will be returned by the mock module.
131 //! Index of the current/next frame.
139 * Checks a single AnalysisDataValue.
141 * \ingroup module_analysisdata
143 void checkReferenceDataPoint(TestReferenceChecker *checker,
144 const AnalysisDataValue &value)
146 TestReferenceChecker compound(checker->checkCompound("DataValue", NULL));
147 compound.checkReal(value.value(), "Value");
148 if (compound.checkPresent(value.hasError(), "Error"))
150 compound.checkReal(value.error(), "Error");
152 if (compound.checkPresent(!value.isPresent(), "Present"))
154 compound.checkBoolean(value.isPresent(), "Present");
160 MockAnalysisDataModule::Impl::Impl(int flags)
161 : source_(NULL), flags_(flags), frameIndex_(0)
167 MockAnalysisDataModule::Impl::startReferenceData(AbstractAnalysisData *data)
174 MockAnalysisDataModule::Impl::startReferenceFrame(
175 const AnalysisDataFrameHeader &header)
177 GMX_RELEASE_ASSERT(rootChecker_.get() != NULL,
178 "Root checker not set, but reference data used");
179 EXPECT_TRUE(frameChecker_.get() == NULL);
180 EXPECT_EQ(frameIndex_, header.index());
181 frameChecker_.reset(new TestReferenceChecker(
182 rootChecker_->checkCompound("DataFrame",
183 formatString("Frame%d", frameIndex_).c_str())));
184 frameChecker_->checkReal(header.x(), "X");
189 MockAnalysisDataModule::Impl::checkReferencePoints(
190 const AnalysisDataPointSetRef &points)
192 EXPECT_TRUE(frameChecker_.get() != NULL);
193 if (frameChecker_.get() != NULL)
195 TestReferenceChecker checker(
196 frameChecker_->checkCompound("DataValues", NULL));
197 checker.checkInteger(points.columnCount(), "Count");
198 if (checker.checkPresent(source_->dataSetCount() > 1, "DataSet"))
200 checker.checkInteger(points.dataSetIndex(), "DataSet");
202 const int sourceColumnCount = source_->columnCount(points.dataSetIndex());
203 const bool bAllColumns = (points.firstColumn() == 0
204 && points.columnCount() == sourceColumnCount);
205 if (checker.checkPresent(!bAllColumns, "FirstColumn"))
207 checker.checkInteger(points.firstColumn(), "FirstColumn");
208 checker.checkInteger(points.lastColumn(), "LastColumn");
211 AnalysisDataValuesRef::const_iterator value;
212 for (value = points.values().begin(); value != points.values().end(); ++value)
214 checkReferenceDataPoint(&checker, *value);
221 MockAnalysisDataModule::Impl::finishReferenceFrame(
222 const AnalysisDataFrameHeader &header)
224 EXPECT_TRUE(frameChecker_.get() != NULL);
225 EXPECT_EQ(frameIndex_, header.index());
226 frameChecker_.reset();
231 MockAnalysisDataModule::Impl::finishReferenceFrameSerial(int frameIndex)
233 EXPECT_TRUE(frameChecker_.get() == NULL);
234 EXPECT_EQ(frameIndex_, frameIndex);
239 /********************************************************************
240 * MockAnalysisDataModule
247 * Helper function for checking the data frame header against static data.
249 * \param[in] header Frame header to check.
250 * \param[in] refFrame Data to check against.
252 void checkHeader(const AnalysisDataFrameHeader &header,
253 const AnalysisDataTestInputFrame &refFrame)
255 EXPECT_EQ(refFrame.index(), header.index());
256 EXPECT_FLOAT_EQ(refFrame.x(), header.x());
257 EXPECT_FLOAT_EQ(refFrame.dx(), header.dx());
261 * Helper function for checking a point set against static data.
263 * \param[in] points Point set to check.
264 * \param[in] refPoints Data to check against.
265 * \param[in] columnOffset Offset of first column of \p points in \p refPoints.
267 void checkPoints(const AnalysisDataPointSetRef &points,
268 const AnalysisDataTestInputPointSet &refPoints,
271 for (int i = 0; i < points.columnCount(); ++i)
273 const int column = points.firstColumn() - refPoints.firstColumn() + i + columnOffset;
274 EXPECT_FLOAT_EQ(refPoints.y(column),
276 << " Column: " << i+1 << " / " << points.columnCount()
277 << " (+" << points.firstColumn() << ")\n"
278 << "Ref. col: " << column+1 << " / " << refPoints.size()
279 << " (+" << refPoints.firstColumn() << ", offs " << columnOffset << ")";
284 * Helper function for checking a full frame against static data.
286 * \param[in] frame Frame to check.
287 * \param[in] refFrame Data to check against.
289 void checkFrame(const AnalysisDataFrameRef &frame,
290 const AnalysisDataTestInputFrame &refFrame)
292 checkHeader(frame.header(), refFrame);
293 ASSERT_EQ(refFrame.pointSetCount(), frame.pointSetCount());
294 for (int i = 0; i < frame.pointSetCount(); ++i)
296 const AnalysisDataPointSetRef &points = frame.pointSet(i);
297 const AnalysisDataTestInputPointSet &refPoints = refFrame.pointSet(i);
298 EXPECT_EQ(refPoints.firstColumn(), points.firstColumn());
299 checkPoints(points, refPoints, 0);
304 * Functor for checking data frame header against static test input data.
306 * This functor is designed to be invoked as a handled for
307 * IAnalysisDataModule::frameStarted().
309 class StaticDataFrameHeaderChecker
313 * Constructs a checker against a given input data frame.
315 * \param[in] frame Frame to check against.
317 * \p frame must exist for the lifetime of this object.
319 StaticDataFrameHeaderChecker(const AnalysisDataTestInputFrame *frame)
324 //! Function call operator for the functor.
325 void operator()(const AnalysisDataFrameHeader &header) const
327 SCOPED_TRACE(formatString("Frame %d", frame_->index()));
328 checkHeader(header, *frame_);
332 const AnalysisDataTestInputFrame *frame_;
336 * Functor for checking data frame points against static test input data.
338 * This functor is designed to be invoked as a handled for
339 * IAnalysisDataModule::pointsAdded().
341 class StaticDataPointsChecker
345 * Constructs a checker against a given input data frame and point set.
347 * \param[in] frame Frame to check against.
348 * \param[in] points Point set in \p frame to check against.
349 * \param[in] firstcol Expected first column.
350 * \param[in] n Expected number of columns.
352 * \p firstcol and \p n are used to create a checker that only expects
353 * to be called for a subset of columns.
354 * \p frame and \p points must exist for the lifetime of this object.
356 StaticDataPointsChecker(const AnalysisDataTestInputFrame *frame,
357 const AnalysisDataTestInputPointSet *points,
359 : frame_(frame), points_(points), firstcol_(firstcol), n_(n)
363 //! Function call operator for the functor.
364 void operator()(const AnalysisDataPointSetRef &points) const
366 SCOPED_TRACE(formatString("Frame %d, point set %d",
367 frame_->index(), points_->index()));
368 EXPECT_EQ(points_->dataSetIndex(), points.dataSetIndex());
369 const int expectedFirstColumn
370 = std::max(0, points_->firstColumn() - firstcol_);
371 const int expectedLastColumn
372 = std::min(n_ - 1, points_->lastColumn() - firstcol_);
373 EXPECT_EQ(expectedFirstColumn, points.firstColumn());
374 EXPECT_EQ(expectedLastColumn, points.lastColumn());
375 checkHeader(points.header(), *frame_);
376 checkPoints(points, *points_, firstcol_);
380 const AnalysisDataTestInputFrame *frame_;
381 const AnalysisDataTestInputPointSet *points_;
387 * Functor for requesting data storage.
389 * This functor is designed to be invoked as a handled for
390 * IAnalysisDataModule::dataStarted().
392 class DataStorageRequester
396 * Constructs a functor that requests the given amount of storage.
398 * \param[in] count Number of frames of storage to request, or
401 * \see AbstractAnalysisData::requestStorage()
403 explicit DataStorageRequester(int count) : count_(count) {}
405 //! Function call operator for the functor.
406 void operator()(AbstractAnalysisData *data) const
408 EXPECT_TRUE(data->requestStorage(count_));
416 * Functor for checking data frame points and storage against static test input
419 * This functor is designed to be invoked as a handled for
420 * IAnalysisDataModule::pointsAdded().
422 class StaticDataPointsStorageChecker
426 * Constructs a checker for a given frame.
428 * \param[in] source Data object that is being checked.
429 * \param[in] data Test input data to check against.
430 * \param[in] frameIndex Frame index for which this functor expects
432 * \param[in] pointSetIndex Point set for which this functor expects
434 * \param[in] storageCount How many past frames should be checked for
435 * storage (-1 = check all frames).
437 * This checker works as StaticDataPointsChecker, but additionally
438 * checks that previous frames can be accessed using access methods
439 * in AbstractAnalysisData and that correct data is returned.
441 * \p source and \p data must exist for the lifetime of this object.
443 StaticDataPointsStorageChecker(AbstractAnalysisData *source,
444 const AnalysisDataTestInput *data,
445 int frameIndex, int pointSetIndex,
447 : source_(source), data_(data),
448 frameIndex_(frameIndex), pointSetIndex_(pointSetIndex),
449 storageCount_(storageCount)
453 //! Function call operator for the functor.
454 void operator()(const AnalysisDataPointSetRef &points) const
456 SCOPED_TRACE(formatString("Frame %d", frameIndex_));
457 const AnalysisDataTestInputFrame &refFrame = data_->frame(frameIndex_);
458 const AnalysisDataTestInputPointSet &refPoints = refFrame.pointSet(pointSetIndex_);
459 EXPECT_EQ(refPoints.firstColumn(), points.firstColumn());
460 EXPECT_EQ(refPoints.size(), points.columnCount());
461 checkHeader(points.header(), refFrame);
462 checkPoints(points, refPoints, 0);
464 (storageCount_ < 0 || past <= storageCount_) && past <= frameIndex_;
467 int index = frameIndex_ - past;
468 SCOPED_TRACE(formatString("Checking storage of frame %d", index));
469 ASSERT_NO_THROW_GMX({
470 AnalysisDataFrameRef frame = source_->getDataFrame(index);
471 ASSERT_TRUE(frame.isValid());
472 checkFrame(frame, data_->frame(index));
478 AbstractAnalysisData *source_;
479 const AnalysisDataTestInput *data_;
486 * Sets the mock object expectation to mimick AnalysisDataModuleSerial.
488 * Makes MockAnalysisDataModule::parallelDataStarted() behave as if the mock
489 * object was an AnalysisDataModuleSerial object: forward the call to
490 * MockAnalysisDataModule::dataStarted() and return false.
492 void setSerialExpectationForParallelDataStarted(MockAnalysisDataModule *mock)
495 using ::testing::AtMost;
496 using ::testing::DoAll;
497 using ::testing::Invoke;
498 using ::testing::Return;
499 using ::testing::WithArg;
500 EXPECT_CALL(*mock, parallelDataStarted(_, _))
502 .WillOnce(DoAll(WithArg<0>(Invoke(mock, &MockAnalysisDataModule::dataStarted)),
506 } // anonymous namespace
509 MockAnalysisDataModule::MockAnalysisDataModule(int flags)
510 : impl_(new Impl(flags))
515 MockAnalysisDataModule::~MockAnalysisDataModule()
520 int MockAnalysisDataModule::flags() const
522 return impl_->flags_;
527 MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput &data,
528 AbstractAnalysisData *source,
531 impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
534 using ::testing::Invoke;
535 using ::testing::Property;
536 using ::testing::Return;
540 ::testing::Expectation init =
541 EXPECT_CALL(*this, parallelDataStarted(source, _))
542 .WillOnce(Return(true));
543 ::testing::ExpectationSet framesFinished;
544 ::testing::Expectation prevFinish;
545 for (int row = 0; row < data.frameCount(); ++row)
547 ::testing::InSequence frameSequence;
548 const AnalysisDataTestInputFrame &frame = data.frame(row);
549 EXPECT_CALL(*this, frameStarted(Property(&AnalysisDataFrameHeader::index, row)))
551 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
552 for (int ps = 0; ps < frame.pointSetCount(); ++ps)
554 const AnalysisDataTestInputPointSet &points = frame.pointSet(ps);
555 StaticDataPointsChecker checker(&frame, &points, 0,
556 data.columnCount(points.dataSetIndex()));
557 EXPECT_CALL(*this, pointsAdded(Property(&AnalysisDataPointSetRef::frameIndex, row)))
558 .WillOnce(Invoke(checker));
560 EXPECT_CALL(*this, frameFinished(Property(&AnalysisDataFrameHeader::index, row)))
561 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
562 ::testing::Expectation finish;
565 finish = EXPECT_CALL(*this, frameFinishedSerial(row))
570 finish = EXPECT_CALL(*this, frameFinishedSerial(row));
572 framesFinished += finish;
575 EXPECT_CALL(*this, dataFinished())
576 .After(framesFinished);
580 ::testing::InSequence dummy;
581 setSerialExpectationForParallelDataStarted(this);
582 EXPECT_CALL(*this, dataStarted(source));
583 for (int row = 0; row < data.frameCount(); ++row)
585 const AnalysisDataTestInputFrame &frame = data.frame(row);
586 EXPECT_CALL(*this, frameStarted(_))
587 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
588 for (int ps = 0; ps < frame.pointSetCount(); ++ps)
590 const AnalysisDataTestInputPointSet &points = frame.pointSet(ps);
591 StaticDataPointsChecker checker(&frame, &points, 0,
592 data.columnCount(points.dataSetIndex()));
593 EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
595 EXPECT_CALL(*this, frameFinished(_))
596 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
597 EXPECT_CALL(*this, frameFinishedSerial(row));
599 EXPECT_CALL(*this, dataFinished());
605 MockAnalysisDataModule::setupStaticColumnCheck(
606 const AnalysisDataTestInput &data,
607 int firstcol, int n, AbstractAnalysisData * /*source*/)
609 impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
611 ::testing::InSequence dummy;
613 using ::testing::Invoke;
615 setSerialExpectationForParallelDataStarted(this);
616 EXPECT_CALL(*this, dataStarted(_));
617 for (int row = 0; row < data.frameCount(); ++row)
619 const AnalysisDataTestInputFrame &frame = data.frame(row);
620 EXPECT_CALL(*this, frameStarted(_))
621 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
622 for (int ps = 0; ps < frame.pointSetCount(); ++ps)
624 const AnalysisDataTestInputPointSet &points = frame.pointSet(ps);
625 if (points.lastColumn() >= firstcol
626 && points.firstColumn() <= firstcol + n - 1)
628 EXPECT_CALL(*this, pointsAdded(_))
629 .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, firstcol, n)));
632 EXPECT_CALL(*this, frameFinished(_))
633 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
634 EXPECT_CALL(*this, frameFinishedSerial(row));
636 EXPECT_CALL(*this, dataFinished());
641 MockAnalysisDataModule::setupStaticStorageCheck(
642 const AnalysisDataTestInput &data,
643 int storageCount, AbstractAnalysisData *source)
645 GMX_RELEASE_ASSERT(data.isMultipoint() == source->isMultipoint(),
646 "Mismatching multipoint properties");
647 impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
649 ::testing::InSequence dummy;
651 using ::testing::Invoke;
653 setSerialExpectationForParallelDataStarted(this);
654 EXPECT_CALL(*this, dataStarted(source))
655 .WillOnce(Invoke(DataStorageRequester(storageCount)));
656 for (int row = 0; row < data.frameCount(); ++row)
658 const AnalysisDataTestInputFrame &frame = data.frame(row);
659 EXPECT_CALL(*this, frameStarted(_))
660 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
661 for (int pointSet = 0; pointSet < frame.pointSetCount(); ++pointSet)
663 StaticDataPointsStorageChecker checker(source, &data, row, pointSet,
665 EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
667 EXPECT_CALL(*this, frameFinished(_))
668 .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
669 EXPECT_CALL(*this, frameFinishedSerial(row));
671 EXPECT_CALL(*this, dataFinished());
676 MockAnalysisDataModule::setupReferenceCheck(const TestReferenceChecker &checker,
677 AbstractAnalysisData *source)
679 impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMissing
680 | efAllowMultipleDataSets;
682 impl_->rootChecker_.reset(new TestReferenceChecker(checker));
683 // Google Mock does not support checking the order fully, because
684 // the number of frames is not known.
685 // Order of the frameStarted(), pointsAdded() and frameFinished()
686 // calls is checked using Google Test assertions in the invoked methods.
688 using ::testing::AnyNumber;
689 using ::testing::Expectation;
690 using ::testing::Invoke;
692 setSerialExpectationForParallelDataStarted(this);
693 Expectation dataStart = EXPECT_CALL(*this, dataStarted(source))
694 .WillOnce(Invoke(impl_.get(), &Impl::startReferenceData));
695 Expectation frameStart = EXPECT_CALL(*this, frameStarted(_))
697 .WillRepeatedly(Invoke(impl_.get(), &Impl::startReferenceFrame));
698 Expectation pointsAdd = EXPECT_CALL(*this, pointsAdded(_))
700 .WillRepeatedly(Invoke(impl_.get(), &Impl::checkReferencePoints));
701 Expectation frameFinish = EXPECT_CALL(*this, frameFinished(_))
703 .WillRepeatedly(Invoke(impl_.get(), &Impl::finishReferenceFrame));
704 Expectation frameFinishSerial = EXPECT_CALL(*this, frameFinishedSerial(_))
706 .WillRepeatedly(Invoke(impl_.get(), &Impl::finishReferenceFrameSerial));
707 EXPECT_CALL(*this, dataFinished())
708 .After(frameStart, pointsAdd, frameFinish, frameFinishSerial);