Sequoia
Loading...
Searching...
No Matches
FreeCheckers.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2020. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
69
70#include <format>
71
72namespace sequoia::testing
73{
74
78 template<class T> struct value_tester;
79
80 //=========================== Types used to generate overload sets ===========================//
81
84
85 template<class ValueBasedCustomizer>
87 {
88 using customizer_type = ValueBasedCustomizer;
89
90 template<class Customizer>
92
93 customizer_type customizer;
94 };
95
96 template<class ValueBasedCustomizer>
97 requires std::is_void_v<ValueBasedCustomizer>
98 struct general_equivalence_check_t<ValueBasedCustomizer>
99 {
101 };
102
104
105 template<class ValueBasedCustomizer>
107 {
108 using customizer_type = ValueBasedCustomizer;
109
110 template<class Customizer>
112
113 customizer_type customizer;
114 };
115
116 template<class ValueBasedCustomizer>
117 requires std::is_void_v<ValueBasedCustomizer>
118 struct general_weak_equivalence_check_t<ValueBasedCustomizer>
119 {
121 };
122
124
125 enum class minimal_reporting_permitted : bool { no, yes };
126
127 template<minimal_reporting_permitted MinimalReporting>
129
130 template<class ValueBasedCustomizer>
131 [[nodiscard]]
133 {
134 return "equivalence";
135 }
136
137 template<class ValueBasedCustomizer>
138 [[nodiscard]]
139 std::string to_string(general_weak_equivalence_check_t<ValueBasedCustomizer>)
140 {
141 return "weak equivalence";
142 }
143
144 //=========================== Values defined for convenience ===========================//
145
146 inline constexpr equality_check_t equality{};
147 inline constexpr simple_equality_check_t simple_equality{};
148 inline constexpr equivalence_check_t equivalence{};
149 inline constexpr weak_equivalence_check_t weak_equivalence{};
150 inline constexpr with_best_available_check_t<minimal_reporting_permitted::no> with_best_available{};
151
152 template<class T>
153 inline constexpr bool is_elementary_check{
154 std::is_same_v<T, equality_check_t>
155 || std::is_same_v<T, simple_equality_check_t>
156 || std::is_same_v<T, equivalence_check_t>
157 || std::is_same_v<T, weak_equivalence_check_t>
158 };
159
160 template<class T>
161 inline constexpr bool is_best_available_check{
162 std::is_same_v<T, with_best_available_check_t<minimal_reporting_permitted::yes>>
163 || std::is_same_v<T, with_best_available_check_t<minimal_reporting_permitted::no>>
164 };
165
166 template<class T>
167 inline constexpr bool is_customized_check{
168 requires {
169 typename T::customizer_type;
170 typename T::template rebind_check_type<typename T::customizer_type>;
171 requires std::is_same_v<typename T::template rebind_check_type<typename T::customizer_type>, T>;
172 }
173 };
174
175 template<class T>
176 inline constexpr bool is_general_equivalence_check{is_customized_check<T> || std::is_same_v<T, equivalence_check_t> || std::is_same_v<T, weak_equivalence_check_t>};
177
178 template<class Compare, class T>
179 inline constexpr bool potential_comparator_for{
180 std::is_invocable_r_v<bool, Compare, T, T>
181 || (faithful_range<T> && !(is_elementary_check<Compare> || is_best_available_check<Compare> || is_customized_check<Compare>))
182 };
183
184 template<class CheckType, test_mode Mode, class T, class U, class... Args>
185 concept tests_against = requires(CheckType c, test_logger<Mode>& logger, T&& obtained, const U& predicted, Args&&... args) {
186 value_tester<std::remove_cvref_t<T>>::test(c, logger, std::forward<T>(obtained), predicted, std::forward<Args>(args)...);
187 };
188
189 template<class CheckType, test_mode Mode, class T, class U, class Tutor>
191
192 template<class CheckType, test_mode Mode, class T, class U, class Tutor>
193 concept checkable_against = requires(CheckType c, test_logger<Mode>& logger, T&& obtained, const U& predicted, Tutor tutor) {
194 check(c, "", logger, std::forward<T>(obtained), predicted, tutor);
195 };
196
197 template<class CheckType, test_mode Mode, class T, class U, class Tutor>
198 inline constexpr bool checkable_against_fallback{
199 requires {
200 typename CheckType::fallback;
202 }
203 };
204
205 template<test_mode Mode, class T, class U, class Tutor>
206 inline constexpr bool has_elementary_check_against{
207 checkable_against<equality_check_t, Mode, T, U, Tutor>
208 || checkable_against<simple_equality_check_t, Mode, T, U, Tutor>
209 || checkable_against<equivalence_check_t, Mode, T, U, Tutor>
210 || checkable_against<weak_equivalence_check_t, Mode, T, U, Tutor>
211 };
212
216 template<class>
218
219 template<class E>
220 requires std::derived_from<E, std::exception>
222 {
223 [[nodiscard]]
224 static std::string get(const E& e) { return e.what(); }
225 };
226
227 template<class E>
228 requires (!std::derived_from<E, std::exception>) && serializable<E>
230 {
231 [[nodiscard]]
232 static std::string get(const E& e) { return to_string(e); }
233 };
234
235 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
236 requires tests_against_with_or_without_tutor<CheckType, Mode, T, U, tutor<Advisor>>
237 void select_test(CheckType flavour, test_logger<Mode>& logger, const T& obtained, const U& prediction, [[maybe_unused]] tutor<Advisor> advisor)
238 {
239 if constexpr(tests_against<CheckType, Mode, T, U, tutor<Advisor>>)
240 {
241 value_tester<T>::test(flavour, logger, obtained, prediction, advisor);
242 }
243 else if constexpr(tests_against<CheckType, Mode, T, U>)
244 {
245 value_tester<T>::test(flavour, logger, obtained, prediction);
246 }
247 else
248 {
249 static_assert(dependent_false<CheckType>::value, "Should never be triggered; indicates mismatch between requirement and logic");
250 }
251 }
252
258 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
259 requires is_general_equivalence_check<CheckType> && tests_against_with_or_without_tutor<CheckType, Mode, T, U, tutor<Advisor>>
260 bool general_equivalence_check(CheckType flavour,
261 std::string description,
262 test_logger<Mode>& logger,
263 const T& obtained,
264 const U& predicted,
265 tutor<Advisor> advisor)
266 {
267 const auto msg{
268 [] (CheckType flavour, std::string desc) -> std::string {
269 return append_lines(desc,
270 "Comparison performed using:",
271 make_type_info<value_tester<T>>(),
272 std::format("Checking for {} with:", to_string(flavour)), make_type_info<U>()).append("\n");
273 }
274 };
275
276 sentinel<Mode> sentry{logger, msg(flavour, std::move(description))};
277
278 select_test(flavour, logger, obtained, predicted, advisor);
279
280 return !sentry.failure_detected();
281 }
282
283 template<bool IsFinalMessage, test_mode Mode, class Compare, class T, class Advisor>
284 requires std::is_invocable_r_v<bool, Compare, T, T> && (!IsFinalMessage || reportable<T>)
285 void binary_comparison(final_message_constant<IsFinalMessage>, sentinel<Mode>& sentry, Compare compare, const T& obtained, const T& prediction, tutor<Advisor> advisor)
286 {
287 sentry.log_check();
288 if(!compare(obtained, prediction))
289 {
290 std::string message{failure_reporter<Compare>::reporter(final_message_constant<IsFinalMessage>{}, compare, obtained, prediction)};
291 append_advice(message, {advisor, obtained, prediction});
292
293 sentry.log_failure(message);
294 }
295 }
296
298 {
299 [[nodiscard]]
300 std::string operator()(const project_paths& projPaths, std::string message) const
301 {
302 constexpr auto npos{std::string::npos};
303 if(const auto pos{message.find(projPaths.project_root().generic_string())}; pos < npos)
304 {
305 const auto len{projPaths.project_root().generic_string().size()};
306 message.erase(pos, len + 1);
307 }
308
309 return message;
310 }
311 };
312
313 //================= namespace-level check functions =================//
314
315 template
316 <
317 class E,
318 test_mode Mode,
319 class Fn,
321 >
322 bool check_exception_thrown(std::string description, test_logger<Mode>& logger, Fn&& function, const project_paths& projPaths, Postprocessor postprocessor={})
323 {
324 auto message{
325 [&description]() -> std::string&& {
326 return std::move(append_lines(description, "Expected Exception Type:", make_type_info<E>()));
327 }()
328 };
329
330 sentinel<Mode> sentry{logger, message};
331 sentry.log_check();
332 try
333 {
334 std::forward<Fn>(function)();
335 sentry.log_failure("No exception thrown");
336 return false;
337 }
338 catch(const E& e)
339 {
340 sentry.log_caught_exception_message(postprocessor(projPaths, exception_message_extractor<E>::get(e)));
341 return true;
342 }
343 catch(const std::exception& e)
344 {
345 std::string msg{append_lines("Unexpected exception thrown (caught by std::exception&):", "\"").append(e.what()).append("\"\n")};
346
347 sentry.log_failure(msg);
348 return false;
349 }
350 catch(...)
351 {
352 sentry.log_failure("Unknown exception thrown\n");
353 return false;
354 }
355 }
356
359 template<class CheckType, test_mode Mode, std::input_or_output_iterator Iter, std::input_or_output_iterator PredictionIter, class Advisor>
361
366 template
367 <
368 class CheckType,
369 test_mode Mode,
370 std::input_or_output_iterator Iter,
371 std::sentinel_for<Iter> Sentinel,
372 std::input_or_output_iterator PredictionIter,
373 std::sentinel_for<PredictionIter> PredictionSentinel,
374 class Advisor = null_advisor
375 >
376 requires supports_iterator_range_check<CheckType, Mode, Iter, PredictionIter, Advisor>
377 bool check(CheckType flavour,
378 std::string description,
379 test_logger<Mode>& logger,
380 Iter first,
381 Sentinel last,
382 PredictionIter predictionFirst,
383 PredictionSentinel predictionLast,
384 tutor<Advisor> advisor = {})
385 {
386 auto info{
387 [&description]() -> std::string&& {
388 return description.empty() || description.back() == '\n' ? std::move(description) : std::move(description.append("\n"));
389 }
390 };
391
392 sentinel<Mode> sentry{logger, info()};
393 bool equal{true};
394
395 const auto actualSize{fixed_width_unsigned_cast(std::ranges::distance(first, last))};
396 const auto predictedSize{fixed_width_unsigned_cast(std::ranges::distance(predictionFirst, predictionLast))};
397 if(check(equality, "Container size wrong", logger, actualSize, predictedSize))
398 {
399 auto predictionIter{predictionFirst};
400 auto iter{first};
401 for(; predictionIter != predictionLast; std::ranges::advance(predictionIter, 1), std::ranges::advance(iter, 1))
402 {
403 const auto dist{std::ranges::distance(predictionFirst, predictionIter)};
404 auto mess{std::format("Element {} of range incorrect", dist)};
405 if(!check(flavour, std::move(mess), logger, *iter, *predictionIter, advisor)) equal = false;
406 }
407 }
408 else
409 {
410 equal = false;
411 }
412
413 return equal;
414 }
415
421 template<class Compare, test_mode Mode, class T, class Advisor=null_advisor>
422 requires potential_comparator_for<Compare, T>
423 bool check(Compare compare,
424 std::string description,
425 test_logger<Mode>& logger,
426 const T& obtained,
427 const T& prediction,
428 tutor<Advisor> advisor={})
429 {
430 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
431
432 if constexpr(std::is_invocable_r_v<bool, Compare, T, T>)
433 {
434 using finality = final_message_constant<!faithful_range<T>>;
435 binary_comparison(finality{}, sentry, std::move(compare), obtained, prediction, advisor);
436 }
437 else
438 {
439 check(std::move(compare), "", logger, obtained.begin(), obtained.end(), prediction.begin(), prediction.end(), advisor);
440 }
441
442 return !sentry.failure_detected();
443 }
444
451 namespace impl
452 {
453 template<class CheckType, test_mode Mode, faithful_range T, faithful_range U, class Advisor>
454 inline constexpr bool supports_range_check_v{
455 requires(T& t, U& u) {
456 requires supports_iterator_range_check<CheckType, Mode, decltype(std::ranges::begin(t)), decltype(std::ranges::begin(u)), Advisor>;
457 }
458 };
459 }
460
461 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
462 struct supports_range_check : std::false_type {};
463
464 template<class CheckType, test_mode Mode, faithful_range T, faithful_range U, class Advisor>
465 requires impl::supports_range_check_v<CheckType, Mode, T, U, Advisor>
466 struct supports_range_check<CheckType, Mode, T, U, Advisor> : std::true_type {};
467
468 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
469 inline constexpr bool supports_range_check_v{supports_range_check<CheckType, Mode, T, U, Advisor>::value};
470
473 template<test_mode Mode, class T, class Advisor>
474 inline constexpr bool supports_equality_check{
477 || supports_range_check_v<equality_check_t, Mode, T, T, Advisor>
478 };
479
498 template<test_mode Mode, class T, class Advisor=null_advisor>
499 requires supports_equality_check<Mode, T, Advisor>
501 std::string description,
502 test_logger<Mode>& logger,
503 const T& obtained,
504 const T& prediction,
505 tutor<Advisor> advisor={})
506 {
507 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
508
509 if constexpr(deep_equality_comparable<T>)
510 {
511 using finality = final_message_constant<!(tests_against_with_or_without_tutor<equality_check_t, Mode, T, T, tutor<Advisor>> || faithful_range<T>)>;
512 binary_comparison(finality{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
513 }
514
515 if constexpr(tests_against_with_or_without_tutor<equality_check_t, Mode, T, T, tutor<Advisor>>)
516 {
517 select_test(equality_check_t{}, logger, obtained, prediction, advisor);
518 }
519 else if constexpr(supports_range_check_v<equality_check_t, Mode, T, T, Advisor>)
520 {
521 check(equality, "", logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
522 }
523
524 return !sentry.failure_detected();
525 }
526
529 template<test_mode Mode, class T, class Advisor>
530 inline constexpr bool supports_simple_equality_check{
532 || supports_range_check_v<simple_equality_check_t, Mode, T, T, Advisor>
533 };
534
537 template<test_mode Mode, class T, class Advisor=null_advisor>
538 requires supports_simple_equality_check<Mode, T, Advisor>
540 std::string description,
541 test_logger<Mode>& logger,
542 const T& obtained,
543 const T& prediction,
544 tutor<Advisor> advisor={})
545 {
546 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
547
548 using finality = final_message_constant<!faithful_range<T>>;
549 binary_comparison(finality{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
550
551 if constexpr(supports_range_check_v<simple_equality_check_t, Mode, T, T, Advisor>)
552 {
553 check(simple_equality, "", logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
554 }
555
556 return !sentry.failure_detected();
557 }
558
573 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
575 is_general_equivalence_check<CheckType>
577 || supports_range_check_v<CheckType, Mode, T, U, Advisor>
578 || checkable_against_fallback<CheckType, Mode, T, U, tutor<Advisor>>)
579 };
580
581 template<class CheckType, test_mode Mode, class T, class U, class Advisor=null_advisor>
582 requires supports_generalized_equivalence_check<CheckType, Mode, T, U, Advisor>
583 bool check(CheckType flavour, std::string description, test_logger<Mode>& logger, const T& obtained, const U& prediction, tutor<Advisor> advisor={})
584 {
585 if constexpr(tests_against_with_or_without_tutor<CheckType, Mode, T, U, tutor<Advisor>>)
586 {
587 return general_equivalence_check(flavour,
588 std::move(description),
589 logger,
590 obtained,
591 prediction,
592 advisor);
593 }
594 else if constexpr(supports_range_check_v<CheckType, Mode, T, U, Advisor>)
595 {
596 return check(flavour,
597 add_type_info<T>(std::move(description)),
598 logger,
599 std::begin(obtained),
600 std::end(obtained),
601 std::begin(prediction),
602 std::end(prediction),
603 advisor);
604 }
605 else if constexpr(checkable_against_fallback<CheckType, Mode, T, U, tutor<Advisor>>)
606 {
607 using fallback = typename CheckType::fallback;
608 return check(fallback{},
609 std::move(description),
610 logger,
611 obtained,
612 prediction,
613 advisor);
614 }
615 else
616 {
617 static_assert(dependent_false<CheckType>::value, "Should never be triggered; indicates mismatch between requirement and logic");
618 }
619 }
620
623 template<minimal_reporting_permitted MinimalReporting, test_mode Mode, class T, class U, class Advisor>
624 inline constexpr bool supports_best_available_check{
626 || has_elementary_check_against<Mode, T, U, tutor<Advisor>>
627 || supports_range_check_v<with_best_available_check_t<MinimalReporting>, Mode, T, U, Advisor>
628 || (std::is_same_v<T, U> && deep_equality_comparable<T> && reportable<T>)
629 || ((MinimalReporting == minimal_reporting_permitted::yes) && std::equality_comparable_with<T, U>)
630 };
631
634 template<minimal_reporting_permitted MinimalReporting, test_mode Mode, class T, class U, class Advisor=null_advisor>
635 requires supports_best_available_check<MinimalReporting, Mode, T, U, Advisor>
637 std::string description,
638 test_logger<Mode>& logger,
639 const T& obtained,
640 const U& prediction,
641 tutor<Advisor> advisor={})
642 {
643 if constexpr(tests_against_with_or_without_tutor<with_best_available_check_t<MinimalReporting>, Mode, T, U, tutor<Advisor>>)
644 {
645 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
646
647 if constexpr(std::is_same_v<T, U> && deep_equality_comparable<T>)
648 {
649 binary_comparison(is_not_final_message_t{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
650 }
651
652 select_test(with_best_available, logger, obtained, prediction, advisor);
653
654 return !sentry.failure_detected();
655 }
656 else if constexpr(std::is_same_v<T, U> && tests_against_with_or_without_tutor<equality_check_t, Mode, T, U, tutor<Advisor>>)
657 {
658 return check(equality, description, logger, obtained, prediction, advisor);
659 }
660 else if constexpr(tests_against_with_or_without_tutor<equivalence_check_t, Mode, T, U, tutor<Advisor>>)
661 {
662 return check(equivalence, description, logger, obtained, prediction, advisor);
663 }
664 else if constexpr(tests_against_with_or_without_tutor<weak_equivalence_check_t, Mode, T, U, tutor<Advisor>>)
665 {
666 return check(weak_equivalence, description, logger, obtained, prediction, advisor);
667 }
668 else if constexpr(supports_range_check_v<with_best_available_check_t<MinimalReporting>, Mode, T, U, Advisor>)
669 {
670 return check(with_best_available, description, logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
671 }
672 else if constexpr(std::is_same_v<T, U> && deep_equality_comparable<T> && reportable<T>)
673 {
674 return check(simple_equality, description, logger, obtained, prediction, advisor);
675 }
676 else if constexpr((MinimalReporting == minimal_reporting_permitted::yes) && std::equality_comparable_with<T, U>)
677 {
678 return check(description, logger, obtained == prediction,advisor);
679 }
680 else
681 {
682 static_assert(false);
683 }
684 }
685
686 template<test_mode Mode, class Advisor=null_advisor>
687 bool check(std::string description, test_logger<Mode>& logger, const bool obtained, tutor<Advisor> advisor={})
688 {
689 return check(equality, std::move(description), logger, obtained, true, std::move(advisor));
690 }
691
706 template<test_mode Mode, class Extender>
707 class checker : public Extender
708 {
709 friend Extender;
710 public:
711 constexpr static test_mode mode{Mode};
713
714 checker() = default;
715
716 checker(const checker&) = delete;
717 checker& operator=(const checker&) = delete;
718
719 template<class T, class Advisor = null_advisor, class Self>
720 requires supports_equality_check<Mode, T, Advisor>
721 bool check(this Self& self, equality_check_t, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
722 {
723 return testing::check(equality, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
724 }
725
726 template<class T, class Advisor = null_advisor, class Self>
727 requires supports_simple_equality_check<Mode, T, Advisor>
728 bool check(this Self& self, simple_equality_check_t, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
729 {
730 return testing::check(simple_equality, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
731 }
732
733 template<class T, class U, minimal_reporting_permitted MinimalReporting, class Advisor = null_advisor, class Self>
734 requires supports_best_available_check<MinimalReporting, Mode, T, U, Advisor>
735 bool check(this Self& self, with_best_available_check_t<MinimalReporting>, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
736 {
737 return testing::check(with_best_available_check_t<MinimalReporting>{},
738 self.report(description),
739 self.m_Logger,
740 obtained,
741 prediction,
742 std::move(advisor));
743 }
744
745 template<class ValueBasedCustomizer, class T, class U, class Advisor = null_advisor, class Self>
746 requires supports_generalized_equivalence_check<general_equivalence_check_t<ValueBasedCustomizer>, Mode, T, U, Advisor>
747 bool check(this Self& self, general_equivalence_check_t<ValueBasedCustomizer> checker, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
748 {
749 return testing::check(checker, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
750 }
751
752 template<class ValueBasedCustomizer, class T, class U, class Advisor = null_advisor, class Self>
753 requires supports_generalized_equivalence_check<general_weak_equivalence_check_t<ValueBasedCustomizer>, Mode, T, U, Advisor>
754 bool check(this Self& self, general_weak_equivalence_check_t<ValueBasedCustomizer> checker, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
755 {
756 return testing::check(checker, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
757 }
758
759 template<class Compare, class T, class Advisor = null_advisor, class Self>
760 requires potential_comparator_for<Compare, T>
761 bool check(this Self& self, Compare compare, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
762 {
763 return testing::check(std::move(compare), self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
764 }
765
766 template<class Advisor=null_advisor, class Self>
767 bool check(this Self& self, const reporter& description, const bool obtained, tutor<Advisor> advisor={})
768 {
769 return testing::check(self.report(description), self.m_Logger, obtained, std::move(advisor));
770 }
771
772 template
773 <
774 class Compare,
775 std::input_or_output_iterator Iter,
776 std::sentinel_for<Iter> Sentinel,
777 std::input_or_output_iterator PredictionIter,
778 std::sentinel_for<PredictionIter> PredictionSentinel,
779 class Advisor = null_advisor,
780 class Self
781 >
782 requires supports_iterator_range_check<Compare, Mode, Iter, PredictionIter, Advisor>
783 bool check(this Self& self,
784 Compare compare,
785 const reporter& description,
786 Iter first,
787 Sentinel last,
788 PredictionIter predictionFirst,
789 PredictionSentinel predictionLast,
790 tutor<Advisor> advisor={})
791 {
792 return testing::check(std::move(compare), self.report(description), self.m_Logger, first, last, predictionFirst, predictionLast, std::move(advisor));
793 }
794
795 template
796 <
797 class E,
798 class Fn,
800 class Self
801 >
802 bool check_exception_thrown(this Self& self, const reporter& description, Fn&& function, Postprocessor postprocessor={})
803 {
804 return testing::check_exception_thrown<E>(self.report(description), self.m_Logger, std::forward<Fn>(function), self.get_project_paths(), std::move(postprocessor));
805 }
806
807#define STATIC_CHECK(...) (check("", [](){ static_assert(__VA_ARGS__); return true; }()))
808
809 template<class Stream>
811 friend Stream& operator<<(Stream& os, const checker& c)
812 {
813 os << c.m_Logger;
814 return os;
815 }
816
817 [[nodiscard]]
818 log_summary summary(std::string_view prefix, const log_summary::duration delta) const
819 {
820 return log_summary{prefix, m_Logger, delta};
821 }
822
823 void reset_results() noexcept { m_Logger.reset_results(); }
824
825 [[nodiscard]]
826 bool has_critical_failures() const noexcept
827 {
828 return m_Logger.results().critical_failures > 0;
829 }
830 protected:
831 explicit checker(active_recovery_files recovery)
832 : m_Logger{std::move(recovery)}
833 {}
834
835 checker(checker&&) noexcept = default;
836 checker& operator=(checker&&) noexcept = default;
837
838 ~checker() = default;
839
840 [[nodiscard]]
841 std::size_t checks() const noexcept { return m_Logger.checks(); }
842
843 [[nodiscard]]
844 std::size_t failures() const noexcept { return m_Logger.failures(); }
845
846 [[nodiscard]]
847 const uncaught_exception_info& exceptions_detected_by_sentinel() const noexcept
848 {
849 return m_Logger.exceptions_detected_by_sentinel();
850 }
851
852 [[nodiscard]]
853 sentinel<Mode> make_sentinel(std::string message)
854 {
855 return {m_Logger, std::move(message)};
856 }
857
858 [[nodiscard]]
859 std::string_view top_level_message() const
860 {
861 return m_Logger.top_level_message();
862 }
863
864 [[nodiscard]]
865 const failure_output& failure_messages() const noexcept
866 {
867 return m_Logger.results().failure_messages;
868 }
869 private:
870 test_logger<Mode> m_Logger;
871 };
872}
Utilities for the advice framework, which provides hints for certain failures.
Utilities for performing checks with respect to a binary operator.
Core declarations / definitions used in the testing framework.
constexpr bool supports_simple_equality_check
Condition for applying an equality check.
Definition: FreeCheckers.hpp:530
constexpr bool supports_generalized_equivalence_check
The workhorse for (weak) equivalence checking.
Definition: FreeCheckers.hpp:574
constexpr bool supports_best_available_check
Condition for applying the best available check.
Definition: FreeCheckers.hpp:624
bool check(CheckType flavour, std::string description, test_logger< Mode > &logger, Iter first, Sentinel last, PredictionIter predictionFirst, PredictionSentinel predictionLast, tutor< Advisor > advisor={})
The workhorse for comparing the contents of ranges.
Definition: FreeCheckers.hpp:377
constexpr bool supports_equality_check
Condition for applying an equality check.
Definition: FreeCheckers.hpp:474
constexpr bool supports_iterator_range_check
Condition for applying a check across a range of values.
Definition: FreeCheckers.hpp:360
bool general_equivalence_check(CheckType flavour, std::string description, test_logger< Mode > &logger, const T &obtained, const U &predicted, tutor< Advisor > advisor)
generic function that generates a check from any class providing a static check method.
Definition: FreeCheckers.hpp:260
Utilities for recording the outcome of tests.
Meta-programming utilities.
Exposes elementary check methods, with the option to plug in arbitrary Extenders to compose functiona...
Definition: FreeCheckers.hpp:708
Summaries data generated by the logger, for the purposes of reporting.
Definition: TestLogger.hpp:299
Paths used by the project.
Definition: ProjectPaths.hpp:469
Definition: Output.hpp:186
Definition: TestLogger.hpp:277
Definition: TestLogger.hpp:183
class template used to wrap function objects which proffer advice.
Definition: Advice.hpp:127
Concept to work around the fact that currently the stl typically underconstrains operator==.
Definition: Concepts.hpp:105
Supplements std::invocable.
Definition: Concepts.hpp:24
A concept which is realized by a T const& which may be serialized to a Stream&.
Definition: Concepts.hpp:61
Definition: FreeCheckers.hpp:193
Definition: Output.hpp:140
Definition: CoreInfrastructure.hpp:54
Definition: FreeCheckers.hpp:185
Holds paths to files where recovery information will be written if the path is not empty.
Definition: TestLogger.hpp:36
Definition: FreeCheckers.hpp:82
class template, specializations of which extract messages from various exception types.
Definition: FreeCheckers.hpp:217
Definition: FreeCheckers.hpp:87
Represents the absence of advice.
Definition: Advice.hpp:93
Definition: FreeCheckers.hpp:83
Definition: FreeCheckers.hpp:462
Definition: CoreInfrastructure.hpp:99
class template, specializations of which implement various comparisons for the specified type.
Definition: FreeCheckers.hpp:78
Definition: FreeCheckers.hpp:128