mimic++ v6
Loading...
Searching...
No Matches
GeneralMatchers.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_GENERAL_MATCHERS_HPP
7#define MIMICPP_MATCHERS_GENERAL_MATCHERS_HPP
8
9#pragma once
10
11#include "mimic++/Fwd.hpp"
13
14#include <functional>
15#include <tuple>
16#include <type_traits>
17#include <utility>
18
19namespace mimicpp::detail
20{
21 template <typename Arg, typename MatchesProjection = std::identity, typename DescribeProjection = PrintFn>
22 struct arg_storage
23 {
24 using matches_reference = std::invoke_result_t<MatchesProjection, const Arg&>;
25 using describe_reference = std::invoke_result_t<DescribeProjection, const Arg&>;
26
27 Arg arg;
28
29 decltype(auto) as_matches_arg() const noexcept(std::is_nothrow_invocable_v<MatchesProjection, const Arg&>)
30 {
31 return std::invoke(MatchesProjection{}, arg);
32 }
33
34 decltype(auto) as_describe_arg() const noexcept(std::is_nothrow_invocable_v<DescribeProjection, const Arg&>)
35 {
36 return std::invoke(DescribeProjection{}, arg);
37 }
38 };
39
40 template <typename T>
41 struct to_arg_storage
42 {
43 using type = arg_storage<T>;
44 };
45
46 template <typename Arg, typename MatchesProjection, typename DescribeProjection>
47 struct to_arg_storage<arg_storage<Arg, MatchesProjection, DescribeProjection>>
48 {
49 using type = arg_storage<Arg, MatchesProjection, DescribeProjection>;
50 };
51
52 template <typename T>
53 using to_arg_storage_t = typename to_arg_storage<T>::type;
54}
55
56namespace mimicpp
57{
64 template <typename Predicate, typename... AdditionalArgs>
65 requires std::is_move_constructible_v<Predicate>
66 && (... && std::is_move_constructible_v<AdditionalArgs>)
68 {
69 private:
70 using storage_t = std::tuple<detail::to_arg_storage_t<AdditionalArgs>...>;
71 template <typename T>
72 using matches_reference_t = typename detail::to_arg_storage_t<T>::matches_reference;
73
74 public:
75 [[nodiscard]]
76 explicit constexpr PredicateMatcher(
77 Predicate predicate,
78 StringViewT fmt,
79 StringViewT invertedFmt,
80 std::tuple<AdditionalArgs...> additionalArgs = {})
81 noexcept(
82 std::is_nothrow_move_constructible_v<Predicate>
83 && (... && std::is_nothrow_move_constructible_v<AdditionalArgs>))
84 : m_Predicate{std::move(predicate)},
85 m_FormatString{std::move(fmt)},
86 m_InvertedFormatString{std::move(invertedFmt)},
87 m_AdditionalArgs{std::move(additionalArgs)}
88 {
89 }
90
91 template <typename First, typename... Others>
92 requires std::predicate<
93 const Predicate&,
94 First&,
95 Others&...,
96 matches_reference_t<AdditionalArgs>...>
97 [[nodiscard]]
98 constexpr bool matches(
99 First& first,
100 Others&... others) const
101 noexcept(
102 std::is_nothrow_invocable_v<
103 const Predicate&,
104 First&,
105 Others&...,
106 matches_reference_t<AdditionalArgs>...>)
107 {
108 return std::apply(
109 [&, this](auto&... additionalArgs) {
110 return std::invoke(
111 m_Predicate,
112 first,
113 others...,
114 additionalArgs.as_matches_arg()...);
115 },
116 m_AdditionalArgs);
117 }
118
119 [[nodiscard]]
120 constexpr StringT describe() const
121 {
122 return std::apply(
123 [&, this](auto&... additionalArgs) {
124 return format::vformat(
125 m_FormatString,
126 format::make_format_args(
127 std::invoke(
128 // std::make_format_args requires lvalue-refs, so let's transform rvalue-refs to const lvalue-refs
129 [](auto&& val) noexcept -> const auto& { return val; },
130 additionalArgs.as_describe_arg())...));
131 },
132 m_AdditionalArgs);
133 }
134
135 [[nodiscard]]
136 constexpr auto operator!() const&
137 requires std::is_copy_constructible_v<Predicate>
138 && std::is_copy_constructible_v<storage_t>
139 {
140 return make_inverted(
141 m_Predicate,
142 m_InvertedFormatString,
143 m_FormatString,
144 m_AdditionalArgs);
145 }
146
147 [[nodiscard]]
148 constexpr auto operator!() &&
149 {
150 return make_inverted(
151 std::move(m_Predicate),
152 std::move(m_InvertedFormatString),
153 std::move(m_FormatString),
154 std::move(m_AdditionalArgs));
155 }
156
157 private:
158 [[no_unique_address]] Predicate m_Predicate;
159 StringViewT m_FormatString;
160 StringViewT m_InvertedFormatString;
161 storage_t m_AdditionalArgs;
162
163 template <typename Fn>
164 [[nodiscard]]
165 static constexpr auto make_inverted(
166 Fn&& fn,
167 StringViewT fmt,
168 StringViewT invertedFmt,
169 storage_t tuple)
170 {
171 using NotFnT = decltype(std::not_fn(std::forward<Fn>(fn)));
173 std::not_fn(std::forward<Fn>(fn)),
174 std::move(fmt),
175 std::move(invertedFmt),
176 std::move(tuple)};
177 }
178 };
179
186 {
187 public:
188 static constexpr bool matches([[maybe_unused]] auto&& target) noexcept
189 {
190 return true;
191 }
192
193 static constexpr StringViewT describe() noexcept
194 {
195 return "has no constraints";
196 }
197 };
198}
199
200namespace mimicpp::matches
201{
233
238 [[maybe_unused]] inline constexpr WildcardMatcher _{};
239
245 template <typename T>
246 [[nodiscard]]
247 constexpr auto eq(T&& value)
248 {
249 return PredicateMatcher{
250 std::equal_to{},
251 "== {}",
252 "!= {}",
253 std::make_tuple(std::forward<T>(value))};
254 }
255
261 template <typename T>
262 [[nodiscard]]
263 constexpr auto ne(T&& value)
264 {
265 return PredicateMatcher{
266 std::not_equal_to{},
267 "!= {}",
268 "== {}",
269 std::make_tuple(std::forward<T>(value))};
270 }
271
277 template <typename T>
278 [[nodiscard]]
279 constexpr auto lt(T&& value)
280 {
281 return PredicateMatcher{
282 std::less{},
283 "< {}",
284 ">= {}",
285 std::make_tuple(std::forward<T>(value))};
286 }
287
293 template <typename T>
294 [[nodiscard]]
295 constexpr auto le(T&& value)
296 {
297 return PredicateMatcher{
298 std::less_equal{},
299 "<= {}",
300 "> {}",
301 std::make_tuple(std::forward<T>(value))};
302 }
303
309 template <typename T>
310 [[nodiscard]]
311 constexpr auto gt(T&& value)
312 {
313 return PredicateMatcher{
314 std::greater{},
315 "> {}",
316 "<= {}",
317 std::make_tuple(std::forward<T>(value))};
318 }
319
325 template <typename T>
326 [[nodiscard]]
327 constexpr auto ge(T&& value)
328 {
329 return PredicateMatcher{
330 std::greater_equal{},
331 ">= {}",
332 "< {}",
333 std::make_tuple(std::forward<T>(value))};
334 }
335
344 template <typename UnaryPredicate>
345 [[nodiscard]]
346 constexpr auto predicate(
347 UnaryPredicate&& predicate,
348 StringViewT description = "passes predicate",
349 StringViewT invertedDescription = "fails predicate")
350 {
351 return PredicateMatcher{
352 std::forward<UnaryPredicate>(predicate),
353 std::move(description),
354 std::move(invertedDescription),
355 };
356 }
357
364 template <satisfies<std::is_lvalue_reference> T>
365 [[nodiscard]]
366 constexpr auto instance(T&& instance) // NOLINT(cppcoreguidelines-missing-std-forward)
367 {
368 return PredicateMatcher{
369 [](const std::remove_cvref_t<T>& target, const auto* instancePtr) noexcept {
370 return std::addressof(target) == instancePtr;
371 },
372 "is instance at {}",
373 "is not instance at {}",
374 std::make_tuple(std::addressof(instance))};
375 }
376
380}
381
382#endif
Generic matcher and the basic building block of most of the built-in matchers.
Definition GeneralMatchers.hpp:68
constexpr bool matches(First &first, Others &... others) const noexcept(std::is_nothrow_invocable_v< const Predicate &, First &, Others &..., matches_reference_t< AdditionalArgs >... >)
Definition GeneralMatchers.hpp:98
constexpr auto operator!() const &
Definition GeneralMatchers.hpp:136
constexpr auto operator!() &&
Definition GeneralMatchers.hpp:148
constexpr StringT describe() const
Definition GeneralMatchers.hpp:120
constexpr PredicateMatcher(Predicate predicate, StringViewT fmt, StringViewT invertedFmt, std::tuple< AdditionalArgs... > additionalArgs={}) noexcept(std::is_nothrow_move_constructible_v< Predicate > &&(... &&std::is_nothrow_move_constructible_v< AdditionalArgs >))
Definition GeneralMatchers.hpp:76
Matcher, which never fails.
Definition GeneralMatchers.hpp:186
static constexpr bool matches(auto &&target) noexcept
Definition GeneralMatchers.hpp:188
static constexpr StringViewT describe() noexcept
Definition GeneralMatchers.hpp:193
constexpr auto lt(T &&value)
Tests, whether the target is less than the expected value.
Definition GeneralMatchers.hpp:279
constexpr auto instance(T &&instance)
Tests, whether the target is the expected instance.
Definition GeneralMatchers.hpp:366
constexpr auto le(T &&value)
Tests, whether the target is less than or equal to the expected value.
Definition GeneralMatchers.hpp:295
constexpr WildcardMatcher _
The wildcard matcher, always matching.
Definition GeneralMatchers.hpp:238
constexpr auto eq(T &&value)
Tests, whether the target compares equal to the expected value.
Definition GeneralMatchers.hpp:247
constexpr auto gt(T &&value)
Tests, whether the target is greater than the expected value.
Definition GeneralMatchers.hpp:311
constexpr auto predicate(UnaryPredicate &&predicate, StringViewT description="passes predicate", StringViewT invertedDescription="fails predicate")
Tests, whether the target fulfills the given predicate.
Definition GeneralMatchers.hpp:346
constexpr auto ge(T &&value)
Tests, whether the target is greater than or equal to the expected value.
Definition GeneralMatchers.hpp:327
constexpr auto ne(T &&value)
Tests, whether the target compares not equal to the expected value.
Definition GeneralMatchers.hpp:263
Definition FloatingPointMatchers.hpp:22
Definition BoostTest.hpp:20
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:345
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:344