mimic++ v4
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
99 ) noexcept(std::is_nothrow_move_constructible_v<Action>)
100 : m_Action{std::move(action)}
101 {
102 }
103
104 template <typename Return, typename... Args>
105 requires std::invocable<Action&, const call::Info<Return, Args...>&>
107 std::invoke_result_t<Action&, const call::Info<Return, Args...>&>,
108 Return>
109 [[nodiscard]]
110 constexpr Return finalize_call(
111 [[maybe_unused]] const call::Info<Return, Args...>& call
112 ) noexcept(
113 std::is_nothrow_invocable_v<Action&, const call::Info<Return, Args...>&>
115 std::invoke_result_t<Action&, const call::Info<Return, Args...>&>,
116 Return>)
117 {
118 return static_cast<Return>(
119 std::invoke(m_Action, call));
120 }
121
122 private:
123 Action m_Action;
124 };
125
126 template <typename Exception>
127 requires (!std::is_reference_v<Exception>)
128 && std::copyable<Exception>
129 class Throws
130 {
131 public:
132 [[nodiscard]]
133 explicit constexpr Throws(Exception exception) noexcept(std::is_nothrow_move_constructible_v<Exception>)
134 : m_Exception{std::move(exception)}
135 {
136 }
137
138 template <typename Return, typename... Args>
139 constexpr Return finalize_call(
140 [[maybe_unused]] const call::Info<Return, Args...>& call
141 )
142 {
143 throw m_Exception; // NOLINT(hicpp-exception-baseclass)
144 }
145
146 private:
147 Exception m_Exception;
148 };
149
150 template <typename Matcher, typename Projection, typename Describer>
151 requires std::same_as<Matcher, std::remove_cvref_t<Matcher>>
152 && std::same_as<Projection, std::remove_cvref_t<Projection>>
153 && std::same_as<Describer, std::remove_cvref_t<Describer>>
154 && std::is_move_constructible_v<Matcher>
155 && std::is_move_constructible_v<Projection>
156 && std::is_move_constructible_v<Describer>
158 {
159 public:
160 [[nodiscard]]
161 explicit constexpr Requirement(
162 Matcher matcher,
163 Projection projection = {},
164 Describer describer = {}
165 ) noexcept(
166 std::is_nothrow_move_constructible_v<Matcher>
167 && std::is_nothrow_move_constructible_v<Projection>
168 && std::is_nothrow_move_constructible_v<Describer>)
169 : m_Matcher{std::move(matcher)},
170 m_Projection{std::move(projection)},
171 m_Describer{std::move(describer)}
172 {
173 }
174
175 static constexpr bool is_satisfied() noexcept
176 {
177 return true;
178 }
179
180 template <typename Return, typename... Args>
181 requires std::invocable<const Projection&, const call::Info<Return, Args...>&>
182 && matcher_for<
183 Matcher,
184 std::invoke_result_t<const Projection&, const call::Info<Return, Args...>&>>
185 [[nodiscard]]
186 constexpr bool matches(const call::Info<Return, Args...>& info) const
187 {
188 decltype(auto) projected = std::invoke(m_Projection, info);
189 return detail::matches_hook::matches(
190 m_Matcher,
191 projected);
192 }
193
194 template <typename Return, typename... Args>
195 static constexpr void consume([[maybe_unused]] const call::Info<Return, Args...>& info) noexcept
196 {
197 }
198
199 [[nodiscard]]
201 {
202 return std::invoke(
203 m_Describer,
204 detail::describe_hook::describe(m_Matcher));
205 }
206
207 private:
208 [[no_unique_address]] Matcher m_Matcher;
209 [[no_unique_address]] Projection m_Projection;
210 [[no_unique_address]] Describer m_Describer;
211 };
212
213 template <typename Action>
215 {
216 public:
217 ~SideEffectAction() = default;
218
219 [[nodiscard]]
220 explicit constexpr SideEffectAction(
221 Action&& action
222 ) noexcept(std::is_nothrow_move_constructible_v<Action>)
223 : m_Action{std::move(action)}
224 {
225 }
226
229
230 [[nodiscard]]
233
234 static constexpr bool is_satisfied() noexcept
235 {
236 return true;
237 }
238
239 template <typename Return, typename... Args>
240 [[nodiscard]]
241 static constexpr bool matches(const call::Info<Return, Args...>&) noexcept
242 {
243 return true;
244 }
245
246 [[nodiscard]]
247 static std::nullopt_t describe() noexcept
248 {
249 return std::nullopt;
250 }
251
252 template <typename Return, typename... Args>
253 requires std::invocable<Action&, const call::Info<Return, Args...>&>
254 constexpr void consume(
256 ) noexcept(std::is_nothrow_invocable_v<Action&, const call::Info<Return, Args...>&>)
257 {
258 std::invoke(m_Action, info);
259 }
260
261 private:
262 Action m_Action;
263 };
264
265 template <typename Action, template <typename> typename Projection>
266 requires std::same_as<Action, std::remove_cvref_t<Action>>
268 {
269 public:
270 [[nodiscard]]
271 explicit constexpr ApplyAllArgsAction(
272 Action action = {}
273 ) noexcept(std::is_nothrow_move_constructible_v<Action>)
274 : m_Action{std::move(action)}
275 {
276 }
277
278 template <typename Arg>
279 using ProjectedArgT = Projection<Arg>;
280
281 template <typename Return, typename... Args>
282 requires std::invocable<
283 const Action&,
285 constexpr decltype(auto) operator ()(
286 const call::Info<Return, Args...>& callInfo
287 ) const noexcept(
288 std::is_nothrow_invocable_v<
289 const Action&,
291 {
292 static_assert(
294 "Projection can not be applied.");
295
296 return std::apply(
297 [this](auto&... args) -> decltype(auto)
298 {
299 return std::invoke(
300 m_Action,
301 static_cast<ProjectedArgT<Args>>(
302 args.get())...);
303 },
304 callInfo.args);
305 }
306
307 private:
308 Action m_Action;
309 };
310
311 template <typename Action, template <typename> typename Projection, std::size_t... indices>
312 requires std::same_as<Action, std::remove_cvref_t<Action>>
314 {
315 public:
316 [[nodiscard]]
317 explicit constexpr ApplyArgsAction(
318 Action action = {}
319 ) noexcept(std::is_nothrow_move_constructible_v<Action>)
320 : m_Action{std::move(action)}
321 {
322 }
323
324 template <std::size_t index, typename... Args>
325 using ArgListElementT = std::tuple_element_t<index, std::tuple<Args...>>;
326
327 template <std::size_t index, typename... Args>
328 using ProjectedArgListElementT = Projection<ArgListElementT<index, Args...>>;
329
330 template <typename Return, typename... Args>
331 requires (... && (indices < sizeof...(Args)))
332 && std::invocable<
333 const Action&,
334 ProjectedArgListElementT<indices, Args...>...>
335 constexpr decltype(auto) operator ()(
336 const call::Info<Return, Args...>& callInfo
337 ) const noexcept(
338 std::is_nothrow_invocable_v<
339 const Action&,
340 ProjectedArgListElementT<indices, Args...>...>)
341 {
342 static_assert(
344 ArgListElementT<indices, Args...>&,
345 ProjectedArgListElementT<indices, Args...>>
346 && ...),
347 "Projection can not be applied.");
348
349 return std::invoke(
350 m_Action,
351 static_cast<ProjectedArgListElementT<indices, Args...>>(
352 std::get<indices>(callInfo.args).get())...);
353 }
354
355 private:
356 [[no_unique_address]] Action m_Action;
357 };
358}
359
360namespace mimicpp::expect
361{
362 namespace detail
363 {
364 template <std::size_t index>
365 struct arg_requirement_describer
366 {
367 [[nodiscard]]
368 constexpr StringT operator ()(
369 const StringViewT matcherDescription
370 ) const
371 {
372 return format::format(
373 "expect: arg[{}] {}",
374 index,
375 matcherDescription);
376 }
377 };
378 }
379
403 template <std::size_t index, typename Matcher, typename Projection = std::identity>
404 [[nodiscard]]
405 constexpr auto arg(
406 Matcher&& matcher,
407 Projection projection = {}
408 ) noexcept(
409 std::is_nothrow_constructible_v<std::remove_cvref_t<Matcher>, Matcher>
410 && std::is_nothrow_move_constructible_v<Projection>)
411 {
412 using ProjectionT = expectation_policies::ApplyArgsAction<
413 Projection,
414 std::add_lvalue_reference_t,
415 index>;
416 using PolicyT = expectation_policies::Requirement<
417 std::remove_cvref_t<Matcher>,
418 ProjectionT,
419 detail::arg_requirement_describer<index>>;
420
421 return PolicyT{
422 std::forward<Matcher>(matcher),
423 ProjectionT{std::move(projection)}
424 };
425 }
426
430}
431
433{
434 // ReSharper disable CppDoxygenUnresolvedReference
435
465 template <typename Fun>
466 requires std::invocable<std::remove_cvref_t<Fun>&>
467 && (!std::is_void_v<std::invoke_result_t<std::remove_cvref_t<Fun>&>>)
468 [[nodiscard]]
469 constexpr auto returns_result_of(
470 Fun&& fun
471 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Fun>, Fun>)
472 {
474 [
475 fn = std::forward<Fun>(fun)
476 ]([[maybe_unused]] const auto& call) mutable noexcept(std::is_nothrow_invocable_v<decltype(fun)>) -> decltype(auto)
477 {
478 return std::invoke(fn);
479 }
480 };
481 }
482
500 template <typename T>
501 requires std::copyable<std::remove_cvref_t<T>>
502 [[nodiscard]]
503 constexpr auto returns(
504 T&& value // NOLINT(cppcoreguidelines-missing-std-forward)
505 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<T>, T>)
506 {
508 [v = std::forward<T>(value)]([[maybe_unused]] const auto& call) mutable noexcept -> auto& {
509 return static_cast<std::unwrap_reference_t<decltype(v)>&>(v);
510 }
511 };
512 }
513
526 template <std::size_t index, std::size_t... otherIndices, typename Action>
527 [[nodiscard]]
529 Action&& action
530 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
531 {
533 std::remove_cvref_t<Action>,
534 std::add_lvalue_reference_t,
535 index,
536 otherIndices...>;
537
539 ActionT{std::forward<Action>(action)}
540 };
541 }
542
553 template <typename Action>
554 [[nodiscard]]
556 Action&& action
557 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
558 {
560 std::remove_cvref_t<Action>,
561 std::add_lvalue_reference_t>;
562
564 ActionT{std::forward<Action>(action)}
565 };
566 }
567
575 template <std::size_t index>
576 [[nodiscard]]
577 constexpr auto returns_arg() noexcept
578 {
580 std::identity,
581 std::add_rvalue_reference_t,
582 index>;
583
585 ActionT{}
586 };
587 }
588
598 template <typename T>
599 requires std::copyable<std::remove_cvref_t<T>>
600 [[nodiscard]]
602 T&& exception
603 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<T>, T>)
604 {
606 std::forward<T>(exception)
607 };
608 }
609
614 // ReSharper restore CppDoxygenUnresolvedReference
615}
616
618{
647 template <std::size_t index, typename Action>
648 [[nodiscard]]
649 constexpr auto apply_arg(
650 Action&& action
651 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
652 {
654 std::remove_cvref_t<Action>,
655 std::add_lvalue_reference_t,
656 index>;
657
659 ActionT{std::forward<Action>(action)}
660 };
661 }
662
673 template <std::size_t index, std::size_t... additionalIndices, typename Action>
674 [[nodiscard]]
675 constexpr auto apply_args(
676 Action&& action
677 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
678 {
680 std::remove_cvref_t<Action>,
681 std::add_lvalue_reference_t,
682 index,
683 additionalIndices...>;
684
686 ActionT{std::forward<Action>(action)}
687 };
688 }
689
696 template <typename Action>
697 [[nodiscard]]
698 constexpr auto apply_all(
699 Action&& action
700 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
701 {
703 std::remove_cvref_t<Action>,
704 std::add_lvalue_reference_t>;
705
707 ActionT{std::forward<Action>(action)}
708 };
709 }
710
717 template <std::invocable Action>
718 [[nodiscard]]
719 constexpr auto invoke(
720 Action&& action
721 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Action>, Action>)
722 {
724 [
725 fn = std::forward<Action>(action)
726 ]([[maybe_unused]] const auto& call) mutable noexcept(std::is_nothrow_invocable_v<Action&>)
727 {
728 std::invoke(fn);
729 }
730 };
731 }
732
736}
737
738#endif
Definition Fwd.hpp:17
Definition ExpectationPolicies.hpp:268
constexpr decltype(auto) operator()(const call::Info< Return, Args... > &callInfo) const noexcept(std::is_nothrow_invocable_v< const Action &, ProjectedArgT< Args >... >)
Definition ExpectationPolicies.hpp:285
constexpr ApplyAllArgsAction(Action action={}) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:271
Projection< Arg > ProjectedArgT
Definition ExpectationPolicies.hpp:279
Definition ExpectationPolicies.hpp:314
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:335
std::tuple_element_t< index, std::tuple< Args... > > ArgListElementT
Definition ExpectationPolicies.hpp:325
constexpr ApplyArgsAction(Action action={}) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:317
Projection< ArgListElementT< index, Args... > > ProjectedArgListElementT
Definition ExpectationPolicies.hpp:328
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:158
static constexpr void consume(const call::Info< Return, Args... > &info) noexcept
Definition ExpectationPolicies.hpp:195
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:175
constexpr bool matches(const call::Info< Return, Args... > &info) const
Definition ExpectationPolicies.hpp:186
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:161
StringT describe() const
Definition ExpectationPolicies.hpp:200
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:110
constexpr ReturnsResultOf(Action &&action) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:97
Definition ExpectationPolicies.hpp:215
static constexpr bool matches(const call::Info< Return, Args... > &) noexcept
Definition ExpectationPolicies.hpp:241
static std::nullopt_t describe() noexcept
Definition ExpectationPolicies.hpp:247
constexpr void consume(const call::Info< Return, Args... > &info) noexcept(std::is_nothrow_invocable_v< Action &, const call::Info< Return, Args... > & >)
Definition ExpectationPolicies.hpp:254
SideEffectAction & operator=(const SideEffectAction &)=delete
static constexpr bool is_satisfied() noexcept
Definition ExpectationPolicies.hpp:234
SideEffectAction(SideEffectAction &&)=default
constexpr SideEffectAction(Action &&action) noexcept(std::is_nothrow_move_constructible_v< Action >)
Definition ExpectationPolicies.hpp:220
SideEffectAction(const SideEffectAction &)=delete
Definition ExpectationPolicies.hpp:130
constexpr Return finalize_call(const call::Info< Return, Args... > &call)
Definition ExpectationPolicies.hpp:139
constexpr Throws(Exception exception) noexcept(std::is_nothrow_move_constructible_v< Exception >)
Definition ExpectationPolicies.hpp:133
Definition Utility.hpp:53
Definition Matcher.hpp:116
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:555
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:528
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:503
constexpr auto returns_arg() noexcept
During the finalization step, the selected call argument is returned.
Definition ExpectationPolicies.hpp:577
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:469
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:405
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:698
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:649
constexpr auto invoke(Action &&action) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Action >, Action >)
Invokes the given function.
Definition ExpectationPolicies.hpp:719
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:675
Definition ControlPolicy.hpp:266
Definition ExpectationPolicies.hpp:20
Definition ExpectationPolicies.hpp:433
Definition ExpectationPolicies.hpp:618
constexpr bool is_matching(const Constness lhs, const Constness rhs) noexcept
Definition Utility.hpp:111
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:208
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:207