test_utils.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // Range v3 library
  2. //
  3. // Copyright Eric Niebler 2014-present
  4. //
  5. // Use, modification and distribution is subject to the
  6. // Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef RANGES_TEST_UTILS_HPP
  10. #define RANGES_TEST_UTILS_HPP
  11. #include <algorithm>
  12. #include <cstring>
  13. #include <functional>
  14. #include <initializer_list>
  15. #include <ostream>
  16. #include <meta/meta.hpp>
  17. #include <range/v3/iterator/concepts.hpp>
  18. #include <range/v3/iterator/operations.hpp>
  19. #include <range/v3/iterator/traits.hpp>
  20. #include <range/v3/range/access.hpp>
  21. #include <range/v3/range/concepts.hpp>
  22. #include <range/v3/range/traits.hpp>
  23. #include <range/v3/view/subrange.hpp>
  24. #include "./debug_view.hpp"
  25. #include "./simple_test.hpp"
  26. #include "./test_iterators.hpp"
  27. #if defined(__clang__) || defined(__GNUC__)
  28. #if defined(__has_builtin)
  29. #if __has_builtin(__builtin_FILE) && \
  30. __has_builtin(__builtin_LINE) && \
  31. __has_builtin(__builtin_FUNCTION)
  32. #define RANGES_CXX_HAS_SLOC_BUILTINS
  33. #endif
  34. #endif
  35. #else
  36. #define RANGES_CXX_HAS_SLOC_BUILTINS
  37. #endif
  38. #if defined(RANGES_CXX_HAS_SLOC_BUILTINS) && defined(__has_include)
  39. #if __has_include(<source_location>)
  40. #include <source_location>
  41. #ifdef __cpp_lib_source_location
  42. #define RANGES_HAS_SLOC 1
  43. using source_location = std::source_location;
  44. #endif
  45. #elif __has_include(<experimental/source_location>)
  46. #include <experimental/source_location>
  47. #if __cpp_lib_experimental_source_location
  48. #define RANGES_HAS_SLOC 1
  49. using source_location = std::experimental::source_location;
  50. #endif
  51. #endif
  52. #endif
  53. #ifndef RANGES_HAS_SLOC
  54. struct source_location
  55. {
  56. static source_location current()
  57. {
  58. return {};
  59. }
  60. };
  61. #define CHECK_SLOC(sloc, ...) \
  62. do \
  63. { \
  64. (void)sloc; \
  65. CHECK(__VA_ARGS__); \
  66. } while(false)
  67. #else
  68. #define CHECK_SLOC(sloc, ...) CHECK_LINE(sloc.file_name(), (int)sloc.line(), __VA_ARGS__)
  69. #endif
  70. RANGES_DIAGNOSTIC_PUSH
  71. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_THIS_CAPTURE
  72. template<typename T, typename U>
  73. CPP_concept both_ranges = ranges::input_range<T> && ranges::input_range<U>;
  74. struct check_equal_fn
  75. {
  76. CPP_template(typename T, typename U)(
  77. requires(!both_ranges<T, U>)) //
  78. constexpr void operator()(
  79. T && actual, U && expected,
  80. source_location sloc = source_location::current()) const
  81. {
  82. CHECK_SLOC(sloc, (T &&) actual == (U &&) expected);
  83. }
  84. CPP_template(typename Rng1, typename Rng2)(
  85. requires both_ranges<Rng1, Rng2>)
  86. constexpr void operator()(
  87. Rng1 && actual, Rng2 && expected,
  88. source_location sloc = source_location::current()) const
  89. {
  90. auto begin0 = ranges::begin(actual);
  91. auto end0 = ranges::end(actual);
  92. auto begin1 = ranges::begin(expected);
  93. auto end1 = ranges::end(expected);
  94. for(; begin0 != end0 && begin1 != end1; ++begin0, ++begin1)
  95. (*this)(*begin0, *begin1, sloc);
  96. CHECK_SLOC(sloc, begin0 == end0);
  97. CHECK_SLOC(sloc, begin1 == end1);
  98. }
  99. CPP_template(typename Rng, typename Val)(
  100. requires ranges::input_range<Rng>)
  101. constexpr void operator()(
  102. Rng && actual, std::initializer_list<Val> && expected,
  103. source_location sloc = source_location::current()) const
  104. {
  105. (*this)(actual, expected, sloc);
  106. }
  107. };
  108. inline namespace function_objects
  109. {
  110. RANGES_INLINE_VARIABLE(check_equal_fn, check_equal)
  111. }
  112. template<typename Expected, typename Actual>
  113. constexpr void has_type(Actual &&)
  114. {
  115. static_assert(std::is_same<Expected, Actual>::value, "Not the same");
  116. }
  117. template<ranges::cardinality Expected,
  118. typename Rng,
  119. ranges::cardinality Actual = ranges::range_cardinality<Rng>::value>
  120. constexpr void has_cardinality(Rng &&)
  121. {
  122. static_assert(Actual == Expected, "Unexpected cardinality");
  123. }
  124. template<typename T>
  125. constexpr T & as_lvalue(T && t)
  126. {
  127. return t;
  128. }
  129. // A simple, light-weight, non-owning reference to a type-erased function.
  130. template<typename Sig>
  131. struct function_ref;
  132. template<typename Ret, typename... Args>
  133. struct function_ref<Ret(Args...)>
  134. {
  135. private:
  136. void const * data_{nullptr};
  137. Ret (*pfun_)(void const *, Args...){nullptr};
  138. template<typename Fun>
  139. static Ret apply_(void const * data, Args... args)
  140. {
  141. return (*static_cast<Fun const *>(data))(args...);
  142. }
  143. public:
  144. function_ref() = default;
  145. template<typename T>
  146. function_ref(T const & t)
  147. : data_(&t)
  148. , pfun_(&apply_<T>)
  149. {}
  150. Ret operator()(Args... args) const
  151. {
  152. return (*pfun_)(data_, args...);
  153. }
  154. };
  155. template<typename T>
  156. struct checker
  157. {
  158. private:
  159. std::function<void(function_ref<void(T)>)> algo_;
  160. public:
  161. explicit checker(std::function<void(function_ref<void(T)>)> algo)
  162. : algo_(std::move(algo))
  163. {}
  164. void check(function_ref<void(T)> const & check) const
  165. {
  166. algo_(check);
  167. }
  168. };
  169. template<bool B, typename T>
  170. meta::if_c<B, T, T const &> rvalue_if(T const & t)
  171. {
  172. return t;
  173. }
  174. template<typename Algo, bool RvalueOK = false>
  175. struct test_range_algo_1
  176. {
  177. private:
  178. Algo algo_;
  179. template<typename I, typename... Rest>
  180. static auto _impl(Algo algo, I first, I last, Rest &&... rest)
  181. -> ::checker<decltype(algo(first, last, rest...))>
  182. {
  183. using S = meta::_t<sentinel_type<I>>;
  184. using R = decltype(algo(first, last, rest...));
  185. auto check_algo = [algo, first, last, rest...](
  186. function_ref<void(R)> const & check) {
  187. check(algo(first, last, rest...));
  188. check(algo(first, S{base(last)}, rest...));
  189. check(
  190. algo(::rvalue_if<RvalueOK>(ranges::make_subrange(first, last)), rest...));
  191. check(algo(::rvalue_if<RvalueOK>(ranges::make_subrange(first, S{base(last)})),
  192. rest...));
  193. };
  194. return ::checker<R>{check_algo};
  195. }
  196. public:
  197. explicit test_range_algo_1(Algo algo)
  198. : algo_(algo)
  199. {}
  200. template<typename I>
  201. auto operator()(I first, I last) const -> ::checker<decltype(algo_(first, last))>
  202. {
  203. return test_range_algo_1::_impl(algo_, first, last);
  204. }
  205. template<typename I, typename T>
  206. auto operator()(I first, I last, T t) const -> ::checker<decltype(algo_(first, last, t))>
  207. {
  208. return test_range_algo_1::_impl(algo_, first, last, t);
  209. }
  210. template<typename I, typename T, typename U>
  211. auto operator()(I first, I last, T t, U u) const
  212. -> ::checker<decltype(algo_(first, last, t, u))>
  213. {
  214. return test_range_algo_1::_impl(algo_, first, last, t, u);
  215. }
  216. template<typename I, typename T, typename U, typename V>
  217. auto operator()(I first, I last, T t, U u, V v) const
  218. -> ::checker<decltype(algo_(first, last, t, u, v))>
  219. {
  220. return test_range_algo_1::_impl(algo_, first, last, t, u, v);
  221. }
  222. };
  223. template<bool RvalueOK = false, typename Algo>
  224. test_range_algo_1<Algo, RvalueOK> make_testable_1(Algo algo)
  225. {
  226. return test_range_algo_1<Algo, RvalueOK>{algo};
  227. }
  228. template<typename Algo, bool RvalueOK1 = false, bool RvalueOK2 = false>
  229. struct test_range_algo_2
  230. {
  231. private:
  232. Algo algo_;
  233. public:
  234. explicit test_range_algo_2(Algo algo)
  235. : algo_(algo)
  236. {}
  237. template<typename I1, typename I2, typename... Rest>
  238. auto operator()(I1 begin1, I1 end1, I2 begin2, I2 end2, Rest &&... rest) const
  239. -> checker<decltype(algo_(begin1, end1, begin2, end2, rest...))>
  240. {
  241. using S1 = meta::_t<sentinel_type<I1>>;
  242. using S2 = meta::_t<sentinel_type<I2>>;
  243. using R = decltype(algo_(begin1, end1, begin2, end2, rest...));
  244. return checker<R>{[algo = algo_, begin1, end1, begin2, end2, rest...](
  245. function_ref<void(R)> const & check) {
  246. check(algo(begin1, end1, begin2, end2, rest...));
  247. check(algo(begin1, S1{base(end1)}, begin2, S2{base(end2)}, rest...));
  248. check(algo(::rvalue_if<RvalueOK1>(ranges::make_subrange(begin1, end1)),
  249. ::rvalue_if<RvalueOK2>(ranges::make_subrange(begin2, end2)),
  250. rest...));
  251. check(algo(
  252. ::rvalue_if<RvalueOK1>(ranges::make_subrange(begin1, S1{base(end1)})),
  253. ::rvalue_if<RvalueOK2>(ranges::make_subrange(begin2, S2{base(end2)})),
  254. rest...));
  255. }};
  256. }
  257. };
  258. template<bool RvalueOK1 = false, bool RvalueOK2 = false, typename Algo>
  259. test_range_algo_2<Algo, RvalueOK1, RvalueOK2> make_testable_2(Algo algo)
  260. {
  261. return test_range_algo_2<Algo, RvalueOK1, RvalueOK2>{algo};
  262. }
  263. // a simple type to test move semantics
  264. struct MoveOnlyString
  265. {
  266. char const * sz_;
  267. MoveOnlyString(char const * sz = "")
  268. : sz_(sz)
  269. {}
  270. MoveOnlyString(MoveOnlyString && that)
  271. : sz_(that.sz_)
  272. {
  273. that.sz_ = "";
  274. }
  275. MoveOnlyString(MoveOnlyString const &) = delete;
  276. MoveOnlyString & operator=(MoveOnlyString && that)
  277. {
  278. sz_ = that.sz_;
  279. that.sz_ = "";
  280. return *this;
  281. }
  282. MoveOnlyString & operator=(MoveOnlyString const &) = delete;
  283. bool operator==(MoveOnlyString const & that) const
  284. {
  285. return 0 == std::strcmp(sz_, that.sz_);
  286. }
  287. bool operator<(const MoveOnlyString & that) const
  288. {
  289. return std::strcmp(sz_, that.sz_) < 0;
  290. }
  291. bool operator!=(MoveOnlyString const & that) const
  292. {
  293. return !(*this == that);
  294. }
  295. friend std::ostream & operator<<(std::ostream & sout, MoveOnlyString const & str)
  296. {
  297. return sout << '"' << str.sz_ << '"';
  298. }
  299. };
  300. RANGES_DIAGNOSTIC_POP
  301. #endif