mimic++ v10.0.1
Loading...
Searching...
No Matches
Common.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_COMMON_HPP
7#define MIMICPP_MATCHERS_COMMON_HPP
8
9#pragma once
10
11#include "mimic++/Fwd.hpp"
16
17#ifndef MIMICPP_DETAIL_IS_MODULE
18 #include <concepts>
19 #include <functional>
20 #include <optional>
21 #include <type_traits>
22#endif
23
25{
26 template <typename Matcher>
28}
29
30namespace mimicpp::detail::describe_hook
31{
32 // This section uses trailing return-types because this seems to help clangd in some cases.
33 template <typename Matcher>
34 [[nodiscard]]
35 constexpr auto describe_impl(util::priority_tag<1> const /*tag*/, Matcher const& matcher)
36 -> decltype(custom::matcher_traits<Matcher>{}.describe(matcher))
37 requires requires {
38 {
39 custom::matcher_traits<Matcher>{}.describe(matcher)
40 } -> util::explicitly_convertible_to<std::optional<StringT>>;
41 }
42 {
43 return custom::matcher_traits<Matcher>{}.describe(matcher);
44 }
45
46 template <typename Matcher>
47 [[nodiscard]]
48 constexpr auto describe_impl(util::priority_tag<0> const /*tag*/, Matcher const& matcher)
49 -> decltype(matcher.describe())
50 requires requires {
51 { matcher.describe() } -> util::explicitly_convertible_to<std::optional<StringT>>;
52 }
53 {
54 return matcher.describe();
55 }
56
57 inline constexpr util::priority_tag<1> maxTag{};
58
59 struct describe_fn
60 {
61 template <typename Matcher>
62 [[nodiscard]]
63 constexpr auto operator()(Matcher const& matcher) const
64 -> decltype(describe_impl(maxTag, matcher))
65 requires requires {
66 { describe_impl(maxTag, matcher) } -> util::explicitly_convertible_to<std::optional<StringT>>;
67 }
68 {
69 return describe_impl(maxTag, matcher);
70 }
71 };
72
73 inline constexpr describe_fn describe{};
74}
75
76namespace mimicpp::detail::matches_hook
77{
78 template <typename Matcher, typename... Ts>
79 [[nodiscard]]
80 expectation::MatchResult matches_impl(util::priority_tag<3> const /*tag*/, Matcher const& matcher, Ts&... targets)
81 requires requires {
82 { custom::matcher_traits<Matcher>{}.matches(matcher, targets...) } -> std::convertible_to<expectation::MatchResult>;
83 }
84 {
85 return custom::matcher_traits<Matcher>{}.matches(matcher, targets...);
86 }
87
88 template <typename Matcher, typename... Ts>
89 [[nodiscard]]
90 expectation::MatchResult matches_impl(util::priority_tag<0> const /*tag*/, Matcher const& matcher, Ts&... targets)
91 requires requires {
92 { matcher.matches(targets...) } -> std::convertible_to<expectation::MatchResult>;
93 }
94 {
95 return matcher.matches(targets...);
96 }
97
98 // deprecated matches overloads
99 template <typename Matcher, typename... Ts>
100 [[nodiscard]]
101 expectation::MatchResult matches_impl(util::priority_tag<0> const /*tag*/, Matcher const& matcher, Ts&... targets)
102 requires requires {
103 { custom::matcher_traits<Matcher>{}.matches(matcher, targets...) } -> util::boolean_testable;
104 }
105 {
106 static_assert(
107 requires{{describe_hook::describe(matcher)}-> util::explicitly_convertible_to<std::optional<StringT>>; },
108 "A legacy matcher requires an appropriate describe-hook.");
109
110 if (custom::matcher_traits<Matcher>{}.matches(matcher, targets...))
111 {
112 return expectation::MatchSuccess{.description = std::optional<StringT>{describe_hook::describe(matcher)}};
113 }
114
115 return expectation::MatchFailure{.description = std::optional<StringT>{describe_hook::describe(matcher)}};
116 }
117
118 template <typename Matcher, typename... Ts>
119 [[nodiscard]]
120 expectation::MatchResult matches_impl(util::priority_tag<0> const /*tag*/, Matcher const& matcher, Ts&... targets)
121 requires requires {
122 { matcher.matches(targets...) } -> util::boolean_testable;
123 }
124 {
125 static_assert(
126 requires {{describe_hook::describe(matcher)}-> util::explicitly_convertible_to<std::optional<StringT>>; },
127 "A legacy matcher requires an appropriate describe-hook.");
128
129 if (matcher.matches(targets...))
130 {
131 return expectation::MatchSuccess{.description = std::optional<StringT>{describe_hook::describe(matcher)}};
132 }
133
134 return expectation::MatchFailure{.description = std::optional<StringT>{describe_hook::describe(matcher)}};
135 }
136
137 inline constexpr util::priority_tag<3> maxTag{};
138
139 struct matches_fn
140 {
141 template <typename Matcher, typename T, typename... Others>
142 [[nodiscard]]
143 expectation::MatchResult operator()(Matcher const& matcher, T& target, Others&... others) const
144 requires requires {
145 { matches_impl(maxTag, matcher, target, others...) } -> std::convertible_to<expectation::MatchResult>;
146 }
147 {
148 return matches_impl(maxTag, matcher, target, others...);
149 }
150 };
151
152 inline constexpr matches_fn matches{};
153}
154
155namespace mimicpp
156{
157 namespace detail
158 {
164 template <typename Matcher, typename... Args>
165 struct is_matcher_accepting
166 : public std::true_type
167 {
168 };
169
170 template <template <typename...> typename is_accepting, typename... Args>
171 struct is_matcher_accepting_helper
172 : public is_accepting<Args...>
173 {
174 };
175
181 template <typename Matcher, typename... Args>
182 requires requires { typename is_matcher_accepting_helper<Matcher::template is_accepting, Args...>; }
183 struct is_matcher_accepting<Matcher, Args...>
184 : public is_matcher_accepting_helper<Matcher::template is_accepting, Args...>
185 {
186 };
187 }
188
199 template <typename Matcher, typename... Args>
200 inline constexpr bool is_matcher_accepting_v{detail::is_matcher_accepting<Matcher, Args...>::value};
201}
202
204{
205 template <typename T, typename First, typename... Others>
206 concept matcher_for = std::same_as<T, std::remove_cvref_t<T>>
207 && std::is_move_constructible_v<T>
208 && std::destructible<T>
209 && is_matcher_accepting_v<T, First, Others...>
210 && requires(T const& matcher, First& first, Others&... others) {
211 { detail::matches_hook::matches(matcher, first, others...) } -> std::convertible_to<expectation::MatchResult>;
212 };
213}
214
215#endif
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
Definition Common.hpp:206
Definition Common.hpp:25
std::variant< MatchSuccess, MatchFailure > MatchResult
Definition Common.hpp:41
Definition Call.hpp:24
constexpr bool is_matcher_accepting_v
Determines, whether the given Matcher accepts the specified Args.
Definition Common.hpp:200
Definition Common.hpp:27
Definition PriorityTag.hpp:24