go home Home | Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Globals | Related Pages
elxCoreMainGTestUtilities.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright UMC Utrecht and contributors
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18
19#ifndef elxCoreMainGTestUtilities_h
20#define elxCoreMainGTestUtilities_h
21
22#include <elxBaseComponent.h> // For elx.
23#include <elxParameterObject.h>
24
25#include <itkImage.h>
26#include <itkImageBufferRange.h>
27#include <itkImageRegionRange.h>
28#include <itkIndex.h>
29#include <itkSize.h>
30
31#include <algorithm> // For fill and transform.
32#include <array>
33#include <cmath> // For round.
34#include <initializer_list>
35#include <iterator> // For begin and end.
36#include <map>
37#include <numeric> // For iota.
38#include <string>
39#include <type_traits> // For is_pointer, is_same, and integral_constant.
40#include <vector>
41
42// GoogleTest header file:
43#include <gtest/gtest.h>
44
45
46namespace elastix
47{
48namespace CoreMainGTestUtilities
49{
50
52class Exception : public std::exception
53{
54 const char * m_message = "";
55
56public:
57 explicit Exception(const char * const message)
58 : m_message(message)
59 {}
60
61 const char *
62 what() const noexcept override
63 {
64 return m_message;
65 }
66};
67
68
70#define ELX_GTEST_EXPECT_FALSE_AND_THROW_EXCEPTION_IF(condition) \
71 if (condition) \
72 { \
73 EXPECT_FALSE(true) << "Expected to be false: " #condition; \
74 throw ::elastix::CoreMainGTestUtilities::Exception("Exception thrown because " #condition); \
75 } \
76 static_assert(true, "Expect a semi-colon ';' at the end of a macro call")
77
79template <typename TRawPointer>
80decltype(auto)
81Deref(const TRawPointer ptr)
82{
83 static_assert(std::is_pointer<TRawPointer>::value, "For smart pointers, use DerefSmartPointer instead!");
84
85 if (ptr == nullptr)
86 {
87 throw Exception("Deref error: the pointer should not be null!");
88 }
89 return *ptr;
90}
91
92
93template <typename TSmartPointer>
94decltype(auto)
95DerefSmartPointer(const TSmartPointer & ptr)
96{
97 static_assert(!std::is_pointer<TSmartPointer>::value, "For raw pointers, use Deref instead!");
98
99 if (ptr == nullptr)
100 {
101 throw Exception("Deref error: the (smart) pointer should not be null!");
102 }
103 return *ptr;
104}
105
106
109template <typename T>
110decltype(T().front())
111Front(T & container)
112{
113 if (container.empty())
114 {
115 throw Exception("Front error: the container should be non-empty!");
116 }
117 return container.front();
118}
119
120
121template <typename T>
122itk::SmartPointer<T>
124{
125 static_assert(std::is_same<decltype(T::New()), itk::SmartPointer<T>>{},
126 "T::New() must return an itk::SmartPointer<T>!");
127
128 const auto ptr = T::New();
129 if (ptr == nullptr)
130 {
131 throw Exception("New() error: should not return null!");
132 }
133 return ptr;
134}
135
137template <typename TPixel, unsigned int VImageDimension>
138void
139FillImageRegion(itk::Image<TPixel, VImageDimension> & image,
140 const itk::Index<VImageDimension> & regionIndex,
141 const itk::Size<VImageDimension> & regionSize)
142{
143 const itk::ImageRegionRange<itk::Image<TPixel, VImageDimension>> imageRegionRange{
144 image, itk::ImageRegion<VImageDimension>{ regionIndex, regionSize }
145 };
146 std::fill(std::begin(imageRegionRange), std::end(imageRegionRange), 1);
147}
148
149
150// Converts the specified strings to a vector of double.
151// Assumes that each string represents a floating point number.
152inline std::vector<double>
153ConvertStringsToVectorOfDouble(const std::vector<std::string> & strings)
154{
155 std::vector<double> result(strings.size());
156
157 std::transform(strings.cbegin(), strings.cend(), result.begin(), [](const std::string & str) {
158 std::size_t index{};
159 const auto result = std::stod(str, &index);
160
161 // Test that all characters have been processed, by std::stod.
162 EXPECT_EQ(index, str.size());
163 return result;
164 });
165
166 return result;
167}
168
169
170// Converts the specified vector of double to itk::Offset, by rounding each element.
171template <std::size_t VDimension>
172itk::Offset<VDimension>
173ConvertToOffset(const std::vector<double> & doubles)
174{
175 ELX_GTEST_EXPECT_FALSE_AND_THROW_EXCEPTION_IF(doubles.size() != VDimension);
176
177 itk::Offset<VDimension> result;
178 std::size_t i{};
179
180 for (const double value : doubles)
181 {
182 const auto roundedValue = std::round(value);
183
184 EXPECT_GE(roundedValue, std::numeric_limits<itk::OffsetValueType>::min());
185 EXPECT_LE(roundedValue, std::numeric_limits<itk::OffsetValueType>::max());
186
187 result[i] = static_cast<itk::OffsetValueType>(roundedValue);
188 ++i;
189 }
190
191 return result;
192}
193
194
195std::map<std::string, std::vector<std::string>> inline CreateParameterMap(
196 std::initializer_list<std::pair<std::string, std::string>> initializerList)
197{
198 std::map<std::string, std::vector<std::string>> result;
199
200 for (const auto & pair : initializerList)
201 {
202 EXPECT_TRUE(result.insert({ pair.first, { pair.second } }).second);
203 }
204 return result;
205}
206
207
208template <unsigned VImageDimension>
209std::map<std::string, std::vector<std::string>>
210CreateParameterMap(std::initializer_list<std::pair<std::string, std::string>> initializerList)
211{
212 std::map<std::string, std::vector<std::string>> result = CreateParameterMap(initializerList);
213
214 for (const auto & key : { "FixedImageDimension", "MovingImageDimension" })
215 {
216 EXPECT_TRUE(result.insert({ key, { std::to_string(VImageDimension) } }).second);
217 }
218 return result;
219}
220
221
223 std::initializer_list<std::pair<std::string, std::string>> initializerList)
224{
225 const auto parameterObject = ParameterObject::New();
226 parameterObject->SetParameterMap(CreateParameterMap(initializerList));
227 return parameterObject;
228}
229
230
231inline std::vector<double>
232GetTransformParametersFromMaps(const std::vector<ParameterObject::ParameterMapType> & transformParameterMaps)
233{
234 // For the time being, only support a single parameter map here.
235 EXPECT_EQ(transformParameterMaps.size(), 1);
236
237 if (transformParameterMaps.empty())
238 {
239 throw Exception("Error: GetTransformParametersFromMaps should not return an empty ParameterMap!");
240 }
241
242 const auto & transformParameterMap = transformParameterMaps.front();
243 const auto found = transformParameterMap.find("TransformParameters");
244
245 if (found == transformParameterMap.cend())
246 {
247 throw Exception("Error: GetTransformParametersFromMaps did not find TransformParameters!");
248 }
249 return ConvertStringsToVectorOfDouble(found->second);
250}
251
252
253template <typename TFilter>
254std::vector<double>
256{
257 const auto transformParameterObject = filter.GetTransformParameterObject();
258 const auto & transformParameterMaps = Deref(transformParameterObject).GetParameterMap();
259 return GetTransformParametersFromMaps(transformParameterMaps);
260}
261
262
263// Creates a test image, filled with zero.
264template <typename TPixel, unsigned VImageDimension>
265auto
266CreateImage(const itk::Size<VImageDimension> & imageSize)
267{
268 const auto image = itk::Image<TPixel, VImageDimension>::New();
269 image->SetRegions(imageSize);
270 image->Allocate(true);
271 return image;
272}
273
274
275// Creates a test image, filled with a sequence of natural numbers, 1, 2, 3, ..., N.
276template <typename TPixel, unsigned VImageDimension>
277auto
278CreateImageFilledWithSequenceOfNaturalNumbers(const itk::Size<VImageDimension> & imageSize)
279{
280 using ImageType = itk::Image<TPixel, VImageDimension>;
281 const auto image = ImageType::New();
282 image->SetRegions(imageSize);
283 image->Allocate();
284 const itk::ImageBufferRange<ImageType> imageBufferRange{ *image };
285 std::iota(imageBufferRange.begin(), imageBufferRange.end(), TPixel{ 1 });
286 return image;
287}
288
289
290std::string
292
293// Returns CMAKE_CURRENT_BINARY_DIR: the path to Core Main GTesting subdirectory of the elastix build tree (without
294// trailing slash).
295std::string
297
298// Returns the name of a test defined by `GTEST_TEST(TestSuiteName, TestName)` as "TestSuiteName_TestName_Test".
299std::string
300GetNameOfTest(const testing::Test &);
301
302} // namespace CoreMainGTestUtilities
303} // namespace elastix
304
305
306#endif
Simple exception class, to be used by unit tests.
const char * what() const noexcept override
itk::SmartPointer< Self > Pointer
#define ELX_GTEST_EXPECT_FALSE_AND_THROW_EXCEPTION_IF(condition)
Expect the specified condition to be false, and throw an exception if it is true.
decltype(auto) DerefSmartPointer(const TSmartPointer &ptr)
std::vector< double > GetTransformParametersFromMaps(const std::vector< ParameterObject::ParameterMapType > &transformParameterMaps)
std::string GetNameOfTest(const testing::Test &)
std::string GetCurrentBinaryDirectoryPath()
auto CreateImageFilledWithSequenceOfNaturalNumbers(const itk::Size< VImageDimension > &imageSize)
decltype(T().front()) Front(T &container)
std::vector< double > GetTransformParametersFromFilter(TFilter &filter)
std::map< std::string, std::vector< std::string > > CreateParameterMap(std::initializer_list< std::pair< std::string, std::string > > initializerList)
void FillImageRegion(itk::Image< TPixel, VImageDimension > &image, const itk::Index< VImageDimension > &regionIndex, const itk::Size< VImageDimension > &regionSize)
Fills the specified image region with pixel values 1.
decltype(auto) Deref(const TRawPointer ptr)
Dereferences the specified raw pointer. Throws an Exception instead, when the pointer is null.
ParameterObject::Pointer CreateParameterObject(std::initializer_list< std::pair< std::string, std::string > > initializerList)
auto CreateImage(const itk::Size< VImageDimension > &imageSize)
itk::Offset< VDimension > ConvertToOffset(const std::vector< double > &doubles)
std::vector< double > ConvertStringsToVectorOfDouble(const std::vector< std::string > &strings)


Generated on 2023-01-13 for elastix by doxygen 1.9.6 elastix logo