6#ifndef MIMICPP_EXPECTATION_HPP
7#define MIMICPP_EXPECTATION_HPP
24#ifndef MIMICPP_DETAIL_IS_MODULE
37namespace mimicpp::detail
39 template <
typename Return,
typename... Params,
typename Signature>
41 std::optional<reporting::RequirementOutcomes> determine_requirement_outcomes(
42 reporting::TargetReport
const& target,
43 call::Info<Return, Params...>
const& call,
44 Expectation<Signature>
const& expectation)
noexcept
48 return expectation.matches(call);
52 reporting::detail::report_unhandled_exception(
58 std::current_exception());
65 std::vector<reporting::ExpectationReport> gather_expectation_reports(
auto&& expectationPtrs)
67 auto view = std::views::transform(expectationPtrs, [](
auto const& exp) {
return exp->report(); });
68 return std::vector<reporting::ExpectationReport>{
73 template <
typename Signature>
75 std::vector<reporting::NoMatchReport> make_no_match_reports(
76 std::vector<std::tuple<Expectation<Signature>*, reporting::RequirementOutcomes>>&& outcomes)
78 std::vector<reporting::NoMatchReport> reports{};
79 reports.reserve(outcomes.size());
80 for (
auto const& [expectationPtr, outcome] : outcomes)
83 expectationPtr->report(),
91 constexpr auto find_best_match(std::span<reporting::ExpectationReport const>
const matches)
93 constexpr auto ratings = [](
auto const& el)
noexcept ->
const auto& {
94 return std::get<reporting::state_applicable>(el.controlReport)
98 auto best = std::ranges::begin(matches);
99 for (
auto iter = best + 1;
100 iter != std::ranges::end(matches);
103 if (!sequence::detail::has_better_rating(
111 return std::ranges::distance(std::ranges::begin(matches), best);
145 template <
typename Signature>
146 requires std::same_as<Signature, signature_decay_t<Signature>>
241 virtual constexpr
util::SourceLocation const&
from() const noexcept = 0;
255 template <typename Signature>
313 void push(std::shared_ptr<ExpectationT> expectation)
315 const std::scoped_lock lock{m_ExpectationsMx};
317 MIMICPP_ASSERT(std::ranges::find(m_Expectations, expectation) == std::ranges::end(m_Expectations),
"Expectation already belongs to this storage.");
319 m_Expectations.emplace_back(std::move(expectation));
329 void remove(std::shared_ptr<ExpectationT> expectation)
331 const std::scoped_lock lock{m_ExpectationsMx};
333 auto iter = std::ranges::find(m_Expectations, expectation);
334 MIMICPP_ASSERT(iter != std::ranges::end(m_Expectations),
"Expectation does not belong to this storage.");
335 m_Expectations.erase(iter);
337 if (!expectation->is_satisfied())
339 reporting::detail::report_unfulfilled_expectation(
340 expectation->report());
357 std::vector<ExpectationT*>
matches{};
358 std::vector<ExpectationT*> inapplicableMatches{};
359 std::vector<std::tuple<ExpectationT*, reporting::RequirementOutcomes>> noMatches{};
361 std::scoped_lock
const lock{m_ExpectationsMx};
362 evaluate_expectations(target,
call,
matches, inapplicableMatches, noMatches);
364 std::size_t
const stacktraceSkip{1u +
call.baseStacktraceSkip};
365 if (!std::ranges::empty(
matches))
367 std::vector reports = detail::gather_expectation_reports(
matches);
369 auto const bestIndex = detail::find_best_match(reports);
370 MIMICPP_ASSERT(0 <= bestIndex && bestIndex < std::ssize(reports),
"Invalid index.");
372 auto& expectation = *
matches[bestIndex];
376 auto&
report = reports[bestIndex];
382 reporting::detail::report_full_match(
387 expectation.consume(
call);
388 return expectation.finalize_call(
call);
391 if (!std::ranges::empty(inapplicableMatches))
393 reporting::detail::report_inapplicable_matches(
395 detail::gather_expectation_reports(inapplicableMatches));
398 reporting::detail::report_no_matches(
400 detail::make_no_match_reports(std::move(noMatches)));
404 std::vector<std::shared_ptr<ExpectationT>> m_Expectations{};
405 std::mutex m_ExpectationsMx{};
407 void evaluate_expectations(
408 reporting::TargetReport
const& target,
410 std::vector<ExpectationT*>&
matches,
411 std::vector<ExpectationT*>& inapplicableMatches,
412 std::vector<std::tuple<ExpectationT*, reporting::RequirementOutcomes>>& noMatches)
414 for (
auto const& exp : std::views::reverse(m_Expectations))
416 if (std::optional outcomes = detail::determine_requirement_outcomes(target, call, *exp))
418 if (std::ranges::any_of(outcomes->outcomes, [](
auto const& el) { return el == false; }))
420 noMatches.emplace_back(exp.get(), *std::move(outcomes));
422 else if (!exp->is_applicable())
424 inapplicableMatches.emplace_back(exp.get());
428 matches.emplace_back(exp.get());
438 template <
typename T,
typename Signature>
440 && std::is_destructible_v<T>
441 && std::same_as<T, std::remove_cvref_t<T>>
446 { policy.consume(info) };
452 template <
typename T,
typename Signature>
454 && std::is_destructible_v<T>
455 && std::same_as<T, std::remove_cvref_t<T>>
457 { policy.finalize_call(info) } -> std::convertible_to<signature_return_type_t<Signature>>;
463 template <
typename T>
465 && std::is_destructible_v<T>
466 && std::same_as<T, std::remove_cvref_t<T>>
467 &&
requires(T& policy) {
469 { std::as_const(policy).state() } -> std::convertible_to<reporting::control_state_t>;
506 template <
typename ControlPolicyArg,
typename FinalizerArg,
typename... PolicyArgs>
507 requires std::constructible_from<ControlPolicyT, ControlPolicyArg>
508 && std::constructible_from<FinalizerT, FinalizerArg>
509 && std::constructible_from<
PolicyListT, PolicyArgs...>
513 ControlPolicyArg&& controlArg,
514 FinalizerArg&& finalizerArg,
515 PolicyArgs&&... args)
517 std::is_nothrow_constructible_v<ControlPolicyT, ControlPolicyArg>
518 && std::is_nothrow_constructible_v<FinalizerT, FinalizerArg>
519 && (std::is_nothrow_constructible_v<Policies, PolicyArgs> && ...))
520 : m_From{std::move(
from)},
521 m_Target{std::move(target)},
522 m_ControlPolicy{std::forward<ControlPolicyArg>(controlArg)},
523 m_Policies{std::forward<PolicyArgs>(args)...},
524 m_Finalizer{std::forward<FinalizerArg>(finalizerArg)}
537 .controlReport = m_ControlPolicy.state(),
538 .finalizerDescription = std::nullopt,
539 .requirementDescriptions = std::apply(
540 [&](
auto const&... policies) {
541 return std::vector<std::optional<StringT>>{
542 std::optional<StringT>{policies.describe()}...};
553 return m_ControlPolicy.is_satisfied()
555 [](
const auto&... policies)
noexcept {
556 return (... && policies.is_satisfied());
567 return std::holds_alternative<reporting::state_applicable>(
568 m_ControlPolicy.state());
578 .outcomes = gather_requirement_outcomes(
call)};
586 m_ControlPolicy.consume();
588 [&](
auto&... policies)
noexcept {
589 (..., policies.consume(
call));
600 return m_Finalizer.finalize_call(
call);
618 return m_Target.name;
624 ControlPolicyT m_ControlPolicy;
625 PolicyListT m_Policies;
626 [[no_unique_address]] FinalizerT m_Finalizer{};
629 std::vector<bool> gather_requirement_outcomes(CallInfoT
const& call)
const
632 [&](
auto const&... policies) {
633 return std::vector<bool>{policies.matches(call)...};
650 virtual ~Concept()
noexcept(
false)
654 Concept(
const Concept&) =
delete;
655 Concept&
operator=(
const Concept&) =
delete;
656 Concept(Concept&&) =
delete;
673 template <
typename Signature>
681 ~Model()
noexcept(
false)
override
683 m_Storage->remove(m_Expectation);
688 std::shared_ptr<StorageT>&& storage,
689 std::shared_ptr<ExpectationT>&& expectation) noexcept
690 : m_Storage{std::move(storage)},
691 m_Expectation{std::move(expectation)}
696 m_Storage->push(m_Expectation);
702 return m_Expectation->is_satisfied();
708 return m_Expectation->is_applicable();
714 return m_Expectation->from();
720 return m_Expectation->mock_name();
724 std::shared_ptr<StorageT> m_Storage;
725 std::shared_ptr<ExpectationT> m_Expectation;
736 delete m_Inner.release();
745 template <
typename Signature>
751 std::make_unique<Model<Signature>>(
752 std::move(collection),
753 std::move(expectation))}
763 template <
typename T>
764 requires requires(util::SourceLocation loc) {
765 { std::declval<T&&>().finalize(loc) } -> std::convertible_to<ScopedExpectation>;
776 ScopedExpectation(ScopedExpectation
const&) =
delete;
801 return m_Inner->is_satisfied();
811 return m_Inner->is_applicable();
821 return m_Inner->from();
831 return m_Inner->mock_name();
835 std::unique_ptr<Concept> m_Inner;
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
FinalizePolicy FinalizerT
Definition Expectation.hpp:490
constexpr BasicExpectation(util::SourceLocation from, reporting::TargetReport target, 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:510
constexpr void consume(const CallInfoT &call) override
Informs all policies, that the given call has been accepted.
Definition Expectation.hpp:584
ControlPolicy ControlPolicyT
Definition Expectation.hpp:489
constexpr bool is_satisfied() const noexcept override
Queries all policies, whether they are satisfied.
Definition Expectation.hpp:551
constexpr util::SourceLocation const & from() const noexcept override
Returns the source-location, where this expectation has been created.
Definition Expectation.hpp:607
typename Expectation< Signature >::ReturnT ReturnT
Definition Expectation.hpp:493
constexpr ReturnT finalize_call(const CallInfoT &call) override
Requests the given call to be finalized.
Definition Expectation.hpp:598
call::info_for_signature_t< Signature > CallInfoT
Definition Expectation.hpp:492
reporting::RequirementOutcomes matches(const CallInfoT &call) const override
Queries all policies, whether they accept the given call.
Definition Expectation.hpp:575
constexpr StringT const & mock_name() const noexcept override
Returns the name of the related mock.
Definition Expectation.hpp:616
constexpr bool is_applicable() const noexcept override
Queries the control policy, whether it's in the applicable state.
Definition Expectation.hpp:565
reporting::ExpectationReport report() const override
Creates a report of the internal state.
Definition Expectation.hpp:532
std::tuple< Policies... > PolicyListT
Definition Expectation.hpp:491
Definition ControlPolicies.hpp:161
Collects all expectations for a specific (decayed) signature.
Definition Expectation.hpp:258
ExpectationCollection(const ExpectationCollection &)=delete
Deleted copy-constructor.
~ExpectationCollection()=default
Defaulted destructor.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:273
ExpectationCollection & operator=(const ExpectationCollection &)=delete
Deleted copy-assignment-operator.
ExpectationCollection(ExpectationCollection &&)=default
Defaulted move-constructor.
void push(std::shared_ptr< ExpectationT > expectation)
Inserts the given expectation into the internal storage.
Definition Expectation.hpp:313
ReturnT handle_call(reporting::TargetReport target, CallInfoT call)
Handles the incoming call.
Definition Expectation.hpp:355
ExpectationCollection()=default
Defaulted default constructor.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:263
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:329
Expectation< Signature > ExpectationT
The interface type of the stored expectations.
Definition Expectation.hpp:268
The base interface for expectations.
Definition Expectation.hpp:148
virtual constexpr StringT const & mock_name() const noexcept=0
Returns the name of the related mock.
virtual constexpr util::SourceLocation const & from() const noexcept=0
Returns the source-location, where this expectation has been created.
Expectation(Expectation &&)=delete
Deleted move-constructor.
virtual reporting::ExpectationReport report() const =0
Creates a report of the internal state.
virtual reporting::RequirementOutcomes matches(const CallInfoT &call) const =0
Queries all policies, whether they accept the given call.
call::info_for_signature_t< Signature > CallInfoT
The expected call type.
Definition Expectation.hpp:153
virtual bool is_applicable() const noexcept=0
Queries the control policy, whether it's in the applicable state.
virtual bool is_satisfied() const noexcept=0
Queries all policies, whether they are satisfied.
virtual ~Expectation()=default
Defaulted virtual destructor.
signature_return_type_t< Signature > ReturnT
The return type.
Definition Expectation.hpp:158
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.
Takes the ownership of an expectation and check whether it's satisfied during destruction.
Definition Expectation.hpp:645
bool is_satisfied() const
Queries the stored expectation, whether it's satisfied.
Definition Expectation.hpp:799
StringT const & mock_name() const noexcept
Queries the stored expectation for the name of the related mock.
Definition Expectation.hpp:829
ScopedExpectation(ScopedExpectation &&)=default
Defaulted move-constructor.
util::SourceLocation const & from() const noexcept
Queries the stored expectation for it's stored source-location.
Definition Expectation.hpp:819
ScopedExpectation & operator=(ScopedExpectation const &)=delete
Deleted copy-assignment-operator.
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:747
ScopedExpectation & operator=(ScopedExpectation &&)=default
Defaulted move-assignment-operator.
bool is_applicable() const
Queries the stored expectation, whether it's applicable.
Definition Expectation.hpp:809
util::SourceLocation loc
Definition Expectation.hpp:768
~ScopedExpectation() noexcept(false)
Removes the owned expectation from the ExpectationCollection and checks, whether it's satisfied.
Definition Expectation.hpp:733
Contains the extracted info from a typed expectation.
Definition ExpectationReport.hpp:85
Contains the boolean outcomes of a match-test.
Definition ExpectationReport.hpp:102
Contains the extracted mock info.
Definition TargetReport.hpp:22
A thin wrapper around general source-location info.
Definition SourceLocation.hpp:38
Determines, whether the given type satisfies the requirements of a control-policy.
Definition Expectation.hpp:464
Determines, whether the given type satisfies the requirements of an expectation-policy for the given ...
Definition Expectation.hpp:439
Determines, whether the given type satisfies the requirements of a finalize-policy for the given sign...
Definition Expectation.hpp:453
Determines, whether B behaves as a the builtin type bool.
Definition Concepts.hpp:66
Determines, whether From can be explicitly converted to To.
Definition Concepts.hpp:34
CallReport make_call_report(TargetReport target, call::Info< Return, Params... > callInfo, util::Stacktrace stacktrace)
Generates the call report for a given call info.
Definition CallReport.hpp:79
std::atomic_bool & report_success() noexcept
Controls whether successful matches are reported.
Definition Settings.hpp:32
typename signature_decay< Signature >::type signature_decay_t
Convenience alias, exposing the type member alias of the actual type-trait.
Definition Fwd.hpp:214
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:230
constexpr detail::current_fn current
Function object, which generates the current-stacktrace.
Definition Stacktrace.hpp:473
typename info_for_signature< Signature >::type info_for_signature_t
Definition Call.hpp:47
Definition FloatingPointMatchers.hpp:25
Definition BasicReporter.hpp:27
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:391