Enable static anon namespace workaround on pathscale
[alexxy/gromacs.git] / src / gromacs / analysisdata / tests / datatest.h
index 2f775dc5237a31c28b78887599063f6cd5f64259..09f41274706c6bc50863b15062b313f33706cdb2 100644 (file)
@@ -1,55 +1,64 @@
 /*
+ * This file is part of the GROMACS molecular simulation package.
  *
- *                This source code is part of
+ * Copyright (c) 2011,2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
  *
- *                 G   R   O   M   A   C   S
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
  *
- *          GROningen MAchine for Chemical Simulations
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
  *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
  *
  * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
+ * the research papers on the package. Check out http://www.gromacs.org.
  */
 /*! \libinternal \file
  * \brief
  * Helper classes for testing classes that derive from AbstractAnalysisData.
  *
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \inlibraryapi
  * \ingroup module_analysisdata
  */
 #ifndef GMX_ANALYSISDATA_TESTS_DATATEST_H
 #define GMX_ANALYSISDATA_TESTS_DATATEST_H
 
-#include <limits>
 #include <vector>
 
 #include <gtest/gtest.h>
 
 #include "gromacs/legacyheaders/types/simple.h"
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/utility/gmxassert.h"
 
 #include "testutils/refdata.h"
 
+// currently the bug manifests itself only in AbstractAnalysisData testing
+#if (defined __ICL && __ICL >= 1400) || (defined __ICC && __ICC >= 1400) || (defined __PATHSCALE__)
+#define STATIC_ANON_NAMESPACE_BUG //see #1558 for details
+#endif
+
 namespace gmx
 {
 
@@ -60,14 +69,7 @@ class AnalysisDataHandle;
 namespace test
 {
 
-class MockAnalysisModule;
-
-//! Constant to use to signify end of data for AnalysisDataTestInput.
-const real END_OF_DATA = std::numeric_limits<real>::max();
-//! Constant to use to signify end of one data frame for AnalysisDataTestInput.
-const real END_OF_FRAME = std::numeric_limits<real>::min();
-//! Constant to use to signify end of one multipoint set for AnalysisDataTestInput.
-const real MPSTOP = -std::numeric_limits<real>::max();
+class FloatingPointTolerance;
 
 /*! \libinternal \brief
  * Represents a single set of points in AnalysisDataTestInputFrame structure.
@@ -77,34 +79,79 @@ const real MPSTOP = -std::numeric_limits<real>::max();
  * passed separately and AnalysisDataHandle::finishPointSet() called in
  * between.
  *
+ * \inlibraryapi
  * \ingroup module_analysisdata
  */
 class AnalysisDataTestInputPointSet
 {
     public:
+        //! Returns zero-based index of this point set in its frame.
+        int index() const { return index_; }
+        //! Returns zero-based index of the data set of this point set.
+        int dataSetIndex() const { return dataSetIndex_; }
+        //! Returns zero-based index of the first column in this point set.
+        int firstColumn() const { return firstColumn_; }
+        //! Returns zero-based index of the last column in this point set.
+        int lastColumn() const { return firstColumn_ + size() - 1; }
         //! Returns the number of columns in the point set.
-        int size() const { return y_.size(); }
+        int size() const { return values_.size(); }
         //! Returns the value in column \p i.
-        real y(int i) const { return y_[i]; }
+        real y(int i) const { return values_[i].y; }
+        //! Returns whether the error is present for column \p i.
+        bool hasError(int i) const { return values_[i].bError; }
         //! Returns the error in column \p i.
-        real dy(int i) const { return 0.0; }
+        real error(int i) const { return values_[i].error; }
         //! Returns whether the value in column \p i is present.
-        real present(int i) const { return true; }
-        //! Returns a vector of values for all columns.
-        const std::vector<real> &yvector() const { return y_; }
+        bool present(int /*i*/) const { return true; }
+        //! Returns an AnalysisDataValue for column \p i.
+        AnalysisDataValue value(int i) const
+        {
+            AnalysisDataValue result;
+            result.setValue(values_[i].y);
+            if (values_[i].bError)
+            {
+                result.setError(values_[i].error);
+            }
+            return result;
+        }
+
+        //! Appends a value to this point set.
+        void addValue(real y) { values_.push_back(Value(y)); }
+        //! Appends a value with an error estimate to this point set.
+        void addValueWithError(real y, real error)
+        {
+            values_.push_back(Value(y, error));
+        }
 
     private:
         //! Creates an empty point set.
-        AnalysisDataTestInputPointSet();
+        AnalysisDataTestInputPointSet(int index, int dataSetIndex,
+                                      int firstColumn);
 
-        std::vector<real>       y_;
+        struct Value
+        {
+            Value() : y(0.0), error(0.0), bError(false) {}
+            explicit Value(real y) : y(y), error(0.0), bError(false) {}
+            Value(real y, real error) : y(y), error(error), bError(true) {}
 
-        friend class AnalysisDataTestInput;
+            real                y;
+            real                error;
+            bool                bError;
+        };
+
+        int                     index_;
+        int                     dataSetIndex_;
+        int                     firstColumn_;
+        std::vector<Value>      values_;
+
+        //! For constructing new point sets.
+        friend class AnalysisDataTestInputFrame;
 };
 
 /*! \libinternal \brief
  * Represents a single frame in AnalysisDataTestInput structure.
  *
+ * \inlibraryapi
  * \ingroup module_analysisdata
  */
 class AnalysisDataTestInputFrame
@@ -118,71 +165,94 @@ class AnalysisDataTestInputFrame
         real dx() const { return 0.0; }
 
         //! Number of individual point sets in the frame.
-        int pointSetCount() const { return points_.size(); }
+        int pointSetCount() const { return pointSets_.size(); }
         //! Returns a point set object for a given point set.
-        const AnalysisDataTestInputPointSet &points(int index = 0) const
+        const AnalysisDataTestInputPointSet &pointSet(int index) const
         {
-            GMX_ASSERT(index >= 0 && static_cast<size_t>(index) < points_.size(),
+            GMX_ASSERT(index >= 0 && static_cast<size_t>(index) < pointSets_.size(),
                        "Point set index out of range");
-            return points_[index];
+            return pointSets_[index];
         }
 
+        //! Appends an empty point set to this frame.
+        AnalysisDataTestInputPointSet &addPointSet(int dataSet, int firstColumn);
+        //! Adds a point set with given values to this frame.
+        void addPointSetWithValues(int dataSet, int firstColumn, real y1);
+        //! Adds a point set with given values to this frame.
+        void addPointSetWithValues(int dataSet, int firstColumn,
+                                   real y1, real y2);
+        //! Adds a point set with given values to this frame.
+        void addPointSetWithValues(int dataSet, int firstColumn,
+                                   real y1, real y2, real y3);
+        //! Adds a point set with given values to this frame.
+        void addPointSetWithValueAndError(int dataSet, int firstColumn,
+                                          real y1, real e1);
+
     private:
         //! Constructs a new frame object with the given values.
         AnalysisDataTestInputFrame(int index, real x);
 
-        int                     index_;
-        real                    x_;
-        std::vector<AnalysisDataTestInputPointSet>  points_;
+        int                                         index_;
+        real                                        x_;
+        std::vector<AnalysisDataTestInputPointSet>  pointSets_;
 
+        //! For constructing new frames.
         friend class AnalysisDataTestInput;
 };
 
 /*! \libinternal \brief
  * Represents static input data for AbstractAnalysisData tests.
  *
- * Used to construct structured test input data from a static array of reals,
- * and then typically used as input to methods in AnalysisDataTestFixture.
+ * Used to construct structured test input data for analysis data unit tests.
+ * Typically used as input to methods in AnalysisDataTestFixture.
  *
  * \see AnalysisDataTestFixture
  *
+ * \inlibraryapi
  * \ingroup module_analysisdata
  */
 class AnalysisDataTestInput
 {
     public:
         /*! \brief
-         * Constructs data representation from a simple array.
+         * Constructs empty input data.
          *
-         * \param[in] data  Array to construct data from.
+         * \param[in] dataSetCount Number of data sets in the data.
+         * \param[in] bMultipoint  Whether the data will be multipoint.
          *
-         * The input array should consist of a set of frames, separated by a
-         * END_OF_FRAME marker.  The first value for a frame is the X value,
-         * all following values are Y values.
-         * For multipoint data, one frame can contain several point sets,
-         * separated by MPSTOP markers.  There should be no MPSTOP marker after
-         * the last point set, only an END_OF_FRAME marker.  All point sets are
-         * assumed to start from column zero, but the sets may contain
-         * different number of columns.  For non-multipoint data, all frames
-         * must containt the same number of columns.
-         * The final element in the array (after the last END_OF_FRAME) should
-         * be END_OF_DATA.
+         * The column count for each data set must be set with
+         * setColumnCount().
          */
-        explicit AnalysisDataTestInput(const real *data);
+        AnalysisDataTestInput(int dataSetCount, bool bMultipoint);
         ~AnalysisDataTestInput();
 
-        //! Returns the number of frames in the input data.
-        int frameCount() const { return frames_.size(); }
-        //! Returns the number of columns in the input data.
-        int columnCount() const { return columnCount_; }
         //! Whether the input data is multipoint.
         bool isMultipoint() const { return bMultipoint_; }
+        //! Returns the number of data sets in the input data.
+        int dataSetCount() const { return columnCounts_.size(); }
+        //! Returns the number of columns in a given data set.
+        int columnCount(int dataSet) const { return columnCounts_[dataSet]; }
+        //! Returns the number of frames in the input data.
+        int frameCount() const { return frames_.size(); }
         //! Returns a frame object for the given input frame.
         const AnalysisDataTestInputFrame &frame(int index) const;
 
+        //! Sets the number of columns in a data set.
+        void setColumnCount(int dataSet, int columnCount);
+        //! Appends an empty frame to this data.
+        AnalysisDataTestInputFrame &addFrame(real x);
+        //! Adds a frame with a single point set and the given values.
+        void addFrameWithValues(real x, real y1);
+        //! Adds a frame with a single point set and the given values.
+        void addFrameWithValues(real x, real y1, real y2);
+        //! Adds a frame with a single point set and the given values.
+        void addFrameWithValues(real x, real y1, real y2, real y3);
+        //! Adds a frame with a single point set and the given values.
+        void addFrameWithValueAndError(real x, real y1, real e1);
+
     private:
-        int                     columnCount_;
-        bool                    bMultipoint_;
+        std::vector<int>                        columnCounts_;
+        bool                                    bMultipoint_;
         std::vector<AnalysisDataTestInputFrame> frames_;
 };
 
@@ -211,16 +281,17 @@ class AnalysisDataTestInput
  *
  * presentAllData() and presentDataFrame() are provided to push data from an
  * AnalysisDataTestInput into an AnalysisData object.  In typical tests, most
- * checks are done during the these methods, by the added mock modules.
+ * checks are done during these methods, by the added mock modules.
  * setupArrayData() performs the same function for classes derived from
  * AbstractAnalysisArrayData.  In that case, the test should separately ensure
  * that AbstractAnalysisArrayData::valuesReady() gets called.
  *
  * \todo
- * Support for errors and for arbitrary multipoint data.
+ * Support for arbitrary AnalysisDataValues (errors and missing values).
  *
  * \see AnalysisDataTestInput
  *
+ * \inlibraryapi
  * \ingroup module_analysisdata
  */
 class AnalysisDataTestFixture : public ::testing::Test
@@ -228,11 +299,19 @@ class AnalysisDataTestFixture : public ::testing::Test
     public:
         AnalysisDataTestFixture();
 
+        /*! \brief
+         * Initializes an AnalysisData object from input data.
+         *
+         * Sets the column count and other properties based on the input data.
+         */
+        static void setupDataObject(const AnalysisDataTestInput &input,
+                                    AnalysisData                *data);
+
         /*! \brief
          * Adds all data from AnalysisDataTestInput into an AnalysisData.
          */
         static void presentAllData(const AnalysisDataTestInput &input,
-                                   AnalysisData *data);
+                                   AnalysisData                *data);
         /*! \brief
          * Adds a single frame from AnalysisDataTestInput into an AnalysisData.
          */
@@ -255,7 +334,7 @@ class AnalysisDataTestFixture : public ::testing::Test
          */
         template <class ArrayData>
         static void setupArrayData(const AnalysisDataTestInput &input,
-                                   ArrayData *data);
+                                   ArrayData                   *data);
 
         /*! \brief
          * Adds a mock module that verifies output against
@@ -274,7 +353,30 @@ class AnalysisDataTestFixture : public ::testing::Test
          * \see AbstractAnalysisData::addModule()
          */
         static void addStaticCheckerModule(const AnalysisDataTestInput &data,
-                                           AbstractAnalysisData *source);
+                                           AbstractAnalysisData        *source);
+        /*! \brief
+         * Adds a mock module that verifies parallel output against
+         * AnalysisDataTestInput.
+         *
+         * \param[in]  data     Data to compare against.
+         * \param      source   Data object to verify.
+         *
+         * Creates a parallel mock module that verifies that the
+         * AnalysisDataModuleInterface methods are called correctly by
+         * \p source.  Parameters for the calls are verified against \p data.
+         * Adds the created module to \p source using \p data->addModule().
+         * Any exceptions from the called functions should be caught by the
+         * caller.
+         *
+         * Differs from addStaticCheckerModule() in that the created mock
+         * module reports that it accepts parallel input data, and accepts and
+         * verifies notification calls following the parallel pattern.
+         *
+         * \see AbstractAnalysisData::addModule()
+         */
+        static void addStaticParallelCheckerModule(
+            const AnalysisDataTestInput &data,
+            AbstractAnalysisData        *source);
         /*! \brief
          * Adds a column mock module that verifies output against
          * AnalysisDataTestInput.
@@ -314,26 +416,30 @@ class AnalysisDataTestFixture : public ::testing::Test
          * the parameter.
          */
         static void addStaticStorageCheckerModule(const AnalysisDataTestInput &data,
-                                                  int storageCount,
-                                                  AbstractAnalysisData *source);
+                                                  int                          storageCount,
+                                                  AbstractAnalysisData        *source);
         /*! \brief
          * Adds a mock module that verifies output against reference data.
          *
-         * \param[in]  checker  Reference data checker to use for comparison.
-         * \param      source   Data object to verify.
+         * \param[in]  checker   Reference data checker to use for comparison.
+         * \param[in]  id        Identifier for reference data compound to use.
+         * \param      source    Data object to verify.
+         * \param[in]  tolerance Tolerance to use for comparison.
          *
          * Creates a mock module that verifies that the
          * AnalysisDataModuleInterface methods are called correctly by
          * \p source.  Parameters for the calls are verified against reference
-         * data using \p checker.
+         * data using a child compound \p id of \p checker.
          * Adds the created module to \p source using \p data->addModule().
          * Any exceptions from the called functions should be caught by the
          * caller.
          *
          * \see TestReferenceData
          */
