6#ifndef MIMICPP_EXPECTATION_HPP
7#define MIMICPP_EXPECTATION_HPP
27namespace mimicpp::detail
29 template <
typename Return,
typename... Params,
typename Signature>
30 std::optional<MatchReport> make_match_report(
31 const call::Info<Return, Params...>& call,
32 const Expectation<Signature>& expectation)
noexcept
36 return expectation.matches(call);
40 report_unhandled_exception(
43 std::current_exception());
49 template <
typename Signature>
50 constexpr auto pick_best_match(std::vector<std::tuple<Expectation<Signature>&, MatchReport>>& matches)
52 constexpr auto ratings = [](
const auto& el)
noexcept ->
const auto& {
53 return std::get<state_applicable>(
54 std::get<MatchReport>(el).controlReport)
58 auto best = std::ranges::begin(matches);
59 for (
auto iter = best + 1;
60 iter != std::ranges::end(matches);
63 if (!sequence::detail::has_better_rating(
105 template <
typename Signature>
106 requires std::same_as<Signature, signature_decay_t<Signature>>
194 virtual constexpr const std::source_location&
from() const noexcept = 0;
201 template <typename Signature>
259 void push(std::shared_ptr<ExpectationT> expectation)
261 const std::scoped_lock lock{m_ExpectationsMx};
264 std::ranges::find(m_Expectations, expectation) == std::ranges::end(m_Expectations)
265 &&
"Expectation already belongs to this storage.");
267 m_Expectations.emplace_back(std::move(expectation));
277 void remove(std::shared_ptr<ExpectationT> expectation)
279 const std::scoped_lock lock{m_ExpectationsMx};
281 auto iter = std::ranges::find(m_Expectations, expectation);
282 assert(iter != std::ranges::end(m_Expectations) &&
"Expectation does not belong to this storage.");
283 m_Expectations.erase(iter);
285 if (!expectation->is_satisfied())
287 detail::report_unfulfilled_expectation(
288 expectation->report());
304 std::vector<std::tuple<ExpectationT&, MatchReport>>
matches{};
305 std::vector<MatchReport> noMatches{};
306 std::vector<MatchReport> inapplicableMatches{};
308 for (
const std::scoped_lock lock{m_ExpectationsMx};
309 auto& exp : m_Expectations | std::views::reverse)
311 if (std::optional matchReport = detail::make_match_report(
call, *exp))
317 noMatches.emplace_back(*std::move(matchReport));
320 inapplicableMatches.emplace_back(*std::move(matchReport));
323 matches.emplace_back(*exp, *std::move(matchReport));
333 if (!std::ranges::empty(
matches))
341 detail::report_full_match(
345 return exp.finalize_call(
call);
348 if (!std::ranges::empty(inapplicableMatches))
350 detail::report_inapplicable_matches(
352 std::move(inapplicableMatches));
355 detail::report_no_matches(
357 std::move(noMatches));
361 std::vector<std::shared_ptr<ExpectationT>> m_Expectations{};
362 std::mutex m_ExpectationsMx{};
368 template <
typename T,
typename Signature>
370 && std::is_destructible_v<T>
371 && std::same_as<T, std::remove_cvref_t<T>>
373 { std::as_const(policy).is_satisfied() }
noexcept -> std::convertible_to<bool>;
374 { std::as_const(policy).matches(info) } -> std::convertible_to<bool>;
375 { std::as_const(policy).describe() } -> std::convertible_to<std::optional<StringT>>;
376 { policy.consume(info) };
382 template <
typename T,
typename Signature>
384 && std::is_destructible_v<T>
385 && std::same_as<T, std::remove_cvref_t<T>>
387 { policy.finalize_call(info) } -> std::convertible_to<signature_return_type_t<Signature>>;
393 template <
typename T>
395 && std::is_destructible_v<T>
396 && std::same_as<T, std::remove_cvref_t<T>>
397 &&
requires(T& policy) {
398 { std::as_const(policy).is_satisfied() }
noexcept -> std::convertible_to<bool>;
399 { std::as_const(policy).state() } -> std::convertible_to<control_state_t>;
435 template <
typename ControlPolicyArg,
typename FinalizerArg,
typename... PolicyArgs>
436 requires std::constructible_from<ControlPolicyT, ControlPolicyArg>
437 && std::constructible_from<FinalizerT, FinalizerArg>
438 && std::constructible_from<
PolicyListT, PolicyArgs...>
440 const std::source_location& sourceLocation,
441 ControlPolicyArg&& controlArg,
442 FinalizerArg&& finalizerArg,
443 PolicyArgs&&... args)
noexcept(std::is_nothrow_constructible_v<ControlPolicyT, ControlPolicyArg> && std::is_nothrow_constructible_v<FinalizerT, FinalizerArg> && (std::is_nothrow_constructible_v<Policies, PolicyArgs> && ...))
444 : m_SourceLocation{sourceLocation},
445 m_ControlPolicy{std::forward<ControlPolicyArg>(controlArg)},
446 m_Policies{std::forward<PolicyArgs>(args)...},
447 m_Finalizer{std::forward<FinalizerArg>(finalizerArg)}
458 .sourceLocation = m_SourceLocation,
459 .finalizerDescription = std::nullopt,
460 .timesDescription = describe_times(),
461 .expectationDescriptions = std::apply(
462 [&](
const auto&... policies) {
463 return std::vector<std::optional<StringT>>{
464 policies.describe()...};
475 return m_ControlPolicy.is_satisfied()
477 [](
const auto&... policies)
noexcept {
478 return (... && policies.is_satisfied());
490 .sourceLocation = m_SourceLocation,
491 .finalizeReport = {std::nullopt},
492 .controlReport = m_ControlPolicy.state(),
493 .expectationReports = std::apply(
494 [&](
const auto&... policies) {
495 return std::vector<MatchReport::Expectation>{
497 .isMatching = policies.matches(
call),
498 .description = policies.describe()}
510 m_ControlPolicy.consume();
512 [&](
auto&... policies)
noexcept {
513 (..., policies.consume(
call));
524 return m_Finalizer.finalize_call(
call);
531 constexpr const std::source_location&
from() const noexcept
override
533 return m_SourceLocation;
537 std::source_location m_SourceLocation;
538 ControlPolicyT m_ControlPolicy;
539 PolicyListT m_Policies;
540 [[no_unique_address]] FinalizerT m_Finalizer{};
543 StringT describe_times()
const
548 detail::control_state_printer{},
549 std::ostreambuf_iterator{ss}),
550 m_ControlPolicy.state());
551 return std::move(ss).str();
566 virtual ~Concept()
noexcept(
false)
570 Concept(
const Concept&) =
delete;
571 Concept&
operator=(
const Concept&) =
delete;
572 Concept(Concept&&) =
delete;
579 virtual const std::source_location&
from()
const noexcept = 0;
585 template <
typename Signature>
593 ~Model()
noexcept(
false)
override
595 m_Storage->remove(m_Expectation);
600 std::shared_ptr<StorageT>&& storage,
601 std::shared_ptr<ExpectationT>&& expectation) noexcept
602 : m_Storage{std::move(storage)},
603 m_Expectation{std::move(expectation)}
605 assert(m_Storage &&
"Storage is nullptr.");
606 assert(m_Expectation &&
"Expectation is nullptr.");
608 m_Storage->push(m_Expectation);
614 return m_Expectation->is_satisfied();
618 const std::source_location&
from()
const noexcept override
620 return m_Expectation->from();
624 std::shared_ptr<StorageT> m_Storage;
625 std::shared_ptr<ExpectationT> m_Expectation;
636 delete m_Inner.release();
645 template <
typename Signature>
651 std::make_unique<Model<Signature>>(
652 std::move(collection),
653 std::move(expectation))}
663 template <
typename T>
664 requires requires(
const std::source_location& loc) {
665 { std::declval<T&&>().finalize(loc) } -> std::convertible_to<ScopedExpectation>;
668 explicit(
false)
constexpr ScopedExpectation(T&&
object,
const std::source_location&
loc = std::source_location::current())
676 ScopedExpectation(
const ScopedExpectation&) =
delete;
701 return m_Inner->is_satisfied();
709 const std::source_location&
from() const noexcept
711 return m_Inner->from();
715 std::unique_ptr<Concept> m_Inner;
FinalizePolicy FinalizerT
Definition Expectation.hpp:420
constexpr void consume(const CallInfoT &call) override
Informs all policies, that the given call has been accepted.
Definition Expectation.hpp:508
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:439
ControlPolicy ControlPolicyT
Definition Expectation.hpp:419
constexpr bool is_satisfied() const noexcept override
Queries all policies, whether they are satisfied.
Definition Expectation.hpp:473
typename Expectation< Signature >::ReturnT ReturnT
Definition Expectation.hpp:423
constexpr ReturnT finalize_call(const CallInfoT &call) override
Requests the given call to be finalized.
Definition Expectation.hpp:522
ExpectationReport report() const override
Creates a report of the internal state.
Definition Expectation.hpp:455
call::info_for_signature_t< Signature > CallInfoT
Definition Expectation.hpp:422
MatchReport matches(const CallInfoT &call) const override
Queries all policies, whether they accept the given call.
Definition Expectation.hpp:487
std::tuple< Policies... > PolicyListT
Definition Expectation.hpp:421
constexpr const std::source_location & from() const noexcept override
Returns the source-location, where this expectation has been created.
Definition Expectation.hpp:531
Definition ControlPolicies.hpp:156
Collects all expectations for a specific (decayed) signature.
Definition Fwd.hpp:327
ExpectationCollection(const ExpectationCollection &)=delete
Deleted copy-constructor.
~ExpectationCollection()=default
Defaulted destructor.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:219
ExpectationCollection & operator=(const ExpectationCollection &)=delete
Deleted copy-assignment-operator.
ReturnT handle_call(CallInfoT call)
Handles the incoming call.
Definition Expectation.hpp:302
ExpectationCollection(ExpectationCollection &&)=default
Defaulted move-constructor.
void push(std::shared_ptr< ExpectationT > expectation)
Inserts the given expectation into the internal storage.
Definition Expectation.hpp:259
ExpectationCollection()=default
Defaulted default constructor.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:209
ExpectationCollection & operator=(ExpectationCollection &&)=default
Defaulted move-assignment-operator.
void remove(std::shared_ptr< ExpectationT > expectation)
Removes the given expectation from the internal storage.
Definition Expectation.hpp:277
Expectation< Signature > ExpectationT
The interface type of the stored expectations.
Definition Expectation.hpp:214
The base interface for expectations.
Definition Fwd.hpp:323
Expectation(Expectation &&)=delete
Deleted move-constructor.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:113
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.
virtual MatchReport matches(const CallInfoT &call) const =0
Queries all policies, whether they accept the given call.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:118
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.
Expectation & operator=(Expectation &&)=delete
Deleted move-assignment-operator.
Contains the extracted info from a typed expectation.
Definition Reports.hpp:331
Information a used expectation policy.
Definition Reports.hpp:436
Contains the detailed information for match outcomes.
Definition Reports.hpp:417
bool is_satisfied() const
Queries the stored expectation, whether it's satisfied.
Definition Expectation.hpp:699
const std::source_location & loc
Definition Expectation.hpp:668
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:709
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:647
ScopedExpectation & operator=(const ScopedExpectation &)=delete
Deleted copy-assignment-operator.
ScopedExpectation & operator=(ScopedExpectation &&)=default
Defaulted move-assignment-operator.
~ScopedExpectation() noexcept(false)
Removes the owned expectation from the ExpectationCollection and checks, whether it's satisfied.
Definition Expectation.hpp:633
Determines, whether the given type satisfies the requirements of a control-policy.
Definition Expectation.hpp:394
Determines, whether the given type satisfies the requirements of an expectation-policy for the given ...
Definition Expectation.hpp:369
Determines, whether the given type satisfies the requirements of a finalize-policy for the given sign...
Definition Expectation.hpp:383
MatchResult evaluate_match_report(const MatchReport &report) noexcept
Determines, whether a match report actually denotes a full, inapplicable or no match.
Definition Reports.hpp:468
CallReport make_call_report(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:157
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:173
typename info_for_signature< Signature >::type info_for_signature_t
Definition Call.hpp:43
Definition FloatingPointMatchers.hpp:22
Definition BoostTest.hpp:20
MatchResult
Definition Fwd.hpp:332
@ inapplicable
Definition Fwd.hpp:334
@ none
Definition Fwd.hpp:333
@ full
Definition Fwd.hpp:335
void unreachable()
Invokes undefined behavior.
Definition Utility.hpp:91