6#ifndef MIMICPP_REPORTING_STRINGIFY_REPORTS_HPP
7#define MIMICPP_REPORTING_STRINGIFY_REPORTS_HPP
22#ifndef MIMICPP_DETAIL_IS_MODULE
31namespace mimicpp::reporting::detail
33 template <pr
int_iterator OutIter>
34 OutIter stringify_stacktrace(OutIter out, util::Stacktrace
const& stacktrace)
36 if (!stacktrace.empty())
38 out = format::format_to(std::move(out),
"\nStacktrace:\n");
45 template <pr
int_iterator OutIter>
46 OutIter stringify_call_report_arguments(OutIter out, CallReport
const& call,
StringViewT const linePrefix)
48 if (call.argDetails.empty())
53 out = std::ranges::copy(linePrefix, std::move(out)).out;
54 out = format::format_to(std::move(out),
"Where:\n");
57 auto const& [
type, state] : call.argDetails)
59 out = std::ranges::copy(linePrefix, std::move(out)).out;
60 out = format::format_to(std::move(out),
"\targ[{}] => ", i++);
61 out = std::ranges::copy(
type.name(), std::move(out)).out;
62 out = format::format_to(std::move(out),
": ");
63 out = std::ranges::copy(state, std::move(out)).out;
64 out = format::format_to(std::move(out),
"\n");
70 template <pr
int_iterator OutIter>
71 OutIter stringify_call_report_from(OutIter out, CallReport
const& call)
73 out = format::format_to(std::move(out),
"Call originated from ");
75 if (!call.stacktrace.empty())
77 out = util::stacktrace::detail::print_entry(std::move(out), call.stacktrace, 0u);
83 out = format::format_to(std::move(out),
"\n");
88 template <pr
int_iterator OutIter>
89 OutIter stringify_call_report_target(OutIter out, CallReport
const& call)
91 out = format::format_to(
93 "\tOn Target `{}` used Overload `{}`\n",
95 call.target.overloadReport.name());
100 template <pr
int_iterator OutIter>
101 OutIter stringify_expectation_report_from(OutIter out, ExpectationReport
const& expectation)
103 out = format::format_to(std::move(out),
"Expectation defined at ");
105 out = format::format_to(std::move(out),
"\n");
110 template <pr
int_iterator OutIter>
111 OutIter stringify_expectation_report_target(OutIter out, ExpectationReport
const& expectation)
113 out = format::format_to(
115 "\tOf Target `{}` related to Overload `{}`\n",
116 expectation.target.name,
117 expectation.target.overloadReport.name());
122 template <pr
int_iterator OutIter>
123 OutIter stringify_expectation_report_requirement_adherences(
125 std::span<std::optional<StringT>
const>
const descriptions,
128 if (descriptions.empty())
133 out = std::ranges::copy(linePrefix, std::move(out)).out;
134 out = format::format_to(std::move(out),
"With Adherence(s):\n");
136 for (
auto const& description : descriptions)
140 out = std::ranges::copy(linePrefix, std::move(out)).out;
141 out = format::format_to(std::move(out),
" + ");
142 out = std::ranges::copy(*description, std::move(out)).out;
143 out = format::format_to(std::move(out),
"\n");
150 struct inapplicable_reason_printer
152 template <pr
int_iterator OutIter>
153 OutIter operator()([[maybe_unused]] OutIter out, [[maybe_unused]] state_applicable
const& state)
const
158 template <pr
int_iterator OutIter>
159 constexpr OutIter operator()(OutIter out, state_inapplicable
const& state)
const
161 auto const totalSequences = std::ranges::ssize(state.sequences)
162 + std::ranges::ssize(state.inapplicableSequences);
163 out = format::format_to(
165 "it's not Head of {} Sequence(s) ({} total).\n",
166 std::ranges::ssize(state.inapplicableSequences),
169 MIMICPP_ASSERT(!state.inapplicableSequences.empty(),
"Inapplicable sequences can not be empty.");
170 for (
auto const& sequence : state.inapplicableSequences)
173 out = format::format_to(std::move(out),
"\t\tExpectation defined at ");
175 out = format::format_to(std::move(out),
" is Head of Sequence from ");
177 out = format::format_to(std::move(out),
"\n");
183 template <pr
int_iterator OutIter>
184 constexpr OutIter operator()(OutIter out, state_saturated
const& state)
const
186 out = format::format_to(
188 "it's already saturated (matched {} out of {} times).\n",
196 template <pr
int_iterator OutIter>
197 OutIter stringify_expectation_report_requirement_violations(
199 std::span<std::optional<StringT>
const>
const descriptions,
202 MIMICPP_ASSERT(!descriptions.empty(),
"Zero requirements can never be violated.");
204 out = std::ranges::copy(linePrefix, std::move(out)).out;
205 out = format::format_to(std::move(out),
"Due to Violation(s):\n");
207 int withoutDescription{0};
208 for (
auto const& description : descriptions)
212 out = std::ranges::copy(linePrefix, std::move(out)).out;
213 out = format::format_to(std::move(out),
" - ");
214 out = std::ranges::copy(*description, std::move(out)).out;
215 out = format::format_to(std::move(out),
"\n");
219 ++withoutDescription;
223 if (0 < withoutDescription)
225 out = std::ranges::copy(linePrefix, std::move(out)).out;
226 out = format::format_to(std::move(out),
" - ");
227 out = format::format_to(
229 "{} Requirement(s) failed without further description.\n",
236 struct unfulfilled_reason_printer
238 template <pr
int_iterator OutIter>
239 OutIter operator()(OutIter out, state_applicable
const& state)
const
241 return stringify_times_state(
248 template <pr
int_iterator OutIter>
249 OutIter operator()(OutIter out, state_inapplicable
const& state)
const
251 return stringify_times_state(
258 template <pr
int_iterator OutIter>
259 OutIter operator()([[maybe_unused]] OutIter out, [[maybe_unused]] state_saturated
const& state)
const
265 template <pr
int_iterator OutIter>
266 static OutIter stringify_times_state(OutIter out,
int const current,
int const min,
int const max)
268 const auto verbalizeValue = [](OutIter o,
int const value) {
273 case 1:
return format::format_to(std::move(o),
"once");
274 case 2:
return format::format_to(std::move(o),
"twice");
275 default:
return format::format_to(std::move(o),
"{} times", value);
279 MIMICPP_ASSERT(current < min,
"State doesn't denote an unsatisfied state.");
281 out = format::format_to(std::move(out),
"matching ");
285 out = format::format_to(std::move(out),
"exactly ");
286 out = verbalizeValue(std::move(out), min);
287 out = format::format_to(std::move(out),
" ");
289 else if (max == std::numeric_limits<int>::max())
291 out = format::format_to(std::move(out),
"at least ");
292 out = verbalizeValue(std::move(out), min);
293 out = format::format_to(std::move(out),
" ");
297 out = format::format_to(
299 "between {} and {} times ",
304 return format::format_to(
306 "was expected => requires {} further match(es).\n",
321 detail::stringify_call_report_from(std::ostreambuf_iterator{ss},
call);
322 detail::stringify_call_report_target(std::ostreambuf_iterator{ss},
call);
323 detail::stringify_call_report_arguments(std::ostreambuf_iterator{ss},
call,
"\t");
325 ss <<
"\t" <<
"Chose ";
326 detail::stringify_expectation_report_from(std::ostreambuf_iterator{ss}, expectation);
331 detail::stringify_expectation_report_requirement_adherences(
332 std::ostreambuf_iterator{ss},
338 ss <<
"\t" <<
"Without any Requirements.\n";
341 detail::stringify_stacktrace(
342 std::ostreambuf_iterator{ss},
345 return std::move(ss).str();
356 detail::stringify_call_report_from(std::ostreambuf_iterator{ss},
call);
357 detail::stringify_call_report_target(std::ostreambuf_iterator{ss},
call);
358 detail::stringify_call_report_arguments(std::ostreambuf_iterator{ss},
call,
"\t");
360 ss << expectations.size() <<
" inapplicable but otherwise matching Expectation(s):";
363 auto& expReport : expectations)
365 ss <<
"\n\t#" << ++i <<
" ";
366 detail::stringify_expectation_report_from(std::ostreambuf_iterator{ss}, expReport);
370 std::bind_front(detail::inapplicable_reason_printer{}, std::ostreambuf_iterator{ss}),
371 expReport.controlReport);
373 std::ranges::sort(expReport.requirementDescriptions);
374 detail::stringify_expectation_report_requirement_adherences(
375 std::ostreambuf_iterator{ss},
376 expReport.requirementDescriptions,
380 detail::stringify_stacktrace(
381 std::ostreambuf_iterator{ss},
384 return std::move(ss).str();
393 detail::stringify_call_report_from(std::ostreambuf_iterator{ss},
call);
394 detail::stringify_call_report_target(std::ostreambuf_iterator{ss},
call);
395 detail::stringify_call_report_arguments(std::ostreambuf_iterator{ss},
call,
"\t");
397 std::vector<NoMatchReport*> applicableReports{};
398 for (
auto& noMatch : noMatchReports)
400 if (std::holds_alternative<state_applicable>(noMatch.expectationReport.controlReport))
402 applicableReports.emplace_back(&noMatch);
406 if (applicableReports.empty())
408 ss <<
"No applicable Expectations available!\n";
412 ss << applicableReports.size() <<
" applicable non-matching Expectation(s):";
415 auto* report : applicableReports)
417 auto& [expReport, outcomes] = *report;
419 ss <<
"\n\t#" << ++i <<
" ";
420 detail::stringify_expectation_report_from(std::ostreambuf_iterator{ss}, expReport);
423 expReport.requirementDescriptions,
425 std::bind_front(std::equal_to{},
true));
426 MIMICPP_ASSERT(!violations.empty(),
"Zero violations do not denote a no-match.");
427 std::ranges::sort(violations);
428 detail::stringify_expectation_report_requirement_violations(
429 std::ostreambuf_iterator{ss},
433 std::span
const adherences{expReport.requirementDescriptions.data(), violations.data()};
434 std::ranges::sort(adherences);
435 detail::stringify_expectation_report_requirement_adherences(
436 std::ostreambuf_iterator{ss},
442 detail::stringify_stacktrace(
443 std::ostreambuf_iterator{ss},
446 return std::move(ss).str();
454 ss <<
"Unfulfilled ";
455 detail::stringify_expectation_report_from(std::ostreambuf_iterator{ss}, expectationReport);
456 detail::stringify_expectation_report_target(std::ostreambuf_iterator{ss}, expectationReport);
459 std::bind_front(detail::unfulfilled_reason_printer{}, std::ostreambuf_iterator{ss}),
462 return std::move(ss).str();
469 std::exception_ptr
const& exception)
472 ss <<
"Unhandled Exception ";
476 std::rethrow_exception(exception);
478 catch (
const std::exception& e)
480 ss <<
"with message `" << e.what() <<
"`\n";
484 ss <<
"of unknown type.\n";
487 ss <<
"\t" <<
"While checking ";
488 detail::stringify_expectation_report_from(std::ostreambuf_iterator{ss}, expectationReport);
491 detail::stringify_call_report_from(std::ostreambuf_iterator{ss},
call);
492 detail::stringify_call_report_target(std::ostreambuf_iterator{ss},
call);
493 detail::stringify_call_report_arguments(std::ostreambuf_iterator{ss},
call,
"\t");
495 detail::stringify_stacktrace(
496 std::ostreambuf_iterator{ss},
499 return std::move(ss).str();
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
Contains the extracted info from a typed call::Info.
Definition CallReport.hpp:43
Contains the extracted info from a typed expectation.
Definition ExpectationReport.hpp:85
std::vector< std::optional< StringT > > requirementDescriptions
Definition ExpectationReport.hpp:91
control_state_t controlReport
Definition ExpectationReport.hpp:89
constexpr TypeMatcher< T > type
Matcher, which can be used as a last resort to disambiguate similar overloads.
Definition GeneralMatchers.hpp:297
constexpr printing::PrintFn print
Functional object, converting the given object to its textual representation.
Definition Print.hpp:183
Definition BasicReporter.hpp:27
StringT stringify_unhandled_exception(CallReport const &call, ExpectationReport const &expectationReport, std::exception_ptr const &exception)
Definition StringifyReports.hpp:466
StringT stringify_unfulfilled_expectation(ExpectationReport const &expectationReport)
Definition StringifyReports.hpp:450
StringT stringify_inapplicable_matches(CallReport const &call, std::span< ExpectationReport > expectations)
Definition StringifyReports.hpp:349
StringT stringify_no_matches(CallReport const &call, std::span< NoMatchReport > noMatchReports)
Definition StringifyReports.hpp:388
StringT stringify_full_match(CallReport const &call, ExpectationReport expectation)
Definition StringifyReports.hpp:315
constexpr std::ranges::borrowed_subrange_t< Target > partition_by(Target &&targetRange, Control &&controlRange, Predicate predicate, Projection projection={})
Partitions the target range by the predicate results on the control range.
Definition Algorithm.hpp:62
void unreachable()
Invokes undefined behavior.
Definition C++23Backports.hpp:40
std::basic_ostringstream< CharT, CharTraitsT > StringStreamT
Definition Format.hpp:35
std::basic_string_view< CharT, CharTraitsT > StringViewT
Definition Fwd.hpp:392
std::basic_string< CharT, CharTraitsT > StringT
Definition Fwd.hpp:391