8010006f33119cd85f1db7da33138215993c21a7
[alexxy/gromacs.git] / src / gromacs / utility / tests / arrayref.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2015,2016,2017,2018,2019, The GROMACS development team.
5  * Copyright (c) 2020,2021, 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 Tests for gmx::ArrayRef.
38  *
39  * \author Mark Abraham <mark.j.abraham@gmail.com>
40  * \ingroup module_utility
41  */
42 #include "gmxpre.h"
43
44 #include "gromacs/utility/arrayref.h"
45
46 #include <vector>
47
48 #include <gtest/gtest.h>
49
50 #include "testutils/testasserts.h"
51
52 #include "gromacs/utility/basedefinitions.h"
53 #include "gromacs/utility/real.h"
54
55 namespace gmx
56 {
57
58 namespace
59 {
60
61 TEST(EmptyArrayRefTest, IsEmpty)
62 {
63     ArrayRef<real> empty;
64
65     EXPECT_EQ(0U, empty.size());
66     EXPECT_TRUE(empty.empty());
67     EXPECT_EQ(empty.data(), nullptr);
68 }
69
70 TEST(EmptyArrayRefTest, ConstructFromNullptrIsEmpty)
71 {
72     ArrayRef<real> empty(nullptr, nullptr);
73     EXPECT_EQ(0U, empty.size());
74     EXPECT_TRUE(empty.empty());
75     EXPECT_EQ(empty.data(), nullptr);
76 }
77
78 TEST(EmptyConstArrayRefTest, IsEmpty)
79 {
80     ArrayRef<const real> empty;
81
82     EXPECT_EQ(0U, empty.size());
83     EXPECT_TRUE(empty.empty());
84     EXPECT_EQ(empty.data(), nullptr);
85 }
86
87 #if !defined(NDEBUG)
88
89 TEST(EmptyArrayRefDeathTest, AssertOnBadPointers)
90 {
91     real random = 5;
92     GMX_EXPECT_DEATH_IF_SUPPORTED(ArrayRef<real> empty(nullptr, &random),
93                                   "If begin is nullptr, end needs to be nullptr as well");
94 }
95
96 TEST(EmptyArrayRefDeathTest, AssertOnBadIterators)
97 {
98     std::vector<real> random = { 5 };
99     GMX_EXPECT_DEATH_IF_SUPPORTED(ArrayRef<real> empty(gmx::ArrayRefIter<real>{},
100                                                        gmx::ArrayRefIter<real>{ &*random.begin() }),
101                                   "If begin is nullptr, end needs to be nullptr as well");
102 }
103
104 #else
105
106 TEST(DISABLED_ArrayRefDeathTest, GenericTests)
107 {
108     ADD_FAILURE() << "Tests for proper assertion triggering only works with assertions enabled.";
109 }
110
111 #endif
112
113 TEST(EmptyArrayRefTest, arrayRefFromArrayIsEmptyForNullptr)
114 {
115     ArrayRef<real> empty = arrayRefFromArray<real>(nullptr, 1234);
116     EXPECT_EQ(0U, empty.size());
117     EXPECT_TRUE(empty.empty());
118     EXPECT_EQ(empty.data(), nullptr);
119 }
120
121 TEST(EmptyArrayRefTest, arrayRefFromArrayIsEmptyForSizeNull)
122 {
123     real           random = 5;
124     ArrayRef<real> empty  = arrayRefFromArray<real>(&random, 0);
125     EXPECT_EQ(0U, empty.size());
126     EXPECT_TRUE(empty.empty());
127     EXPECT_EQ(empty.data(), &random);
128 }
129
130 #ifdef GTEST_HAS_TYPED_TEST
131
132 //! Define the types that end up being available as TypeParam in the test cases for both kinds of ArrayRef
133 typedef ::testing::Types<ArrayRef<char>,
134                          ArrayRef<unsigned char>,
135                          ArrayRef<int>,
136                          ArrayRef<unsigned int>,
137                          ArrayRef<long>,
138                          ArrayRef<unsigned long>,
139                          ArrayRef<int64_t>,
140                          ArrayRef<uint64_t>,
141                          ArrayRef<float>,
142                          ArrayRef<double>,
143                          ArrayRef<const char>,
144                          ArrayRef<const unsigned char>,
145                          ArrayRef<const int>,
146                          ArrayRef<const unsigned int>,
147                          ArrayRef<const long>,
148                          ArrayRef<const unsigned long>,
149                          ArrayRef<const int64_t>,
150                          ArrayRef<const uint64_t>,
151                          ArrayRef<const float>,
152                          ArrayRef<const double>>
153         ArrayRefTypes;
154
155 constexpr index aSize = 3;
156
157 /*! \brief Permit all the tests to run on all kinds of ArrayRefs
158  *
159  * The main objective is to verify that all the different kinds of
160  * construction lead to the expected result. */
161 template<typename TypeParam>
162 class ArrayRefTest : public ::testing::Test
163 {
164 public:
165     typedef TypeParam                         ArrayRefType;
166     typedef typename ArrayRefType::value_type ValueType;
167     typedef std::remove_const_t<ValueType>    NonConstValueType;
168
169     /*! \brief Run the same tests all the time
170      *
171      * Note that test cases must call this->runTests(), because
172      * that's how the derived-class templates that implement
173      * type-parameterized tests actually work. */
174     void runTests(ValueType* aData, ArrayRefType& arrayRef)
175     {
176         ASSERT_EQ(aSize, arrayRef.size());
177         ASSERT_FALSE(arrayRef.empty());
178         EXPECT_EQ(aData, arrayRef.data());
179         EXPECT_EQ(a[0], arrayRef.front());
180         EXPECT_EQ(a[aSize - 1], arrayRef.back());
181         for (index i = 0; i != aSize; ++i)
182         {
183             EXPECT_EQ(a[i], arrayRef[i]);
184         }
185     }
186
187     ValueType         a[aSize]  = { ValueType(1.2), ValueType(2.4), ValueType(3.1) };
188     NonConstValueType ma[aSize] = { ValueType(1.2), ValueType(2.4), ValueType(3.1) };
189 };
190
191 TYPED_TEST_CASE(ArrayRefTest, ArrayRefTypes);
192
193
194 TYPED_TEST(ArrayRefTest, MakeWithAssignmentWorks)
195 {
196     typename TestFixture::ArrayRefType arrayRef = this->a;
197     this->runTests(this->a, arrayRef);
198 }
199
200 TYPED_TEST(ArrayRefTest, MakeWithNonConstAssignmentWorks)
201 {
202     typename TestFixture::ArrayRefType arrayRef = this->ma;
203     this->runTests(this->ma, arrayRef);
204 }
205
206 TYPED_TEST(ArrayRefTest, ConstructWithTemplateConstructorWorks)
207 {
208     typename TestFixture::ArrayRefType arrayRef(this->a);
209     this->runTests(this->a, arrayRef);
210 }
211
212 TYPED_TEST(ArrayRefTest, ConstructWithNonConstTemplateConstructorWorks)
213 {
214     typename TestFixture::ArrayRefType arrayRef(this->ma);
215     this->runTests(this->ma, arrayRef);
216 }
217
218 TYPED_TEST(ArrayRefTest, ConstructFromPointersWorks)
219 {
220     typename TestFixture::ArrayRefType arrayRef(this->a, this->a + aSize);
221     this->runTests(this->a, arrayRef);
222 }
223
224 TYPED_TEST(ArrayRefTest, ConstructFromNonConstPointersWorks)
225 {
226     typename TestFixture::ArrayRefType arrayRef(this->ma, this->ma + aSize);
227     this->runTests(this->ma, arrayRef);
228 }
229
230 template<bool c, typename T>
231 using makeConstIf_t = std::conditional_t<c, const T, T>;
232
233 TYPED_TEST(ArrayRefTest, ConstructFromVectorWorks)
234 {
235     makeConstIf_t<std::is_const_v<typename TestFixture::ValueType>, std::vector<typename TestFixture::NonConstValueType>> v(
236             this->a, this->a + aSize);
237     typename TestFixture::ArrayRefType arrayRef(v);
238     this->runTests(v.data(), arrayRef);
239 }
240
241 TYPED_TEST(ArrayRefTest, ConstructFromNonConstVectorWorks)
242 {
243     std::vector<typename TestFixture::NonConstValueType> v(this->a, this->a + aSize);
244     typename TestFixture::ArrayRefType                   arrayRef(v);
245     this->runTests(v.data(), arrayRef);
246 }
247
248 //! Helper struct for the case actually used in mdrun signalling
249 template<typename T>
250 struct Helper
251 {
252 public:
253     T   a[3];
254     int size;
255 };
256
257 /*! \brief Test of the case actually used in mdrun signalling
258  *
259  * There, we take a non-const struct-field array of static length and
260  * make an ArrayRef to it using the template constructor that is
261  * supposed to infer the length from the static size. This has
262  * been a problem (for a compiler that we no longer support),
263  * so we test it.
264  */
265
266 TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
267 {
268     Helper<typename TestFixture::NonConstValueType> h;
269     h.size = aSize;
270     for (int i = 0; i != h.size; ++i)
271     {
272         h.a[i] = this->a[i];
273     }
274     typename TestFixture::ArrayRefType arrayRef(h.a);
275     this->runTests(h.a, arrayRef);
276 }
277
278 #else // GTEST_HAS_TYPED_TEST
279
280 /* A dummy test that at least signals that something is missing if one runs the
281  * unit test executable itself.
282  */
283 TEST(DISABLED_ArrayRefTest, GenericTests)
284 {
285     ADD_FAILURE() << "Tests for generic ArrayRef functionality require support for "
286                   << "Google Test typed tests, which was not available when the tests "
287                   << "were compiled.";
288 }
289
290 #endif // GTEST_HAS_TYPED_TEST
291
292 } // namespace
293
294 } // namespace gmx