3990584c16e5581df9e8c67d2b908026e005a204
[alexxy/gromacs.git] / src / gromacs / math / tests / arrayrefwithpadding.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2018,2019,2020, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief Tests for gmx::ArrayRefWithPadding.
37  *
38  * \author Mark Abraham <mark.j.abraham@gmail.com>
39  * \ingroup module_math
40  */
41 #include "gmxpre.h"
42
43 #include "gromacs/math/arrayrefwithpadding.h"
44
45 #include <vector>
46
47 #include <gtest/gtest.h>
48
49 #include "gromacs/math/paddedvector.h"
50 #include "gromacs/utility/arrayref.h"
51 #include "gromacs/utility/basedefinitions.h"
52 #include "gromacs/utility/real.h"
53
54 namespace gmx
55 {
56
57 namespace
58 {
59
60 TEST(EmptyArrayRefWithPaddingTest, IsEmpty)
61 {
62     ArrayRefWithPadding<real> empty;
63
64     EXPECT_EQ(0U, empty.size());
65     EXPECT_TRUE(empty.empty());
66 }
67
68 TEST(EmptyConstArrayRefWithPaddingTest, IsEmpty)
69 {
70     ArrayRefWithPadding<const real> empty;
71
72     EXPECT_EQ(0U, empty.size());
73     EXPECT_TRUE(empty.empty());
74 }
75
76 #ifdef GTEST_HAS_TYPED_TEST
77
78 //! Define the types that end up being available as TypeParam in the test cases for both kinds of ArrayRefWithPadding
79 typedef ::testing::Types<ArrayRefWithPadding<int32_t>, ArrayRefWithPadding<float>, ArrayRefWithPadding<double>> ArrayRefTypes;
80
81 //! Helper constant used in the text fixture.
82 constexpr index aSize = 3;
83
84 /*! \brief Permit all the tests to run on all kinds of ArrayRefWithPadding types
85  *
86  * The main objective is to verify that all the different kinds of
87  * construction lead to the expected result. */
88 template<typename TypeParam>
89 class ArrayRefWithPaddingTest : public ::testing::Test
90 {
91 public:
92     typedef TypeParam                         ArrayRefType;
93     typedef typename ArrayRefType::value_type ValueType;
94     typedef PaddedVector<ValueType>           PaddedVectorType;
95
96     ValueType        a[aSize] = { ValueType(1.2), ValueType(2.4), ValueType(3.1) };
97     PaddedVectorType v;
98
99     //! Constructor, which prepares a padded vector to take array ref of.
100     ArrayRefWithPaddingTest() : v(aSize) { std::copy(a, a + aSize, v.begin()); }
101
102     /*! \brief Run the same tests all the time
103      *
104      * Note that test cases must call this->runTests(), because
105      * that's how the derived-class templates that implement
106      * type-parameterized tests actually work. */
107     void runTests(ArrayRefType& arrayRefWithPadding)
108     {
109         ASSERT_LE(aSize, arrayRefWithPadding.size());
110         ASSERT_FALSE(arrayRefWithPadding.empty());
111         auto unpaddedArrayRef = arrayRefWithPadding.unpaddedArrayRef();
112         auto paddedArrayRef   = arrayRefWithPadding.paddedArrayRef();
113         EXPECT_LE(unpaddedArrayRef.size(), paddedArrayRef.size());
114         for (index i = 0; i != aSize; ++i)
115         {
116             EXPECT_EQ(paddedArrayRef[i], unpaddedArrayRef[i]);
117             EXPECT_EQ(a[i], unpaddedArrayRef[i]);
118         }
119
120         using ConstArrayRefWithPaddingType = ArrayRefWithPadding<const typename ArrayRefType::value_type>;
121         {
122             // Check that we can make a padded view that refers to const elements
123             ConstArrayRefWithPaddingType constArrayRefWithPadding =
124                     arrayRefWithPadding.constArrayRefWithPadding();
125             for (index i = 0; i != aSize; ++i)
126             {
127                 EXPECT_EQ(a[i], constArrayRefWithPadding.paddedArrayRef()[i]);
128             }
129         }
130
131         {
132             // Check that we can implicitly make a padded view that refers to const elements
133             ConstArrayRefWithPaddingType constArrayRefWithPadding = arrayRefWithPadding;
134             for (index i = 0; i != aSize; ++i)
135             {
136                 EXPECT_EQ(a[i], constArrayRefWithPadding.paddedArrayRef()[i]);
137             }
138         }
139
140         {
141             // Check that a swap works, by making an empty padded
142             // vector, and a view of it, and observing what
143             // happens when we swap with the one constructed for
144             // the test.
145             PaddedVectorType w;
146             ArrayRefType     view = w.arrayRefWithPadding();
147             EXPECT_TRUE(view.empty());
148
149             view.swap(arrayRefWithPadding);
150             EXPECT_TRUE(arrayRefWithPadding.empty());
151             EXPECT_LE(aSize, view.size());
152             for (index i = 0; i != v.size(); ++i)
153             {
154                 EXPECT_EQ(v[i], view.paddedArrayRef()[i]);
155             }
156             // Restore arrayRefWithPadding for future test code
157             view.swap(arrayRefWithPadding);
158         }
159     }
160 };
161
162 TYPED_TEST_CASE(ArrayRefWithPaddingTest, ArrayRefTypes);
163
164
165 TYPED_TEST(ArrayRefWithPaddingTest, AssignFromPaddedVectorWorks)
166 {
167     typename TestFixture::ArrayRefType arrayRef = this->v.arrayRefWithPadding();
168     this->runTests(arrayRef);
169 }
170
171 TYPED_TEST(ArrayRefWithPaddingTest, ConstructFromPointersWorks)
172 {
173     typename TestFixture::ArrayRefType arrayRef(
174             this->v.data(), this->v.data() + this->v.size(), this->v.data() + this->v.paddedSize());
175     this->runTests(arrayRef);
176 }
177
178 template<bool c, typename T>
179 using makeConstIf_t = std::conditional_t<c, const T, T>;
180
181 //! Helper struct for the case actually used in mdrun signalling
182 template<typename T>
183 struct Helper
184 {
185 public:
186     T   a[3];
187     int size;
188 };
189
190 #else // GTEST_HAS_TYPED_TEST
191
192 /* A dummy test that at least signals that something is missing if one runs the
193  * unit test executable itself.
194  */
195 TEST(DISABLED_ArrayRefWithPaddingTest, GenericTests)
196 {
197     ADD_FAILURE() << "Tests for generic ArrayRefWithPadding functionality require support for "
198                   << "Google Test typed tests, which was not available when the tests "
199                   << "were compiled.";
200 }
201
202 #endif // GTEST_HAS_TYPED_TEST
203
204 } // namespace
205
206 } // namespace gmx