-        static void addReferenceCheckerModule(const TestReferenceChecker &checker,
-                                              AbstractAnalysisData *source);
+        static void addReferenceCheckerModule(TestReferenceChecker          checker,
+                                              const char                   *id,
+                                              AbstractAnalysisData         *source,
+                                              const FloatingPointTolerance &tolerance);
 
         /*! \brief
          * Adds a mock module that verifies output against reference data.
@@ -346,7 +452,7 @@ class AnalysisDataTestFixture : public ::testing::Test
          *
          * See the static overload for other details.
          */
-        void addReferenceCheckerModule(const char *id,
+        void addReferenceCheckerModule(const char           *id,
                                        AbstractAnalysisData *source);
 
     protected:
@@ -361,25 +467,29 @@ class AnalysisDataTestFixture : public ::testing::Test
 
 template <class ArrayData>
 void AnalysisDataTestFixture::setupArrayData(const AnalysisDataTestInput &input,
-                                             ArrayData *data)
+                                             ArrayData                   *data)
 {
     GMX_RELEASE_ASSERT(!input.isMultipoint(),
                        "Array data cannot be initialized from multipoint data");
-    GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(),
+    GMX_RELEASE_ASSERT(input.dataSetCount() == 1,
+                       "Array data cannot be initialized from multiple data sets");
+    GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(0),
                        "Mismatching input and target data");
     GMX_RELEASE_ASSERT(data->rowCount() == 0 || data->rowCount() == input.frameCount(),
                        "Mismatching input and target data");
-    data->setColumnCount(input.columnCount());
+    data->setColumnCount(input.columnCount(0));
     data->setRowCount(input.frameCount());
     data->allocateValues();
     for (int row = 0; row < input.frameCount(); ++row)
     {
-        const AnalysisDataTestInputFrame &frame = input.frame(row);
+        const AnalysisDataTestInputFrame    &frame = input.frame(row);
         EXPECT_FLOAT_EQ(frame.x(), data->xvalue(row));
-        const AnalysisDataTestInputPointSet &points = frame.points();
-        for (int column = 0; column < input.columnCount(); ++column)
+        GMX_RELEASE_ASSERT(frame.pointSetCount() == 1,
+                           "Multiple point sets not supported by array data");
+        const AnalysisDataTestInputPointSet &points = frame.pointSet(0);
+        for (int column = 0; column < points.size(); ++column)
         {
-            data->setValue(row, column, points.y(column));
+            data->value(row, column + points.firstColumn()) = points.value(column);
         }
     }
 }