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