mimic++ v5
Loading...
Searching...
No Matches
ExpectationPolicies.hpp
Go to the documentation of this file.
1// // Copyright Dominic (DNKpp) Koepke 2024 - 2024.
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_EXPECTATION_POLICIES_HPP
7#define MIMICPP_EXPECTATION_POLICIES_HPP
8
9#pragma once
10
12#include "mimic++/Matcher.hpp"
13#include "mimic++/Printer.hpp"
14#include "mimic++/Utility.hpp"
15
16#include <cassert>
17#include <functional>
18
20{
22 {
23 public:
24 template <typename Return, typename... Args>
25 static constexpr void finalize_call(const call::Info<Return, Args...>&) noexcept
26 {
27 }
28 };
29
30 template <ValueCategory expected>
32 {
33 public:
34 static constexpr bool is_satisfied() noexcept
35 {
36 return true;
37 }
38
39 template <typename Return, typename... Args>
40 static constexpr bool matches(const call::Info<Return, Args...>& info) noexcept
41 {
42 return mimicpp::is_matching(info.fromCategory, expected);
43 }
44
45 template <typename Return, typename... Args>
46 static constexpr void consume([[maybe_unused]] const call::Info<Return, Args...>& info) noexcept
47 {
48 assert(mimicpp::is_matching(info.fromCategory, expected) && "Call does not match.");
49 }
50
51 [[nodiscard]]
53 {
54 return format::format(
55 "expect: from {} category overload",
56 expected);
57 }
58 };
59
60 template <Constness constness>
62 {
63 public:
64 static constexpr bool is_satisfied() noexcept
65 {
66 return true;
67 }
68
69 template <typename Return, typename... Args>
70 static constexpr bool matches(const call::Info<Return, Args...>& info) noexcept
71 {
72 return mimicpp::is_matching(info.fromConstness, constness);
73 }
74
75 template <typename Return, typename... Args>
76 static constexpr void consume([[maybe_unused]] const call::Info<Return, Args...>& info) noexcept
77 {
78 assert(mimicpp::is_matching(info.fromConstness, constness) && "Call does not match.");
79 }
80
81 [[nodiscard]]
83 {
84 return format::format(
85 "expect: from {} qualified overload",
86 constness);
87 }
88 };
89
90 template <typename Action>
91 requires std::same_as<Action, std::remove_cvref_t<Action>>
92 && std::is_move_constructible_v<Action>
94 {
95 public:
96 [[nodiscard]]
97 explicit constexpr ReturnsResultOf(
98 Action&& action) noexcept(std::is_nothrow_move_constructible_v<Action>)
99 : m_Action{std::move(action)}
100 {
101 }
102
103 template <typename Return, typename... Args>
104 requires std::invocable<Action&, const call::Info<Return, Args...>&>
106 std::invoke_result_t<Action&, const call::Info<Return, Args...>&>,
107 Return>
108 [[nodiscard]]
109 constexpr Return finalize_call(
110 [[maybe_unused]] const call::Info<Return, Args...>& call) noexcept(std::is_nothrow_invocable_v<Action&, const call::Info<Return, Args...>&> && nothrow_explicitly_convertible_to<std::invoke_result_t<Action&, const call::Info<Return, Args...>&>, Return>)
111 {
112 return static_cast<Return>(
113 std::invoke(m_Action, call));
114 }
115
116 private:
117 Action m_Action;
118 };
119
120 template <typename Exception>
121 requires(!std::is_reference_v<Exception>)
122 && std::copyable<Exception>
123 class Throws
124 {
125 public:
126 [[nodiscard]]
127 explicit constexpr Throws(Exception exception) noexcept(std::is_nothrow_move_constructible_v<Exception>)
128 : m_Exception{std::move(exception)}
129 {
130 }
131
132 template <typename Return, typename... Args>
133 constexpr Return finalize_call(
134 [[maybe_unused]] const call::Info<Return, Args...>& call)
135 {
136 throw m_Exception; // NOLINT(hicpp-exception-baseclass)
137 }
138
139 private:
140 Exception m_Exception;
141 };
142
143 template <typename Matcher, typename Projection, typename Describer>
144 requires std::same_as<Matcher, std::remove_cvref_t<Matcher>>
145 && std::same_as<Projection, std::remove_cvref_t<Projection>>
146 && std::same_as<Describer, std::remove_cvref_t<Describer>>
147 && std::is_move_constructible_v<Matcher>
148 && std::is_move_constructible_v<Projection>
149 && std::is_move_constructible_v<Describer>
151 {
152 public:
153 [[nodiscard]]
154 explicit constexpr Requirement(
155 Matcher matcher,
156 Projection projection = {},
157 Describer describer = {}) noexcept(std::is_nothrow_move_constructible_v<Matcher> && std::is_nothrow_move_constructible_v<Projection> && std::is_nothrow_move_constructible_v<Describer>)
158 : m_Matcher{std::move(matcher)},
159 m_Projection{std::move(projection)},
160 m_Describer{std::move(describer)}
161 {
162 }
163
164 static constexpr bool is_satisfied() noexcept
165 {
166 return true;
167 }
168
169 template <typename Return, typename... Args>
170 requires std::invocable<const Projection&, const call::Info<Return, Args...>&>
171 && matcher_for<
172 Matcher,
173 std::invoke_result_t<const Projection&, const call::Info<Return, Args...>&>>
174 [[nodiscard]]
175 constexpr bool matches(const call::Info<Return, Args...>& info) const
176 {
177 decltype(auto) projected = std::invoke(m_Projection, info);
178 return detail::matches_hook::matches(
179 m_Matcher,
180 projected);
181 }
182
183 template <typename Return, typename... Args>
184 static constexpr void consume([[maybe_unused]] const call::Info<Return, Args...>& info) noexcept
185 {
186 }
187
188 [[nodiscard]]
190 {
191 return std::invoke(
192 m_Describer,
193 detail::describe_hook::describe(m_Matcher));
194 }
195
196 private:
197 [[no_unique_address]] Matcher m_Matcher;
198 [[no_unique_address]] Projection m_Projection;
199 [[no_unique_address]] Describer m_Describer;
200 };
201
202 template <typename Action>
204 {
205 public:
206 ~SideEffectAction() = default;
207
208 [[nodiscard]]
209 explicit constexpr SideEffectAction(
210 Action&& action) noexcept(std::is_nothrow_move_constructible_v<Action>)
211 : m_Action{std::move(action)}
212 {
213 }
214
217
218 [[nodiscard]]
221
222 static constexpr bool is_satisfied() noexcept
223 {
224 return true;
225 }
226
227 template <typename Return, typename... Args>
228 [[nodiscard]]
229 static constexpr bool matches(const call::Info<Return, Args...>&) noexcept
230 {
231 return true;
232 }
233
234 [[nodiscard]]
235 static std::nullopt_t describe() noexcept
236 {
237 return std::nullopt;
238 }
239
240 template <typename Return, typename... Args>
241 requires std::invocable<Action&, const call::Info<Return, Args...>&>
242 constexpr void consume(
243 const call::Info<Return, Args...>& info) noexcept(std::is_nothrow_invocable_v<Action&, const call::Info<Return, Args...>&>)
244 {
245 std::invoke(m_Action, info);
246 }
247
248 private:
249 Action m_Action;
250 };
251
252 template <typename Action, template <typename> typename Projection>
253 requires std::same_as<Action, std::remove_cvref_t<Action>>
255 {
256 public:
257 [[nodiscard]]
258 explicit constexpr ApplyAllArgsAction(
259 Action action = {}) noexcept(std::is_nothrow_move_constructible_v<Action>)
260 : m_Action{std::move(action)}
261 {
262 }
263
264 template <typename Arg>
265 using ProjectedArgT = Projection<Arg>;
266
267 template <typename Return, typename... Args>
268 requires std::invocable<
269 const Action&,
271 constexpr decltype(auto) operator()(
272 const call::Info<Return, Args...>& callInfo) const noexcept(std::is_nothrow_invocable_v<const Action&, ProjectedArgT<Args>...>)
273 {
274 static_assert(
276 "Projection can not be applied.");
277
278 return std::apply(
279 [this](auto&... args) -> decltype(auto) {
280 return std::invoke(
281 m_Action,
282 static_cast<ProjectedArgT<Args>>(
283 args.get())...);
284 },
285 callInfo.args);
286 }
287
288 private:
289 Action m_Action;
290 };
291
292 template <typename Action, template <typename> typename Projection, std::size_t... indices>
293 requires std::same_as<Action, std::remove_cvref_t<Action>>
295 {
296 public:
297 [[nodiscard]]
298 explicit constexpr ApplyArgsAction(
299 Action action = {}) noexcept(std::is_nothrow_move_constructible_v<Action>)
300 : m_Action{std::move(action)}
301 {
302 }
303
304 template <std::size_t index, typename... Args>
305 using ArgListElementT = std::tuple_element_t<index, std::tuple<Args...>>;
306
307 template <std::size_t index, typename... Args>
308 using ProjectedArgListElementT = Projection<ArgListElementT<index, Args...>>;
309
310 template <typename Return, typename... Args>
311 requires(... && (indices < sizeof...(Args)))
312 && std::invocable<
313 const Action&,
314 ProjectedArgListElementT<indices, Args...>...>
315 constexpr decltype(auto) operator()(
316 const call::Info<Return, Args...>& callInfo) const noexcept(std::is_nothrow_invocable_v<const Action&, ProjectedArgListElementT<indices, Args...>...>)
317 {
318 static_assert(
320 ArgListElementT<indices, Args...>&,
321 ProjectedArgListElementT<indices, Args...>>
322 && ...),
323 "Projection can not be applied.");
324
325 return std::invoke(
326 m_Action,
327 static_cast<ProjectedArgListElementT<indices, Args...>>(
328 std::get<indices>(callInfo.args).get())...);
329 }
330
331 private:
332 [[no_unique_address]] Action m_Action;
333 };
334}
335
336namespace mimicpp::expect
337{
338 namespace detail
339 {
340 template <std::size_t index>
341 struct arg_requirement_describer
342 {
343 [[nodiscard]]
344 constexpr StringT operator()(
345 const StringViewT matcherDescription) const
346 {
347 return format::format(
348 "expect: arg[{}] {}",
349 index,
350 matcherDescription);
351 }
352 };
353 }
354
378 template <std::size_t index, typename Matcher, typename Projection = std::identity>
379 [[nodiscard]]
380 constexpr auto arg(
381 Matcher&& matcher,
382 Projection projection = {}) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Matcher>, Matcher> && std::is_nothrow_move_constructible_v<Projection>)
383 {
384 using ProjectionT = expectation_policies::ApplyArgsAction<
385 Projection,
386 std::add_lvalue_reference_t,
387 index>;
388 using PolicyT = expectation_policies::Requirement<
389 std::remove_cvref_t<Matcher>,
390 ProjectionT,
391 detail::arg_requirement_describer<index>>;
392
393 return PolicyT{
394 std::forward<Matcher>(matcher),
395 ProjectionT{std::move(projection)}};
396 }
397
401}
402
404{
405 // ReSharper disable CppDoxygenUnresolvedReference
406
436 template <typename Fun>
437 requires std::invocable<std::remove_cvref_t<Fun>&>
438 && (!std::is_void_v<std::invoke_result_t<std::remove_cvref_t<Fun>&>>)
439 [[nodiscard]]
440 constexpr auto returns_result_of(
441 Fun&& fun) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Fun>, Fun>)
442 {
444 [fn = std::forward<Fun>(fun)]([[maybe_unused]] const auto& call) mutable noexcept(std::is_nothrow_invocable_v<decltype(fun)>) -> decltype(auto) {
445 return std::invoke(fn);
446 }};
447 }
448
466 template <typename T>
467 requires std::copyable<std::remove_cvref_t<T>>
468 [[nodiscard]]
469 constexpr auto returns(
470 T&& value // NOLINT(cppcoreguidelines-missing-std-forward)
471 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<T>, T>)
472 {
474 [v = std::forward<T>(value)]([[maybe_unused]] const auto& call) mutable noexcept -> auto& {
475 return static_cast<std::unwrap_reference_t<decltype(v)>&>(v);
476 }};
477 }
478
491 template <std::size_t index, std::size_t... otherIndices, typename Action>
492 [[nodiscard]]
494 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
495 {
497 std::remove_cvref_t<Action>,
498 std::add_lvalue_reference_t,
499 index,
500 otherIndices...>;
501
503 ActionT{std::forward<Action>(action)}};
504 }
505
516 template <typename Action>
517 [[nodiscard]]
519 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
520 {
522 std::remove_cvref_t<Action>,
523 std::add_lvalue_reference_t>;
524
526 ActionT{std::forward<Action>(action)}};
527 }
528
536 template <std::size_t index>
537 [[nodiscard]]
538 constexpr auto returns_arg() noexcept
539 {
541 std::identity,
542 std::add_rvalue_reference_t,
543 index>;
544
546 ActionT{}};
547 }
548
558 template <typename T>
559 requires std::copyable<std::remove_cvref_t<T>>
560 [[nodiscard]]
562 T&& exception) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<T>, T>)
563 {
565 std::forward<T>(exception)};
566 }
567
572 // ReSharper restore CppDoxygenUnresolvedReference
573}
574
576{
605 template <std::size_t index, typename Action>
606 [[nodiscard]]
607 constexpr auto apply_arg(
608 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
609 {
611 std::remove_cvref_t<Action>,
612 std::add_lvalue_reference_t,
613 index>;
614
616 ActionT{std::forward<Action>(action)}};
617 }
618
629 template <std::size_t index, std::size_t... additionalIndices, typename Action>
630 [[nodiscard]]
631 constexpr auto apply_args(
632 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
633 {
635 std::remove_cvref_t<Action>,
636 std::add_lvalue_reference_t,
637 index,
638 additionalIndices...>;
639
641 ActionT{std::forward<Action>(action)}};
642 }
643
650 template <typename Action>
651 [[nodiscard]]
652 constexpr auto apply_all(
653 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
654 {
656 std::remove_cvref_t<Action>,
657 std::add_lvalue_reference_t>;
658
660 ActionT{std::forward<Action>(action)}};
661 }
662
669 template <std::invocable Action>
670 [[nodiscard]]
671 constexpr auto invoke(
672 Action&& action) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
673 {
675 [fn = std::forward<Action>(action)]([[maybe_unused]] const auto& call) mutable noexcept(std::is_nothrow_invocable_v<Action&>) {
676 std::invoke(fn);
677 }};
678 }
679
683}
684
685#endif
Definition Fwd.hpp:17
Definition ExpectationPolicies.hpp:255
constexpr decltype(auto) operator()(const call::Info< Return, Args... > &callInfo) const noexcept(std::is_nothrow_invocable_v< const Action &, ProjectedArgT< Args >... >)
Definition ExpectationPolicies.hpp:271
constexpr ApplyAllArgsAction(Action action={}) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:258
Projection< Arg > ProjectedArgT
Definition ExpectationPolicies.hpp:265
Definition ExpectationPolicies.hpp:295
constexpr decltype(auto) operator()(const call::Info< Return, Args... > &callInfo) const noexcept(std::is_nothrow_invocable_v< const Action &, ProjectedArgListElementT< indices, Args... >... >)
Definition ExpectationPolicies.hpp:315
std::tuple_element_t< index, std::tuple< Args... > > ArgListElementT
Definition ExpectationPolicies.hpp:305
constexpr ApplyArgsAction(Action action={}) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:298
Projection< ArgListElementT< index, Args... > > ProjectedArgListElementT
Definition ExpectationPolicies.hpp:308
Definition ExpectationPolicies.hpp:32
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:34
static constexpr void consume(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:46
static StringT describe()
Definition ExpectationPolicies.hpp:52
static constexpr bool matches(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:40
Definition ExpectationPolicies.hpp:62
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:64
static constexpr void consume(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:76
static constexpr bool matches(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:70
static StringT describe()
Definition ExpectationPolicies.hpp:82
Definition ExpectationPolicies.hpp:22
static constexpr void finalize_call(const call::Info< Return, Args... > &) noexcept
Definition ExpectationPolicies.hpp:25
Definition ExpectationPolicies.hpp:151
static constexpr void consume(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:184
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:164
constexpr bool matches(const call::Info< Return, Args... > &info) const
Definition ExpectationPolicies.hpp:175
constexpr Requirement(Matcher matcher, Projection projection={}, Describer describer={}) noexcept(std::is_nothrow_move_constructible_v< Matcher > &&std::is_nothrow_move_constructible_v< Projection > &&std::is_nothrow_move_constructible_v< Describer >)
Definition ExpectationPolicies.hpp:154
StringT describe() const
Definition ExpectationPolicies.hpp:189
Definition ExpectationPolicies.hpp:94
constexpr Return finalize_call(const call::Info< Return, Args... > &call) noexcept(std::is_nothrow_invocable_v< Action &, const call::Info< Return, Args... > & > &&nothrow_explicitly_convertible_to< std::invoke_result_t< Action &, const call::Info< Return, Args... > & >, Return >)
Definition ExpectationPolicies.hpp:109
constexpr ReturnsResultOf(Action &&action) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:97
Definition ExpectationPolicies.hpp:204
static constexpr bool matches(const call::Info< Return, Args... > &) noexcept
Definition ExpectationPolicies.hpp:229
static std::nullopt_t describe() noexcept
Definition ExpectationPolicies.hpp:235
constexpr void consume(const call::Info< Return, Args... > &info) noexcept(std::is_nothrow_invocable_v< Action &, const call::Info< Return, Args... > & >)
Definition ExpectationPolicies.hpp:242
SideEffectAction & operator=(const SideEffectAction &)=delete
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:222
SideEffectAction(SideEffectAction &&)=default
constexpr SideEffectAction(Action &&action) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:209
SideEffectAction & operator=(SideEffectAction &&)=default
SideEffectAction(const SideEffectAction &)=delete
Definition ExpectationPolicies.hpp:124
constexpr Return finalize_call(const call::Info< Return, Args... > &call)
Definition ExpectationPolicies.hpp:133
constexpr Throws(Exception exception) noexcept(std::is_nothrow_move_constructible_v< Exception >)
Definition ExpectationPolicies.hpp:127
Definition Utility.hpp:51
Definition Matcher.hpp:110
constexpr auto returns_apply_all_result_of(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
During the finalization step, all call arguments are applied on the given action.
Definition ExpectationPolicies.hpp:518
constexpr auto returns_apply_result_of(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
During the finalization step, the selected call arguments are applied on the given action.
Definition ExpectationPolicies.hpp:493
constexpr auto returns(T &&value) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< T >, T >)
During the finalization step, the stored value is returned.
Definition ExpectationPolicies.hpp:469
constexpr auto returns_arg() noexcept
During the finalization step, the selected call argument is returned.
Definition ExpectationPolicies.hpp:538
constexpr auto returns_result_of(Fun &&fun) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Fun >, Fun >)
During the finalization step, the invocation result of the given function is returned.
Definition ExpectationPolicies.hpp:440
constexpr auto arg(Matcher &&matcher, Projection projection={}) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Matcher >, Matcher > &&std::is_nothrow_move_constructible_v< Projection >)
Checks, whether the selected argument matches the given matcher.
Definition ExpectationPolicies.hpp:380
constexpr auto apply_all(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
Applies all arguments on the given action.
Definition ExpectationPolicies.hpp:652
constexpr auto apply_arg(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
Applies the argument at the specified index on the given action.
Definition ExpectationPolicies.hpp:607
constexpr auto invoke(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
Invokes the given function.
Definition ExpectationPolicies.hpp:671
constexpr auto apply_args(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
Applies the arguments at the specified index and in that order on the given action.
Definition ExpectationPolicies.hpp:631
Definition ControlPolicy.hpp:252
Definition ExpectationPolicies.hpp:20
Definition ExpectationPolicies.hpp:404
Definition ExpectationPolicies.hpp:576
constexpr bool is_matching(const Constness lhs, const Constness rhs) noexcept
Definition Utility.hpp:107
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:343
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:342