mimic++ v9.2.1
Loading...
Searching...
No Matches
RangeMatchers.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024 - 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_MATCHERS_RANGE_MATCHERS_HPP
7#define MIMICPP_MATCHERS_RANGE_MATCHERS_HPP
8
9#include "mimic++/Fwd.hpp"
13
14#ifndef MIMICPP_DETAIL_IS_MODULE
15 #include <algorithm>
16 #include <concepts>
17 #include <functional>
18 #include <ranges>
19 #include <tuple>
20 #include <utility>
21#endif
22
23namespace mimicpp::matches::range::detail
24{
25#if MIMICPP_DETAIL_IS_GCC \
26 && __GNUC__ <= 11
27 // This is a small compatibility layer for gcc 11 and prior, because they do just provide a partial
28 // implementation of `std::views::all`. In fact, the `std::ranges::owning_view` impl is completely missing.
29 template <std::ranges::range Range>
30 [[nodiscard]]
31 constexpr auto store(Range&& range)
32 {
33 if constexpr (std::ranges::view<std::decay_t<Range>>)
34 {
35 return std::forward<Range>(range);
36 }
37 else if constexpr (requires { std::ranges::ref_view{std::declval<Range>()}; })
38 {
39 return std::ranges::ref_view{std::forward<Range>(range)};
40 }
41 else
42 {
43 return std::forward<Range>(range);
44 }
45 }
46
47#else
48 constexpr auto store = std::views::all;
49#endif
50}
51
53{
61
69 template <std::ranges::forward_range Range, typename Comparator = std::equal_to<>>
70 [[nodiscard]]
71 constexpr auto eq(Range&& expected, Comparator comparator = Comparator{})
72 {
73 return PredicateMatcher{
74 [comp = std::move(comparator)]<typename Target>(Target&& target, auto& range) // NOLINT(cppcoreguidelines-missing-std-forward)
75 requires std::predicate<
76 Comparator const&,
77 std::ranges::range_reference_t<Target>,
78 std::ranges::range_reference_t<Range>>
79 {
80 return std::ranges::equal(
81 target,
82 range,
83 std::ref(comp));
84 },
85 "elements are {}",
86 "elements are not {}",
87 std::make_tuple(detail::store(std::forward<Range>(expected)))};
88 }
89
97 template <std::ranges::forward_range Range, typename Comparator = std::equal_to<>>
98 [[nodiscard]]
99 constexpr auto unordered_eq(Range&& expected, Comparator comparator = Comparator{})
100 {
101 return PredicateMatcher{
102 [comp = std::move(comparator)]<typename Target>(Target&& target, auto& range) // NOLINT(cppcoreguidelines-missing-std-forward)
103 requires std::predicate<
104 Comparator const&,
105 std::ranges::range_reference_t<Target>,
106 std::ranges::range_reference_t<Range>>
107 {
108 return std::ranges::is_permutation(
109 target,
110 range,
111 std::ref(comp));
112 },
113 "is a permutation of {}",
114 "is not a permutation of {}",
115 std::make_tuple(detail::store(std::forward<Range>(expected)))};
116 }
117
123 template <typename Relation = std::ranges::less>
124 [[nodiscard]]
125 constexpr auto is_sorted(Relation relation = Relation{})
126 {
127 return PredicateMatcher{
128 [rel = std::move(relation)]<typename Target>(Target&& target) // NOLINT(cppcoreguidelines-missing-std-forward)
129 requires std::equivalence_relation<
130 const Relation&,
131 std::ranges::range_reference_t<Target>,
132 std::ranges::range_reference_t<Target>>
133 {
134 return std::ranges::is_sorted(
135 target,
136 std::ref(rel));
137 },
138 "is a sorted range",
139 "is an unsorted range"};
140 }
141
145 [[nodiscard]]
146 constexpr auto is_empty()
147 {
148 return PredicateMatcher{
149 [](std::ranges::range auto&& target) {
150 return std::ranges::empty(target);
151 },
152 "is an empty range",
153 "is not an empty range"};
154 }
155
160 [[nodiscard]]
161 constexpr auto has_size(const std::integral auto expected)
162 {
163 return PredicateMatcher{
164 [](std::ranges::range auto&& target, const std::integral auto size) {
165 return std::cmp_equal(
166 size,
167 std::ranges::size(target));
168 },
169 "has size of {}",
170 "has different size than {}",
171 std::make_tuple(expected)};
172 }
173
178 template <typename Matcher>
179 [[nodiscard]]
180 constexpr auto each_element(Matcher&& matcher)
181 {
182 using MatcherType = std::remove_cvref_t<Matcher>;
183 using arg_storage = mimicpp::detail::arg_storage<
184 MatcherType,
185 std::identity,
186 mimicpp::detail::describe_hook::describe_fn>;
187
188 return PredicateMatcher{
189 []<std::ranges::range Range>(Range&& target, MatcherType const& m) {
190 return std::ranges::all_of(
191 std::forward<Range>(target),
192 [&](auto&& element) {
193 return mimicpp::detail::matches_hook::matches(m, element);
194 });
195 },
196 "each el in range: el {}",
197 "not each el in range: el {}",
198 std::tuple<arg_storage>{std::forward<Matcher>(matcher)}};
199 }
200
205 template <typename Matcher>
206 [[nodiscard]]
207 constexpr auto any_element(Matcher&& matcher)
208 {
209 using MatcherType = std::remove_cvref_t<Matcher>;
210 using arg_storage = mimicpp::detail::arg_storage<
211 MatcherType,
212 std::identity,
213 mimicpp::detail::describe_hook::describe_fn>;
214
215 return PredicateMatcher{
216 []<std::ranges::range Range>(Range&& target, MatcherType const& m) {
217 return std::ranges::any_of(
218 std::forward<Range>(target),
219 [&](auto&& element) {
220 return mimicpp::detail::matches_hook::matches(m, element);
221 });
222 },
223 "any el in range: el {}",
224 "none el in range: el {}",
225 std::tuple<arg_storage>{std::forward<Matcher>(matcher)}};
226 }
227
231}
232
233#endif
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
Generic matcher and the basic building block of most of the built-in matchers.
Definition GeneralMatchers.hpp:75
constexpr auto eq(Range &&expected, Comparator comparator=Comparator{})
Tests, whether the target range compares equal to the expected range, by comparing them element-wise.
Definition RangeMatchers.hpp:71
constexpr auto each_element(Matcher &&matcher)
Tests, whether each element of the target range matches the specified matcher.
Definition RangeMatchers.hpp:180
constexpr auto unordered_eq(Range &&expected, Comparator comparator=Comparator{})
Tests, whether the target range is a permutation of the expected range, by comparing them element-wis...
Definition RangeMatchers.hpp:99
constexpr auto any_element(Matcher &&matcher)
Tests, whether any element of the target range matches the specified matcher.
Definition RangeMatchers.hpp:207
constexpr auto has_size(const std::integral auto expected)
Tests, whether the target range has the expected size.
Definition RangeMatchers.hpp:161
constexpr auto is_sorted(Relation relation=Relation{})
Tests, whether the target range is sorted, by applying the relation on each adjacent elements.
Definition RangeMatchers.hpp:125
constexpr auto is_empty()
Tests, whether the target range is empty.
Definition RangeMatchers.hpp:146
Definition RangeMatchers.hpp:24