TestHelpers.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Commonly used routines, functions and definitions shared amongst unit tests
6 
7 #pragma once
8 
10 
11 #include <algorithm>
12 #include <array>
13 #include <boost/algorithm/string/predicate.hpp>
14 #include <cstddef>
15 #include <iterator>
16 #include <memory>
17 #include <ostream>
18 #include <random>
19 #include <string>
20 #include <tuple>
21 
23 #include "ErrorHandling/Assert.hpp"
24 #include "ErrorHandling/Error.hpp"
26 #include "Parallel/Serialize.hpp"
27 #include "Utilities/ContainerHelpers.hpp"
29 #include "Utilities/Gsl.hpp"
30 #include "Utilities/MakeArray.hpp"
31 #include "Utilities/Requires.hpp"
32 #include "Utilities/StdArrayHelpers.hpp" // IWYU pragma: keep
33 #include "Utilities/TMPL.hpp"
34 #include "Utilities/Tuple.hpp"
35 #include "Utilities/TypeTraits.hpp"
36 
37 /*!
38  * \ingroup TestingFrameworkGroup
39  * \brief Serializes and deserializes an object `t` of type `T`
40  */
41 template <typename T>
43  static_assert(
45  "Cannot use serialize_and_deserialize if a class is not default "
46  "constructible.");
47  return deserialize<T>(serialize<T>(t).data());
48 }
49 
50 /// \ingroup TestingFrameworkGroup
51 /// \brief Tests the serialization of comparable types
52 /// \example
53 /// \snippet Test_PupStlCpp11.cpp example_serialize_comparable
54 template <typename T>
55 void test_serialization(const T& t) {
56  static_assert(tt::has_equivalence_v<T>, "No operator== for T");
57  CHECK(t == serialize_and_deserialize(t));
58 }
59 
60 /// \ingroup TestingFrameworkGroup
61 /// \brief Test the serialization of a derived class via a base class pointer
62 /// \example
63 /// \snippet Test_PupStlCpp11.cpp example_serialize_derived
64 /// \tparam B the base class
65 /// \tparam D the derived class
66 /// \tparam Args deduced from `args`
67 /// \param args arguments passed to a constructor of the derived class
68 template <typename B, typename D, typename... Args>
69 void test_serialization_via_base(Args&&... args) {
70  static_assert(cpp17::is_base_of_v<B, D>,
71  "passed input type is not derived from specified base");
72  static_assert(tt::has_equivalence_v<D>, "No operator== for derived class");
73  Parallel::register_derived_classes_with_charm<B>();
74  std::unique_ptr<B> base = std::make_unique<D>(args...);
76  CHECK_FALSE(nullptr == dynamic_cast<const D*>(pupped_base.get()));
77  const D derived(args...);
78  CHECK(derived == dynamic_cast<const D&>(*pupped_base));
79 }
80 
81 /// Test for copy semantics assuming operator== is implement correctly
82 template <typename T, Requires<tt::has_equivalence<T>::value> = nullptr>
83 void test_copy_semantics(const T& a) {
85  "Class is not copy assignable.");
87  "Class is not copy constructible.");
88  T b = a;
89  CHECK(b == a);
90  // clang-tidy: intentionally not a reference to force invocation of copy
91  // constructor
92  const T c(a); // NOLINT
93  CHECK(c == a);
94 #ifndef __APPLE__
95 #if defined(__clang__) && __clang_major__ > 6
96 #pragma GCC diagnostic push
97 #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
98 #endif // defined(__clang__) && __clang_major__ > 6
99 #endif // ! __APPLE__
100  // clang-tidy: self-assignment
101  b = b; // NOLINT
102 #ifndef __APPLE__
103 #if defined(__clang__) && __clang_major__ > 6
104 #pragma GCC diagnostic pop
105 #endif // defined(__clang__) && __clang_major__ > 6
106 #endif // ! __APPLE__
107  CHECK(b == a);
108 }
109 
110 /// Test for move semantics assuming operator== is implemented correctly.
111 /// \requires `std::is_rvalue_reference<decltype(a)>::%value` is true.
112 /// If T is not default constructible, you pass additional
113 /// arguments that are used to construct a T.
114 template <typename T, Requires<tt::has_equivalence<T>::value> = nullptr,
115  typename... Args>
116 void test_move_semantics(T&& a, const T& comparison, Args&&... args) {
117  static_assert(std::is_rvalue_reference<decltype(a)>::value,
118  "Must move into test_move_semantics");
120  "Class is not nothrow move assignable.");
122  "Class is not nothrow move constructible.");
123  if (&a == &comparison or a != comparison) {
124  // We use ERROR instead of ASSERT (which we normally should be using) to
125  // guard against someone writing tests in Release mode where ASSERTs don't
126  // show up.
127  ERROR("'a' and 'comparison' must be distinct (but equal in value) objects");
128  }
129  T b(std::forward<Args>(args)...);
130  // clang-tidy: use std::forward instead of std::move
131  b = std::move(a); // NOLINT
132  CHECK(b == comparison);
133  T c(std::move(b));
134  CHECK(c == comparison);
135 }
136 
137 // Test for iterators
138 template <typename Container>
139 void test_iterators(Container& c) {
140  CHECK(std::distance(c.begin(), c.end()) ==
141  static_cast<decltype(std::distance(c.begin(), c.end()))>(c.size()));
142  CHECK(c.begin() == c.cbegin());
143  CHECK(c.end() == c.cend());
144 
145  const auto& const_c = c;
146  CHECK(std::distance(const_c.begin(), const_c.end()) ==
147  static_cast<decltype(std::distance(const_c.begin(), const_c.end()))>(
148  const_c.size()));
149  CHECK(const_c.begin() == const_c.cbegin());
150  CHECK(const_c.end() == const_c.cend());
151 }
152 
153 // Test for reverse iterators
154 template <typename Container>
155 void test_reverse_iterators(Container& c) {
156  CHECK(std::distance(c.rbegin(), c.rend()) ==
157  static_cast<decltype(std::distance(c.rbegin(), c.rend()))>(c.size()));
158 
159  CHECK(c.rbegin() == c.crbegin());
160  CHECK(c.rend() == c.crend());
161 
162  auto it = c.begin();
163  auto rit = c.rbegin();
164  auto end = c.end();
165  auto rend = c.rend();
166  auto cit = c.cbegin();
167  auto cend = c.cend();
168  auto crit = c.crbegin();
169  auto crend = c.crend();
170 
171  for (size_t i = 0; i < c.size(); i++) {
172  CHECK(*it == *(std::prev(rend, 1)));
173  CHECK(*rit == *(std::prev(end, 1)));
174  CHECK(*cit == *(std::prev(crend, 1)));
175  CHECK(*crit == *(std::prev(cend, 1)));
176  it++;
177  rit++;
178  rend--;
179  end--;
180  crit++;
181  cit++;
182  crend--;
183  cend--;
184  }
185 
186  const auto& const_c = c;
187  CHECK(std::distance(const_c.begin(), const_c.end()) ==
188  static_cast<decltype(std::distance(const_c.begin(), const_c.end()))>(
189  const_c.size()));
190  auto c_it = const_c.begin();
191  auto c_rit = const_c.rbegin();
192  auto c_end = const_c.end();
193  auto c_rend = const_c.rend();
194  for (size_t i = 0; i < c.size(); i++) {
195  CHECK(*c_it == *(std::prev(c_rend, 1)));
196  CHECK(*c_rit == *(std::prev(c_end, 1)));
197  c_it++;
198  c_rit++;
199  c_rend--;
200  c_end--;
201  }
202 }
203 
204 /*!
205  * \ingroup TestingFrameworkGroup
206  * \brief Function to test comparison operators. Pass values with
207  * less < greater.
208  */
209 template <typename T, typename U>
210 void check_cmp(const T& less, const U& greater) {
211  CHECK(less == less);
212  CHECK_FALSE(less == greater);
213  CHECK(less != greater);
214  CHECK_FALSE(less != less);
215  CHECK(less < greater);
216  CHECK_FALSE(greater < less);
217  CHECK(greater > less);
218  CHECK_FALSE(less > greater);
219  CHECK(less <= greater);
220  CHECK_FALSE(greater <= less);
221  CHECK(greater >= less);
222  CHECK_FALSE(less >= greater);
223  CHECK(less <= less);
224  CHECK_FALSE(less < less);
225  CHECK(less >= less);
226  CHECK_FALSE(less > less);
227 }
228 
229 /*!
230  * \ingroup TestingFrameworkGroup
231  * \brief Check a op b == c and also the op= version.
232  */
233 #define CHECK_OP(a, op, b, c) \
234  do { \
235  const auto& a_ = a; \
236  const auto& b_ = b; \
237  const auto& c_ = c; \
238  CHECK(a_ op b_ == c_); \
239  auto f = a_; \
240  CHECK((f op## = b_) == c_); \
241  CHECK(f == c_); \
242  } while (false)
243 
244 /*!
245  * \ingroup TestingFrameworkGroup
246  * \brief Calculates the derivative of an Invocable at a point x - represented
247  * by an array of doubles - in the domain of `map` with a sixth-order finite
248  * difference method.
249  *
250  * \details Intended for use with CoordinateMaps taking the domain {xi,eta,zeta}
251  * to the range {x,y,z}. This function calculates the derivative along the
252  * direction given by `direction` with a step size of `h`.
253  *
254  * \requires direction be between 0 and VolumeDim
255  */
256 template <typename Invocable, size_t VolumeDim>
258  const Invocable& map, const std::array<double, VolumeDim>& x,
259  const size_t direction, const double delta) {
260  ASSERT(0 <= direction and direction < VolumeDim,
261  "Trying to take derivative along axis " << direction);
262 
263  const auto dx = [direction, delta]() {
264  auto d = make_array<VolumeDim>(0.);
265  gsl::at(d, direction) = delta;
266  return d;
267  }();
268 
269  const std::array<double, VolumeDim> x_1ahead = x + dx;
270  const std::array<double, VolumeDim> x_2ahead = x_1ahead + dx;
271  const std::array<double, VolumeDim> x_3ahead = x_2ahead + dx;
272  const std::array<double, VolumeDim> x_1behind = x - dx;
273  const std::array<double, VolumeDim> x_2behind = x_1behind - dx;
274  const std::array<double, VolumeDim> x_3behind = x_2behind - dx;
275  return (1.0 / (60.0 * delta)) * map(x_3ahead) +
276  (-3.0 / (20.0 * delta)) * map(x_2ahead) +
277  (0.75 / delta) * map(x_1ahead) + (-0.75 / delta) * map(x_1behind) +
278  (3.0 / (20.0 * delta)) * map(x_2behind) +
279  (-1.0 / (60.0 * delta)) * map(x_3behind);
280 }
281 
282 struct NonCopyable {
283  constexpr NonCopyable() = default;
284  constexpr NonCopyable(const NonCopyable&) = delete;
285  constexpr NonCopyable& operator=(const NonCopyable&) = delete;
286  constexpr NonCopyable(NonCopyable&&) = default;
287  NonCopyable& operator=(NonCopyable&&) = default;
288  ~NonCopyable() = default;
289 };
290 inline bool operator==(const NonCopyable& /*a*/,
291  const NonCopyable& /*b*/) noexcept {
292  return true;
293 }
294 inline bool operator!=(const NonCopyable& a, const NonCopyable& b) noexcept {
295  return not(a == b);
296 }
297 inline std::ostream& operator<<(std::ostream& os,
298  const NonCopyable& /*v*/) noexcept {
299  return os << "NC";
300 }
301 
303  public:
304  DoesNotThrow() noexcept = default;
305  DoesNotThrow(const DoesNotThrow&) noexcept = default;
306  DoesNotThrow& operator=(const DoesNotThrow&) noexcept = default;
307  DoesNotThrow(DoesNotThrow&&) noexcept = default;
308  DoesNotThrow& operator=(DoesNotThrow&&) noexcept = default;
309  ~DoesNotThrow() = default;
310 };
311 class DoesThrow {
312  public:
313  DoesThrow() noexcept(false);
314  DoesThrow(const DoesThrow&) noexcept(false);
315  DoesThrow& operator=(const DoesThrow&) noexcept(false);
316  DoesThrow(DoesThrow&&) noexcept(false);
317  DoesThrow& operator=(DoesThrow&&) noexcept(false);
318  ~DoesThrow() = default;
319 };
320 
321 /*!
322  * \ingroup TestingFrameworkGroup
323  * \brief Execute `func` and check that it throws an exception `expected`.
324  *
325  * \note The `.what()` strings of the thrown and `expected` exceptions are
326  * compared for a partial match only: the `expected.what()` string must be
327  * contained in (or equal to) the `.what()` string of the thrown exception.
328  */
329 template <typename Exception, typename ThrowingFunctor>
330 void test_throw_exception(const ThrowingFunctor& func,
331  const Exception& expected) {
332  try {
333  func();
334  INFO("Failed to throw any exception");
335  CHECK(false);
336  } catch (Exception& e) {
337  CAPTURE(e.what());
338  CAPTURE(expected.what());
339  CHECK(boost::contains(std::string(e.what()), std::string(expected.what())));
340  } catch (...) {
341  INFO("Failed to throw exception of type " +
342  pretty_type::get_name<Exception>());
343  CHECK(false);
344  }
345 }
346 
347 /// \cond
348 #define MAKE_GENERATOR_IMPL_FIRST_ARG(NAME, ...) NAME
349 #define MAKE_GENERATOR_IMPL_SECOND_ARG(NAME, SEED, ...) SEED
350 /// \endcond
351 
352 /// \ingroup TestingFrameworkGroup
353 /// \brief `MAKE_GENERATOR(NAME [, SEED])` declares a variable of name `NAME`
354 /// containing a generator of type `std::mt19937`.
355 ///
356 /// \details As the generator is made, `INFO` is called to make sure failed
357 /// tests provide seed information. `SEED` is chosen randomly if not supplied,
358 /// otherwise it must be a constant expression.
359 // What is going on here:
360 //
361 // If this is called as MAKE_GENERATOR(NAME):
362 // MAKE_GENERATOR_IMPL_FIRST_ARG(__VA_ARGS__, DUMMY_TOKEN)
363 // -> MAKE_GENERATOR_IMPL_FIRST_ARG(NAME, DUMMY_TOKEN)
364 // -> NAME
365 // MAKE_GENERATOR_IMPL_SECOND_ARG(
366 // __VA_ARGS__, std::random_device{}(), DUMMY_TOKEN)
367 // -> MAKE_GENERATOR_IMPL_SECOND_ARG(
368 // NAME, std::random_device{}(), DUMMY_TOKEN)
369 // -> std::random_device{}()
370 // So we create NAME with a random seed.
371 //
372 // In this case DUMMY_TOKEN is needed because the "..." in the IMPL
373 // macros has to match at least one thing.
374 //
375 // If this is called as MAKE_GENERATOR(NAME, SEED):
376 // MAKE_GENERATOR_IMPL_FIRST_ARG(__VA_ARGS__, DUMMY_TOKEN)
377 // -> MAKE_GENERATOR_IMPL_FIRST_ARG(NAME, SEED, DUMMY_TOKEN)
378 // -> NAME
379 // MAKE_GENERATOR_IMPL_SECOND_ARG(
380 // __VA_ARGS__, std::random_device{}(), DUMMY_TOKEN)
381 // -> MAKE_GENERATOR_IMPL_SECOND_ARG(
382 // NAME, SEED, std::random_device{}(), DUMMY_TOKEN)
383 // -> SEED
384 // So we create NAME with seed SEED.
385 //
386 // In this case the DUMMY_TOKEN is not necessary.
387 #define MAKE_GENERATOR(...) \
388  std::mt19937 MAKE_GENERATOR_IMPL_FIRST_ARG(__VA_ARGS__, DUMMY_TOKEN); \
389  INFO("Seed is: " << [&MAKE_GENERATOR_IMPL_FIRST_ARG( \
390  __VA_ARGS__, DUMMY_TOKEN)]() noexcept { \
391  const auto seed = (MAKE_GENERATOR_IMPL_SECOND_ARG( \
392  __VA_ARGS__, std::random_device{}(), DUMMY_TOKEN)); \
393  MAKE_GENERATOR_IMPL_FIRST_ARG(__VA_ARGS__, DUMMY_TOKEN).seed(seed); \
394  return seed; \
395  }())
396 
397 /*!
398  * \ingroup TestingFrameworkGroup
399  * \brief A wrapper around Catch's CHECK macro that checks approximate equality
400  * of each entry in each tag within a variables.
401  */
402 #define CHECK_VARIABLES_APPROX(a, b) \
403  do { \
404  INFO(__FILE__ ":" + std::to_string(__LINE__) + ": " #a " == " #b); \
405  check_variables_approx<std::common_type_t< \
406  std::decay_t<decltype(a)>, std::decay_t<decltype(b)>>>::apply(a, b); \
407  } while (false)
408 
409 /*!
410  * \ingroup TestingFrameworkGroup
411  * \brief Same as `CHECK_VARIABLES_APPROX`, but with a user-defined Approx.
412  * The third argument should be of type `Approx`.
413  */
414 #define CHECK_VARIABLES_CUSTOM_APPROX(a, b, appx) \
415  do { \
416  INFO(__FILE__ ":" + std::to_string(__LINE__) + ": " #a " == " #b); \
417  check_variables_approx<std::common_type_t< \
418  std::decay_t<decltype(a)>, std::decay_t<decltype(b)>>>::apply(a, b, \
419  appx); \
420  } while (false)
421 
422 template <typename T>
424 
425 template <typename TagList>
426 struct check_variables_approx<Variables<TagList>> {
427  // clang-tidy: non-const reference
428  static void apply(const Variables<TagList>& a, const Variables<TagList>& b,
429  Approx& appx = approx) { // NOLINT
430  tmpl::for_each<TagList>([&a, &b, &appx](auto x) {
431  using Tag = typename decltype(x)::type;
432  auto& a_val = get<Tag>(a);
433  auto& b_val = get<Tag>(b);
434  CHECK_ITERABLE_CUSTOM_APPROX(a_val, b_val, appx);
435  });
436  }
437 };
438 
439 /*!
440  * \ingroup TestingFrameworkGroup
441  * \brief A test utility for verifying that an element-wise function, `function`
442  * acts identically to the same operation applied to each element of a container
443  * separately. This macro invokes `test_element_wise_function()` (which gives a
444  * more complete documentation of the element-wise checking operations and
445  * arguments).
446  */
447 #define CHECK_ELEMENT_WISE_FUNCTION_APPROX(function, arguments) \
448  do { \
449  INFO(__FILE__ ":" + std::to_string(__LINE__) + \
450  ": " #function ", " #arguments); \
451  test_element_wise_function(function, arguments); \
452  } while (false)
453 
454 /*!
455  * \ingroup TestingFrameworkGroup
456  * \brief Same as `CHECK_ELEMENT_WISE_FUNCTION_APPROX`, but with a user-defined
457  * function `at_operator` and `size_of_operator`, each of which correspond to
458  * arguments of `test_element_wise_function()` (which gives a more complete
459  * documentation of the element-wise checking operations and arguments).
460  */
461 #define CHECK_CUSTOM_ELEMENT_WISE_FUNCTION_APPROX( \
462  function, arguments, at_operator, size_of_operator) \
463  do { \
464  INFO(__FILE__ ":" + std::to_string(__LINE__) + \
465  ": " #function ", " #arguments); \
466  test_element_wise_function(function, arguments, at_operator, \
467  size_of_operator); \
468  } while (false)
469 
470 namespace TestHelpers_detail {
471 // CHECK forwarding for parameter pack expansion. Return value also required for
472 // easy parameter pack use.
473 template <typename Approx>
474 SPECTRE_ALWAYS_INLINE int call_check_approx(double a, double b,
475  Approx custom_approx) noexcept {
476  CHECK(custom_approx(a) == b);
477  return 0;
478 }
479 
480 template <typename Approx>
481 SPECTRE_ALWAYS_INLINE int call_check_approx(std::complex<double> a,
483  Approx custom_approx) noexcept {
484  CHECK(custom_approx(real(a)) == real(b));
485  CHECK(custom_approx(imag(a)) == imag(b));
486  return 0;
487 }
488 
489 // internal implementation for checking that an element-wise function acts
490 // appropriately on a container object by first trying the operation on the
491 // containers, then checking that the operation has been performed as it would
492 // by looping over the elements and performing the same operation on each. This
493 // also supports testing functions between containers and single elements by
494 // making use of `get_size` and `get_element`.
495 template <typename Function, typename IndexingFunction, typename SizeFunction,
496  typename... Arguments, size_t... Is>
497 void test_element_wise_function_impl(
498  Function element_wise_function,
499  const gsl::not_null<std::tuple<Arguments...>*> arguments,
500  IndexingFunction at, SizeFunction size, std::index_sequence<Is...> /*meta*/,
501  Approx custom_approx) noexcept {
502  const size_t size_value =
503  std::max({get_size(std::get<Is>(*arguments), size)...});
504  tuple_fold(*arguments, [&size, &size_value ](const auto x) noexcept {
505  if (not(get_size(x, size) == size_value or get_size(x, size) == 1)) {
506  ERROR(
507  "inconsistent sized arguments passed "
508  "to test_element_wise_function");
509  }
510  });
511  // Some operators might modify the values of the arguments. We take care to
512  // verify that the modifications (or lack thereof) are also as expected.
513  auto original_arguments = std::make_tuple(std::get<Is>(*arguments)...);
514  const auto result = element_wise_function(std::get<Is>(*arguments)...);
515  for (size_t i = 0; i < size_value; ++i) {
516  // the arguments which modify their arguments must be passed lvalues
517  auto element_of_arguments = std::make_tuple(
518  get_element(std::get<Is>(original_arguments), i, at)...);
519  call_check_approx(
520  get_element(result, i, at),
521  element_wise_function(std::get<Is>(element_of_arguments)...),
522  custom_approx);
523  // ensure that the final state of the arguments matches
524  expand_pack(call_check_approx(get_element(std::get<Is>(*arguments), i, at),
525  std::get<Is>(element_of_arguments),
526  custom_approx)...);
527  }
528 }
529 } // namespace TestHelpers_detail
530 
531 /*!
532  * \ingroup TestingFrameworkGroup
533  * \brief Utility function for verifying the action of an element-wise function
534  * on containers, or on some combination of containers and compatible
535  * non-containers (e.g. `DataVectors` with `doubles`).
536  *
537  * \details The ability to specify custom functions for `at` and `size` is
538  * useful for more intricate containers. For instance, multidimensional types
539  * can be used with this function with a size function that returns the full
540  * number of elements, and an `at` function which indexes the multidimensional
541  * type in a flattened fashion.
542  *
543  * parameters:
544  * \param element_wise_function A callable which is expected to act in an
545  * element-wise fashion, must be compatible both with the container and its
546  * individual elements.
547  * \param arguments A tuple of arguments to be tested
548  * \param at A function to override the container access function. Defaults to
549  * an object which simply calls `container.at(i)`. A custom callable must take
550  * as arguments the container(s) used in `arguments` and a `size_t` index (in
551  * that order), and return an element compatible with
552  * `element_wise_function`. This function signature follows the convention of
553  * `gsl::at`.
554  * \param size A function to override the container size function. Defaults to
555  * an object which simply calls `container.size()`. A custom callable must take
556  * as argument the container(s) used in `arguments`, and return a size_t. This
557  * function signature follows the convention of `cpp17::size`.
558  * \param custom_approx An object of type `Approx` specifying an alternative
559  * precision with which to test the element-wise function
560  */
561 template <typename ElementWiseFunction,
562  typename AtFunction = GetContainerElement,
563  typename SizeFunction = GetContainerSize, typename... Arguments>
565  ElementWiseFunction element_wise_function,
566  const gsl::not_null<std::tuple<Arguments...>*> arguments,
567  AtFunction at = GetContainerElement{},
568  SizeFunction size = GetContainerSize{},
569  Approx custom_approx = approx) noexcept {
570  TestHelpers_detail::test_element_wise_function_impl(
571  element_wise_function, arguments, at, size,
572  std::make_index_sequence<sizeof...(Arguments)>{}, custom_approx);
573 }
Callable struct which retrieves the t.size() for operand t. This will cause a compiler error if no su...
Definition: ContainerHelpers.hpp:17
Defines function dereference_wrapper.
Functions for serializing factory-created classes.
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:35
Definition: TestHelpers.hpp:282
Defines function make_array.
void check_cmp(const T &less, const U &greater)
Function to test comparison operators. Pass values with less < greater.
Definition: TestHelpers.hpp:210
void test_serialization_via_base(Args &&... args)
Test the serialization of a derived class via a base class pointer.
Definition: TestHelpers.hpp:69
Definition: TestHelpers.hpp:311
decltype(auto) get_size(const T &t, SizeFunction size=GetContainerSize{}) noexcept
Retrieve the size of t if t.size() is a valid expression, otherwise if T is fundamental or a std::com...
Definition: ContainerHelpers.hpp:119
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
void test_element_wise_function(ElementWiseFunction element_wise_function, const gsl::not_null< std::tuple< Arguments... > *> arguments, AtFunction at=GetContainerElement{}, SizeFunction size=GetContainerSize{}, Approx custom_approx=approx) noexcept
Utility function for verifying the action of an element-wise function on containers, or on some combination of containers and compatible non-containers (e.g. DataVectors with doubles).
Definition: TestHelpers.hpp:564
constexpr void tuple_fold(const std::tuple< Elements... > &tuple, N_aryOp &&op, Args &&... args) noexcept(noexcept(tuple_impl_detail::tuple_fold_impl< ReverseIteration >(tuple, std::forward< N_aryOp >(op), std::make_index_sequence< sizeof...(Elements)>{}, args...)))
Perform a fold over a std::tuple.
Definition: Tuple.hpp:112
std::array< double, VolumeDim > numerical_derivative(const Invocable &map, const std::array< double, VolumeDim > &x, const size_t direction, const double delta)
Calculates the derivative of an Invocable at a point x - represented by an array of doubles - in the ...
Definition: TestHelpers.hpp:257
Defines the type alias Requires.
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
Defines the serialize and deserialize functions.
#define CHECK_ITERABLE_CUSTOM_APPROX(a, b, appx)
Same as CHECK_ITERABLE_APPROX with user-defined Approx. The third argument should be of type Approx...
Definition: TestingFramework.hpp:122
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
void test_copy_semantics(const T &a)
Test for copy semantics assuming operator== is implement correctly.
Definition: TestHelpers.hpp:83
Defines class Variables.
void test_move_semantics(T &&a, const T &comparison, Args &&... args)
Test for move semantics assuming operator== is implemented correctly.
Definition: TestHelpers.hpp:116
void test_serialization(const T &t)
Tests the serialization of comparable types.
Definition: TestHelpers.hpp:55
Defines functions for manipulating tuples.
Defines macro ASSERT.
Definition: TestHelpers.hpp:423
Wraps the template metaprogramming library used (brigand)
Defines functions and classes from the GSL.
Code to wrap or improve the Catch testing framework used for unit tests.
T serialize_and_deserialize(const T &t)
Serializes and deserializes an object t of type T
Definition: TestHelpers.hpp:42
void test_throw_exception(const ThrowingFunctor &func, const Exception &expected)
Execute func and check that it throws an exception expected.
Definition: TestHelpers.hpp:330
Definition: TestHelpers.hpp:302
Defines macro ERROR.
Defines type traits, some of which are future STL type_traits header.
Callable struct for the subscript operator. Returns t[i]
Definition: ContainerHelpers.hpp:26
Defines arithmetic operators for std::array and other helpful functions.
Definition: MakeWithRandomValues.hpp:21
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
decltype(auto) get_element(T &t, const size_t i, SubscriptFunction at=GetContainerElement{}) noexcept
Returns the ith element if T has a subscript operator, otherwise if T is fundamental or a std::comple...
Definition: ContainerHelpers.hpp:91
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid...
Definition: Gsl.hpp:124