6#ifndef MIMICPP_EXPECTATION_HPP
7#define MIMICPP_EXPECTATION_HPP
25namespace mimicpp::detail
27 template <
typename Return,
typename... Params,
typename Signature>
28 std::optional<MatchReport> make_match_report(
29 const call::Info<Return, Params...>& call,
30 const Expectation<Signature>& expectation
35 return expectation.matches(call);
39 report_unhandled_exception(
42 std::current_exception());
48 template <
typename Signature>
49 constexpr auto pick_best_match(std::vector<std::tuple<Expectation<Signature>&, MatchReport>>& matches)
51 constexpr auto ratings = [](
const auto& el)
noexcept ->
const auto& {
52 return std::get<state_applicable>(
53 std::get<MatchReport>(el).controlReport)
57 auto best = std::ranges::begin(matches);
58 for (
auto iter = best + 1;
59 iter != std::ranges::end(matches);
62 if (!sequence::detail::has_better_rating(
104 template <
typename Signature>
105 requires std::same_as<Signature, signature_decay_t<Signature>>
193 virtual constexpr const std::source_location&
from() const noexcept = 0;
200 template <typename Signature>
258 void push(std::shared_ptr<ExpectationT> expectation)
260 const std::scoped_lock lock{m_ExpectationsMx};
263 std::ranges::find(m_Expectations, expectation) == std::ranges::end(m_Expectations)
264 &&
"Expectation already belongs to this storage.");
266 m_Expectations.emplace_back(std::move(expectation));
276 void remove(std::shared_ptr<ExpectationT> expectation)
278 const std::scoped_lock lock{m_ExpectationsMx};
280 auto iter = std::ranges::find(m_Expectations, expectation);
281 assert(iter != std::ranges::end(m_Expectations) &&
"Expectation does not belong to this storage.");
282 m_Expectations.erase(iter);
284 if (!expectation->is_satisfied())
286 detail::report_unfulfilled_expectation(
287 expectation->report());
303 std::vector<std::tuple<ExpectationT&, MatchReport>> matches{};
304 std::vector<MatchReport> noMatches{};
305 std::vector<MatchReport> inapplicableMatches{};
307 for (
const std::scoped_lock lock{m_ExpectationsMx};
308 auto& exp : m_Expectations | std::views::reverse)
310 if (std::optional matchReport = detail::make_match_report(call, *exp))
316 noMatches.emplace_back(*std::move(matchReport));
319 inapplicableMatches.emplace_back(*std::move(matchReport));
322 matches.emplace_back(*exp, *std::move(matchReport));
332 if (!std::ranges::empty(matches))
334 auto&& [exp,
report] = *detail::pick_best_match(matches);
335 detail::report_full_match(
339 return exp.finalize_call(call);
342 if (!std::ranges::empty(inapplicableMatches))
344 detail::report_inapplicable_matches(
346 std::move(inapplicableMatches));
349 detail::report_no_matches(
351 std::move(noMatches));
355 std::vector<std::shared_ptr<ExpectationT>> m_Expectations{};
356 std::mutex m_ExpectationsMx{};
362 template <
typename T,
typename Signature>
364 && std::is_destructible_v<T>
365 && std::same_as<T, std::remove_cvref_t<T>>
368 { std::as_const(policy).is_satisfied() }
noexcept -> std::convertible_to<bool>;
369 { std::as_const(policy).matches(info) } -> std::convertible_to<bool>;
370 { std::as_const(policy).describe() } -> std::convertible_to<std::optional<StringT>>;
371 { policy.consume(info) };
377 template <
typename T,
typename Signature>
379 && std::is_destructible_v<T>
380 && std::same_as<T, std::remove_cvref_t<T>>
383 { policy.finalize_call(info) } -> std::convertible_to<signature_return_type_t<Signature>>;
389 template <
typename T>
391 && std::is_destructible_v<T>
392 && std::same_as<T, std::remove_cvref_t<T>>
393 &&
requires(T& policy)
395 { std::as_const(policy).is_satisfied() }
noexcept -> std::convertible_to<bool>;
396 { std::as_const(policy).state() } -> std::convertible_to<control_state_t>;
433 template <
typename ControlPolicyArg,
typename FinalizerArg,
typename... PolicyArgs>
434 requires std::constructible_from<ControlPolicyT, ControlPolicyArg>
435 && std::constructible_from<FinalizerT, FinalizerArg>
436 && std::constructible_from<
PolicyListT, PolicyArgs...>
438 const std::source_location& sourceLocation,
439 ControlPolicyArg&& controlArg,
440 FinalizerArg&& finalizerArg,
443 std::is_nothrow_constructible_v<ControlPolicyT, ControlPolicyArg>
444 && std::is_nothrow_constructible_v<FinalizerT, FinalizerArg>
445 && (std::is_nothrow_constructible_v<Policies, PolicyArgs> && ...))
446 : m_SourceLocation{sourceLocation},
447 m_ControlPolicy{std::forward<ControlPolicyArg>(controlArg)},
448 m_Policies{std::forward<PolicyArgs>(args)...},
449 m_Finalizer{std::forward<FinalizerArg>(finalizerArg)}
460 .sourceLocation = m_SourceLocation,
461 .finalizerDescription = std::nullopt,
462 .timesDescription = std::invoke(
468 detail::control_state_printer{},
469 std::ostreambuf_iterator{ss}),
470 m_ControlPolicy.state());
471 return std::move(ss).str();
473 .expectationDescriptions = std::apply(
474 [&](
const auto&... policies)
476 return std::vector<std::optional<StringT>>{
477 policies.describe()...
490 return m_ControlPolicy.is_satisfied()
492 [](
const auto&... policies)
noexcept
494 return (... && policies.is_satisfied());
506 .sourceLocation = m_SourceLocation,
507 .finalizeReport = {std::nullopt},
508 .controlReport = m_ControlPolicy.state(),
509 .expectationReports = std::apply(
510 [&](
const auto&... policies)
512 return std::vector<MatchReport::Expectation>{
514 .isMatching = policies.matches(call),
515 .description = policies.describe()
528 m_ControlPolicy.consume();
530 [&](
auto&... policies)
noexcept
532 (..., policies.consume(call));
543 return m_Finalizer.finalize_call(call);
550 constexpr const std::source_location&
from() const noexcept
override
552 return m_SourceLocation;
556 std::source_location m_SourceLocation;
557 ControlPolicyT m_ControlPolicy;
558 PolicyListT m_Policies;
559 [[no_unique_address]] FinalizerT m_Finalizer{};
573 virtual ~Concept()
noexcept(
false)
577 Concept(
const Concept&) =
delete;
578 Concept& operator =(
const Concept&) =
delete;
579 Concept(Concept&&) =
delete;
580 Concept& operator =(Concept&&) =
delete;
583 virtual bool is_satisfied()
const = 0;
586 virtual const std::source_location& from()
const noexcept = 0;
592 template <
typename Signature>
600 ~Model()
noexcept(
false)
override
602 m_Storage->remove(m_Expectation);
607 std::shared_ptr<StorageT>&& storage,
608 std::shared_ptr<ExpectationT>&& expectation
610 : m_Storage{std::move(storage)},
611 m_Expectation{std::move(expectation)}
613 assert(m_Storage &&
"Storage is nullptr.");
614 assert(m_Expectation &&
"Expectation is nullptr.");
616 m_Storage->push(m_Expectation);
620 bool is_satisfied()
const override
626 const std::source_location& from()
const noexcept override
628 return m_Expectation->from();
632 std::shared_ptr<StorageT> m_Storage;
633 std::shared_ptr<ExpectationT> m_Expectation;
644 delete m_Inner.release();
653 template <
typename Signature>
660 std::make_unique<Model<Signature>>(
661 std::move(collection),
662 std::move(expectation))
673 template <
typename T>
674 requires requires(
const std::source_location& loc)
676 { std::declval<T&&>().finalize(loc) } -> std::convertible_to<ScopedExpectation>;
679 explicit(
false)
constexpr ScopedExpectation(T&&
object,
const std::source_location& loc = std::source_location::current())
687 ScopedExpectation(
const ScopedExpectation&) =
delete;
712 return m_Inner->is_satisfied();
720 const std::source_location&
from() const noexcept
722 return m_Inner->from();
726 std::unique_ptr<Concept> m_Inner;
The actual expectation template.
Definition Expectation.hpp:415
FinalizePolicy FinalizerT
Definition Expectation.hpp:418
constexpr void consume(const CallInfoT &call) override
Informs all policies, that the given call has been accepted.
Definition Expectation.hpp:526
constexpr BasicExpectation(const std::source_location &sourceLocation, ControlPolicyArg &&controlArg, FinalizerArg &&finalizerArg, PolicyArgs &&... args) noexcept(std::is_nothrow_constructible_v< ControlPolicyT, ControlPolicyArg > &&std::is_nothrow_constructible_v< FinalizerT, FinalizerArg > &&(std::is_nothrow_constructible_v< Policies, PolicyArgs > &&...))
Constructs the expectation with the given arguments.
Definition Expectation.hpp:437
constexpr bool is_satisfied() const noexcept override
Queries all policies, whether they are satisfied.
Definition Expectation.hpp:488
typename Expectation< Signature >::ReturnT ReturnT
Definition Expectation.hpp:421
constexpr ReturnT finalize_call(const CallInfoT &call) override
Requests the given call to be finalized.
Definition Expectation.hpp:541
ExpectationReport report() const override
Creates a report of the internal state.
Definition Expectation.hpp:457
call::info_for_signature_t< Signature > CallInfoT
Definition Expectation.hpp:420
MatchReport matches(const CallInfoT &call) const override
Queries all policies, whether they accept the given call.
Definition Expectation.hpp:503
std::tuple< Policies... > PolicyListT
Definition Expectation.hpp:419
constexpr const std::source_location & from() const noexcept override
Returns the source-location, where this expectation has been created.
Definition Expectation.hpp:550
Definition ControlPolicy.hpp:165
Collects all expectations for a specific (decayed) signature.
Definition Fwd.hpp:176
ExpectationCollection(const ExpectationCollection &)=delete
Deleted copy-constructor.
~ExpectationCollection()=default
Defaulted destructor.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:218
ReturnT handle_call(const CallInfoT &call)
Handles the incoming call.
Definition Expectation.hpp:301
ExpectationCollection(ExpectationCollection &&)=default
Defaulted move-constructor.
void push(std::shared_ptr< ExpectationT > expectation)
Inserts the given expectation into the internal storage.
Definition Expectation.hpp:258
ExpectationCollection()=default
Defaulted default constructor.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:208
void remove(std::shared_ptr< ExpectationT > expectation)
Removes the given expectation from the internal storage.
Definition Expectation.hpp:276
The base interface for expectations.
Definition Fwd.hpp:172
Expectation(Expectation &&)=delete
Deleted move-constructor.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:112
virtual bool is_satisfied() const noexcept=0
Queries all policies, whether they are satisfied.
virtual constexpr const std::source_location & from() const noexcept=0
Returns the source-location, where this expectation has been created.
virtual ExpectationReport report() const =0
Creates a report of the internal state.
virtual ~Expectation()=default
Defaulted virtual destructor.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:117
Expectation()=default
Defaulted default constructor.
Expectation(const Expectation &)=delete
Deleted copy-constructor.
virtual constexpr ReturnT finalize_call(const CallInfoT &call)=0
Requests the given call to be finalized.
Expectation & operator=(const Expectation &)=delete
Deleted copy-assignment-operator.
virtual void consume(const CallInfoT &call)=0
Informs all policies, that the given call has been accepted.
Contains the extracted info from a typed expectation.
Definition Reports.hpp:320
Information a used expectation policy.
Definition Reports.hpp:426
Contains the detailed information for match outcomes.
Definition Reports.hpp:407
Takes the ownership of an expectation and check whether it's satisfied during destruction.
Definition Expectation.hpp:568
bool is_satisfied() const
Queries the stored expectation, whether it's satisfied.
Definition Expectation.hpp:710
ScopedExpectation(ScopedExpectation &&)=default
Defaulted move-constructor.
const std::source_location & from() const noexcept
Queries the stored expectation for it's stored source-location.
Definition Expectation.hpp:720
ScopedExpectation(std::shared_ptr< ExpectationCollection< Signature > > collection, std::shared_ptr< typename ExpectationCollection< Signature >::ExpectationT > expectation) noexcept
Constructor, which generates the type-erase storage.
Definition Expectation.hpp:655
~ScopedExpectation() noexcept(false)
Removes the owned expectation from the ExpectationCollection and checks, whether it's satisfied.
Definition Expectation.hpp:641
Determines, whether the given type satisfies the requirements of a control-policy.
Definition Expectation.hpp:390
Determines, whether the given type satisfies the requirements of an expectation-policy for the given ...
Definition Expectation.hpp:363
Determines, whether the given type satisfies the requirements of a finalize-policy for the given sign...
Definition Expectation.hpp:378
MatchResult evaluate_match_report(const MatchReport &report) noexcept
Determines, whether a match report actually denotes a full, inapplicable or no match.
Definition Reports.hpp:458
CallReport make_call_report(const call::Info< Return, Params... > &callInfo)
Generates the call report for a given call info.
Definition Reports.hpp:244
typename signature_decay< Signature >::type signature_decay_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:68
typename signature_return_type< Signature >::type signature_return_type_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:84
typename info_for_signature< Signature >::type info_for_signature_t
Definition Call.hpp:70
Definition BoostTest.hpp:20
MatchResult
Definition Fwd.hpp:181
void unreachable()
Invokes undefined behavior.
Definition Utility.hpp:93
std::basic_ostringstream< CharT, CharTraitsT > StringStreamT
Definition Printer.hpp:41