Enable clang tidy/warnings for tests
[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, 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::ArrayRef.
37  *
38  * \author Mark Abraham <mark.j.abraham@gmail.com>
39  * \ingroup module_utility
40  */
41 #include "gmxpre.h"
42
43 #include "gromacs/utility/arrayref.h"
44
45 #include <vector>
46
47 #include <gtest/gtest.h>
48
49 #include "gromacs/utility/basedefinitions.h"
50 #include "gromacs/utility/real.h"
51
52 namespace gmx
53 {
54
55 namespace
56 {
57
58 TEST(EmptyArrayRefTest, IsEmpty)
59 {
60     EmptyArrayRef  emptyArray = {};
61     ArrayRef<real> empty(emptyArray);
62
63     EXPECT_EQ(0U, empty.size());
64     EXPECT_TRUE(empty.empty());
65 }
66
67 TEST(EmptyConstArrayRefTest, IsEmpty)
68 {
69     EmptyArrayRef        emptyArray = {};
70     ArrayRef<const real> empty(emptyArray);
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 ArrayRef
79 typedef ::testing::Types<
80         ArrayRef<char>,
81         ArrayRef<unsigned char>,
82         ArrayRef<int>,
83         ArrayRef<unsigned int>,
84         ArrayRef<long>,
85         ArrayRef<unsigned long>,
86         ArrayRef<int64_t>,
87         ArrayRef<uint64_t>,
88         ArrayRef<float>,
89         ArrayRef<double>,
90         ArrayRef<const char>,
91         ArrayRef<const unsigned char>,
92         ArrayRef<const int>,
93         ArrayRef<const unsigned int>,
94         ArrayRef<const long>,
95         ArrayRef<const unsigned long>,
96         ArrayRef<const int64_t>,
97         ArrayRef<const uint64_t>,
98         ArrayRef<const float>,
99         ArrayRef<const double>
100         > ArrayRefTypes;
101
102 /*! \brief Permit all the tests to run on all kinds of ArrayRefs
103  *
104  * The main objective is to verify that all the different kinds of
105  * construction lead to the expected result. */
106 template <typename TypeParam>
107 class ArrayRefTest : public ::testing::Test
108 {
109     public:
110         typedef TypeParam ArrayRefType;
111         typedef typename ArrayRefType::value_type ValueType;
112         typedef typename std::remove_const<ValueType>::type NonConstValueType;
113
114         /*! \brief Run the same tests all the time
115          *
116          * Note that test cases must call this->runTests(), because
117          * that's how the derived-class templates that implement
118          * type-parameterized tests actually work. */
119         void runTests(ValueType     *a,
120                       size_t         aSize,
121                       ValueType     *aData,
122                       ArrayRefType  &arrayRef)
123         {
124             ASSERT_EQ(aSize, arrayRef.size());
125             ASSERT_FALSE(arrayRef.empty());
126             EXPECT_EQ(aData, arrayRef.data());
127             EXPECT_EQ(a[0], arrayRef.front());
128             EXPECT_EQ(a[aSize-1], arrayRef.back());
129             for (size_t i = 0; i != aSize; ++i)
130             {
131                 EXPECT_EQ(a[i], arrayRef[i]);
132             }
133         }
134 };
135
136 TYPED_TEST_CASE(ArrayRefTest, ArrayRefTypes);
137
138 /* Welcome back to the past. While you can declare a static array[] of
139    templated type in a class, in C++98, you have to define it outside
140    the class, and when you do, the compiler knows the declaration is
141    incomplete and can't match the types to actual functions. So,
142    declaring locals is the only choice available, so we need macros to
143    avoid duplication. Lovely. */
144 #define DEFINE_ARRAY(a, aSize)                                  \
145     typename TestFixture::ValueType (a)[] = {                   \
146         static_cast<typename TestFixture::ValueType>(1.2),      \
147         static_cast<typename TestFixture::ValueType>(2.4),      \
148         static_cast<typename TestFixture::ValueType>(3.1)       \
149     };                                                          \
150     size_t aSize = sizeof((a)) / sizeof(typename TestFixture::ValueType);
151
152 #define DEFINE_NON_CONST_ARRAY(a, aSize)                        \
153     typename TestFixture::NonConstValueType (a)[] = {           \
154         static_cast<typename TestFixture::ValueType>(1.2),      \
155         static_cast<typename TestFixture::ValueType>(2.4),      \
156         static_cast<typename TestFixture::ValueType>(3.1)       \
157     };                                                          \
158     size_t aSize = sizeof((a)) / sizeof(typename TestFixture::ValueType);
159
160
161 TYPED_TEST(ArrayRefTest, MakeWithAssignmentWorks)
162 {
163     DEFINE_ARRAY(a, aSize);
164     typename TestFixture::ArrayRefType arrayRef = a;
165     this->runTests(a, aSize, a, arrayRef);
166 }
167
168 TYPED_TEST(ArrayRefTest, MakeWithNonConstAssignmentWorks)
169 {
170     DEFINE_NON_CONST_ARRAY(a, aSize);
171     typename TestFixture::ArrayRefType arrayRef = a;
172     this->runTests(a, aSize, a, arrayRef);
173 }
174
175 TYPED_TEST(ArrayRefTest, ConstructWithTemplateConstructorWorks)
176 {
177     DEFINE_ARRAY(a, aSize);
178     typename TestFixture::ArrayRefType arrayRef(a);
179     this->runTests(a, aSize, a, arrayRef);
180 }
181
182 TYPED_TEST(ArrayRefTest, ConstructWithNonConstTemplateConstructorWorks)
183 {
184     DEFINE_NON_CONST_ARRAY(a, aSize);
185     typename TestFixture::ArrayRefType arrayRef(a);
186     this->runTests(a, aSize, a, arrayRef);
187 }
188
189 TYPED_TEST(ArrayRefTest, ConstructFromPointersWorks)
190 {
191     DEFINE_ARRAY(a, aSize);
192     typename TestFixture::ArrayRefType arrayRef(a, a + aSize);
193     this->runTests(a, aSize, a, arrayRef);
194 }
195
196 TYPED_TEST(ArrayRefTest, ConstructFromNonConstPointersWorks)
197 {
198     DEFINE_NON_CONST_ARRAY(a, aSize);
199     typename TestFixture::ArrayRefType arrayRef(a, a + aSize);
200     this->runTests(a, aSize, a, arrayRef);
201 }
202
203 template<bool c, typename T>
204 using makeConstIf_t = typename std::conditional<c, const T, T>::type;
205
206 TYPED_TEST(ArrayRefTest, ConstructFromVectorWorks)
207 {
208     DEFINE_ARRAY(a, aSize);
209     makeConstIf_t<std::is_const<typename TestFixture::ValueType>::value,
210                   std::vector<typename TestFixture::NonConstValueType> > v(a, a + aSize);
211     typename TestFixture::ArrayRefType                                   arrayRef(v);
212     this->runTests(a, aSize, v.data(), arrayRef);
213 }
214
215 TYPED_TEST(ArrayRefTest, ConstructFromNonConstVectorWorks)
216 {
217     DEFINE_ARRAY(a, aSize);
218     std::vector<typename TestFixture::NonConstValueType> v(a, a + aSize);
219     typename TestFixture::ArrayRefType                   arrayRef(v);
220     this->runTests(a, aSize, v.data(), arrayRef);
221 }
222
223 //! Helper struct for the case actually used in mdrun signalling
224 template <typename T>
225 struct Helper
226 {
227     public:
228         T   a[3];
229         int size;
230 };
231
232 /*! \brief Test of the case actually used in mdrun signalling
233  *
234  * There, we take a non-const struct-field array of static length and
235  * make an ArrayRef to it using the template constructor that is
236  * supposed to infer the length from the static size. This has
237  * been a problem (for a compiler that we no longer support),
238  * so we test it.
239  */
240
241 TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
242 {
243     DEFINE_ARRAY(a, aSize);
244     Helper<typename TestFixture::NonConstValueType> h;
245     h.size = aSize;
246     for (int i = 0; i != h.size; ++i)
247     {
248         h.a[i] = a[i];
249     }
250     typename TestFixture::ArrayRefType arrayRef(h.a);
251     this->runTests(h.a, h.size, h.a, arrayRef);
252 }
253
254 #else   // GTEST_HAS_TYPED_TEST
255
256 /* A dummy test that at least signals that something is missing if one runs the
257  * unit test executable itself.
258  */
259 TEST(DISABLED_ArrayRefTest, GenericTests)
260 {
261     ADD_FAILURE()
262     << "Tests for generic ArrayRef functionality require support for "
263     << "Google Test typed tests, which was not available when the tests "
264     << "were compiled.";
265 }
266
267 #endif // GTEST_HAS_TYPED_TEST
268
269 }      // namespace
270
271 }      // namespace