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 [flavour] (std::string desc) -> std::string {
269 return append_lines(
270 desc,
271 "Comparison performed using:",
272 make_type_info<value_tester<T>>(),
273 std::format("Checking for {} with:", to_string(flavour)), make_type_info<U>()
274 ).append("\n");
275 }
276 };
277
278 sentinel<Mode> sentry{logger, msg(std::move(description))};
279
280 select_test(flavour, logger, obtained, predicted, advisor);
281
282 return !sentry.failure_detected();
283 }
284
285 template<bool IsFinalMessage, test_mode Mode, class Compare, class T, class Advisor>
286 requires std::is_invocable_r_v<bool, Compare, T, T> && (!IsFinalMessage || reportable<T>)
287 void binary_comparison(final_message_constant<IsFinalMessage>, sentinel<Mode>& sentry, Compare compare, const T& obtained, const T& prediction, tutor<Advisor> advisor)
288 {
289 sentry.log_check();
290 if(!compare(obtained, prediction))
291 {
292 std::string message{failure_reporter<Compare>::reporter(final_message_constant<IsFinalMessage>{}, compare, obtained, prediction)};
293 append_advice(message, {advisor, obtained, prediction});
294
295 sentry.log_failure(message);
296 }
297 }
298
300 {
301 [[nodiscard]]
302 std::string operator()(const project_paths& projPaths, std::string message) const
303 {
304 constexpr auto npos{std::string::npos};
305 if(const auto pos{message.find(projPaths.project_root().generic_string())}; pos < npos)
306 {
307 const auto len{projPaths.project_root().generic_string().size()};
308 message.erase(pos, len + 1);
309 }
310
311 return message;
312 }
313 };
314
315 //================= namespace-level check functions =================//
316
317 template
318 <
319 class E,
320 test_mode Mode,
321 class Fn,
323 >
324 bool check_exception_thrown(std::string description, test_logger<Mode>& logger, Fn&& function, const project_paths& projPaths, Postprocessor postprocessor={})
325 {
326 auto message{
327 [&description]() -> std::string&& {
328 return std::move(append_lines(description, "Expected Exception Type:", make_type_info<E>()));
329 }()
330 };
331
332 sentinel<Mode> sentry{logger, message};
333 sentry.log_check();
334 try
335 {
336 std::forward<Fn>(function)();
337 sentry.log_failure("No exception thrown");
338 return false;
339 }
340 catch(const E& e)
341 {
342 sentry.log_caught_exception_message(postprocessor(projPaths, exception_message_extractor<E>::get(e)));
343 return true;
344 }
345 catch(const std::exception& e)
346 {
347 std::string msg{append_lines("Unexpected exception thrown (caught by std::exception&):", "\"").append(e.what()).append("\"\n")};
348
349 sentry.log_failure(msg);
350 return false;
351 }
352 catch(...)
353 {
354 sentry.log_failure("Unknown exception thrown\n");
355 return false;
356 }
357 }
358
361 template<class CheckType, test_mode Mode, std::input_or_output_iterator Iter, std::input_or_output_iterator PredictionIter, class Advisor>
363
368 template
369 <
370 class CheckType,
371 test_mode Mode,
372 std::input_or_output_iterator Iter,
373 std::sentinel_for<Iter> Sentinel,
374 std::input_or_output_iterator PredictionIter,
375 std::sentinel_for<PredictionIter> PredictionSentinel,
376 class Advisor = null_advisor
377 >
378 requires supports_iterator_range_check<CheckType, Mode, Iter, PredictionIter, Advisor>
379 bool check(CheckType flavour,
380 std::string description,
381 test_logger<Mode>& logger,
382 Iter first,
383 Sentinel last,
384 PredictionIter predictionFirst,
385 PredictionSentinel predictionLast,
386 tutor<Advisor> advisor = {})
387 {
388 auto info{
389 [&description]() -> std::string&& {
390 return description.empty() || description.back() == '\n' ? std::move(description) : std::move(description.append("\n"));
391 }
392 };
393
394 sentinel<Mode> sentry{logger, info()};
395 bool equal{true};
396
397 const auto actualSize{fixed_width_unsigned_cast(std::ranges::distance(first, last))};
398 const auto predictedSize{fixed_width_unsigned_cast(std::ranges::distance(predictionFirst, predictionLast))};
399 if(check(equality, "Container size wrong", logger, actualSize, predictedSize))
400 {
401 auto predictionIter{predictionFirst};
402 auto iter{first};
403 for(; predictionIter != predictionLast; std::ranges::advance(predictionIter, 1), std::ranges::advance(iter, 1))
404 {
405 const auto dist{std::ranges::distance(predictionFirst, predictionIter)};
406 auto mess{std::format("Element {} of range incorrect", dist)};
407 if(!check(flavour, std::move(mess), logger, *iter, *predictionIter, advisor)) equal = false;
408 }
409 }
410 else
411 {
412 equal = false;
413 }
414
415 return equal;
416 }
417
423 template<class Compare, test_mode Mode, class T, class Advisor=null_advisor>
424 requires potential_comparator_for<Compare, T>
425 bool check(Compare compare,
426 std::string description,
427 test_logger<Mode>& logger,
428 const T& obtained,
429 const T& prediction,
430 tutor<Advisor> advisor={})
431 {
432 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
433
434 if constexpr(std::is_invocable_r_v<bool, Compare, T, T>)
435 {
436 using finality = final_message_constant<!faithful_range<T>>;
437 binary_comparison(finality{}, sentry, std::move(compare), obtained, prediction, advisor);
438 }
439 else
440 {
441 check(std::move(compare), "", logger, obtained.begin(), obtained.end(), prediction.begin(), prediction.end(), advisor);
442 }
443
444 return !sentry.failure_detected();
445 }
446
453 namespace impl
454 {
455 template<class CheckType, test_mode Mode, faithful_range T, faithful_range U, class Advisor>
456 inline constexpr bool supports_range_check_v{
457 requires(T& t, U& u) {
458 requires supports_iterator_range_check<CheckType, Mode, decltype(std::ranges::begin(t)), decltype(std::ranges::begin(u)), Advisor>;
459 }
460 };
461 }
462
463 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
464 struct supports_range_check : std::false_type {};
465
466 template<class CheckType, test_mode Mode, faithful_range T, faithful_range U, class Advisor>
467 requires impl::supports_range_check_v<CheckType, Mode, T, U, Advisor>
468 struct supports_range_check<CheckType, Mode, T, U, Advisor> : std::true_type {};
469
470 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
471 inline constexpr bool supports_range_check_v{supports_range_check<CheckType, Mode, T, U, Advisor>::value};
472
475 template<test_mode Mode, class T, class Advisor>
476 inline constexpr bool supports_equality_check{
479 || supports_range_check_v<equality_check_t, Mode, T, T, Advisor>
480 };
481
500 template<test_mode Mode, class T, class Advisor=null_advisor>
501 requires supports_equality_check<Mode, T, Advisor>
503 std::string description,
504 test_logger<Mode>& logger,
505 const T& obtained,
506 const T& prediction,
507 tutor<Advisor> advisor={})
508 {
509 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
510
511 if constexpr(deep_equality_comparable<T>)
512 {
513 using finality = final_message_constant<!(tests_against_with_or_without_tutor<equality_check_t, Mode, T, T, tutor<Advisor>> || faithful_range<T>)>;
514 binary_comparison(finality{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
515 }
516
517 if constexpr(tests_against_with_or_without_tutor<equality_check_t, Mode, T, T, tutor<Advisor>>)
518 {
519 select_test(equality_check_t{}, logger, obtained, prediction, advisor);
520 }
521 else if constexpr(supports_range_check_v<equality_check_t, Mode, T, T, Advisor>)
522 {
523 check(equality, "", logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
524 }
525
526 return !sentry.failure_detected();
527 }
528
531 template<test_mode Mode, class T, class Advisor>
532 inline constexpr bool supports_simple_equality_check{
534 || supports_range_check_v<simple_equality_check_t, Mode, T, T, Advisor>
535 };
536
539 template<test_mode Mode, class T, class Advisor=null_advisor>
540 requires supports_simple_equality_check<Mode, T, Advisor>
542 std::string description,
543 test_logger<Mode>& logger,
544 const T& obtained,
545 const T& prediction,
546 tutor<Advisor> advisor={})
547 {
548 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
549
550 using finality = final_message_constant<!faithful_range<T>>;
551 binary_comparison(finality{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
552
553 if constexpr(supports_range_check_v<simple_equality_check_t, Mode, T, T, Advisor>)
554 {
555 check(simple_equality, "", logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
556 }
557
558 return !sentry.failure_detected();
559 }
560
575 template<class CheckType, test_mode Mode, class T, class U, class Advisor>
577 is_general_equivalence_check<CheckType>
579 || supports_range_check_v<CheckType, Mode, T, U, Advisor>
580 || checkable_against_fallback<CheckType, Mode, T, U, tutor<Advisor>>)
581 };
582
583 template<class CheckType, test_mode Mode, class T, class U, class Advisor=null_advisor>
584 requires supports_generalized_equivalence_check<CheckType, Mode, T, U, Advisor>
585 bool check(CheckType flavour, std::string description, test_logger<Mode>& logger, const T& obtained, const U& prediction, tutor<Advisor> advisor={})
586 {
587 if constexpr(tests_against_with_or_without_tutor<CheckType, Mode, T, U, tutor<Advisor>>)
588 {
589 return general_equivalence_check(flavour,
590 std::move(description),
591 logger,
592 obtained,
593 prediction,
594 advisor);
595 }
596 else if constexpr(supports_range_check_v<CheckType, Mode, T, U, Advisor>)
597 {
598 return check(flavour,
599 add_type_info<T>(std::move(description)),
600 logger,
601 std::begin(obtained),
602 std::end(obtained),
603 std::begin(prediction),
604 std::end(prediction),
605 advisor);
606 }
607 else if constexpr(checkable_against_fallback<CheckType, Mode, T, U, tutor<Advisor>>)
608 {
609 using fallback = typename CheckType::fallback;
610 return check(fallback{},
611 std::move(description),
612 logger,
613 obtained,
614 prediction,
615 advisor);
616 }
617 else
618 {
619 static_assert(dependent_false<CheckType>::value, "Should never be triggered; indicates mismatch between requirement and logic");
620 }
621 }
622
625 template<minimal_reporting_permitted MinimalReporting, test_mode Mode, class T, class U, class Advisor>
626 inline constexpr bool supports_best_available_check{
628 || has_elementary_check_against<Mode, T, U, tutor<Advisor>>
629 || supports_range_check_v<with_best_available_check_t<MinimalReporting>, Mode, T, U, Advisor>
630 || (std::is_same_v<T, U> && deep_equality_comparable<T> && reportable<T>)
631 || ((MinimalReporting == minimal_reporting_permitted::yes) && std::equality_comparable_with<T, U>)
632 };
633
636 template<minimal_reporting_permitted MinimalReporting, test_mode Mode, class T, class U, class Advisor=null_advisor>
637 requires supports_best_available_check<MinimalReporting, Mode, T, U, Advisor>
639 std::string description,
640 test_logger<Mode>& logger,
641 const T& obtained,
642 const U& prediction,
643 tutor<Advisor> advisor={})
644 {
645 if constexpr(tests_against_with_or_without_tutor<with_best_available_check_t<MinimalReporting>, Mode, T, U, tutor<Advisor>>)
646 {
647 sentinel<Mode> sentry{logger, add_type_info<T>(std::move(description))};
648
649 if constexpr(std::is_same_v<T, U> && deep_equality_comparable<T>)
650 {
651 binary_comparison(is_not_final_message_t{}, sentry, std::ranges::equal_to{}, obtained, prediction, advisor);
652 }
653
654 select_test(with_best_available, logger, obtained, prediction, advisor);
655
656 return !sentry.failure_detected();
657 }
658 else if constexpr(std::is_same_v<T, U> && tests_against_with_or_without_tutor<equality_check_t, Mode, T, U, tutor<Advisor>>)
659 {
660 return check(equality, description, logger, obtained, prediction, advisor);
661 }
662 else if constexpr(tests_against_with_or_without_tutor<equivalence_check_t, Mode, T, U, tutor<Advisor>>)
663 {
664 return check(equivalence, description, logger, obtained, prediction, advisor);
665 }
666 else if constexpr(tests_against_with_or_without_tutor<weak_equivalence_check_t, Mode, T, U, tutor<Advisor>>)
667 {
668 return check(weak_equivalence, description, logger, obtained, prediction, advisor);
669 }
670 else if constexpr(supports_range_check_v<with_best_available_check_t<MinimalReporting>, Mode, T, U, Advisor>)
671 {
672 return check(with_best_available, description, logger, std::begin(obtained), std::end(obtained), std::begin(prediction), std::end(prediction), advisor);
673 }
674 else if constexpr(std::is_same_v<T, U> && deep_equality_comparable<T> && reportable<T>)
675 {
676 return check(simple_equality, description, logger, obtained, prediction, advisor);
677 }
678 else if constexpr((MinimalReporting == minimal_reporting_permitted::yes) && std::equality_comparable_with<T, U>)
679 {
680 return check(description, logger, obtained == prediction,advisor);
681 }
682 else
683 {
684 static_assert(false);
685 }
686 }
687
688 template<test_mode Mode, class Advisor=null_advisor>
689 bool check(std::string description, test_logger<Mode>& logger, const bool obtained, tutor<Advisor> advisor={})
690 {
691 return check(equality, std::move(description), logger, obtained, true, std::move(advisor));
692 }
693
708 template<test_mode Mode, class Extender>
709 class checker : public Extender
710 {
711 friend Extender;
712 public:
713 constexpr static test_mode mode{Mode};
715
716 checker() = default;
717
718 checker(const checker&) = delete;
719 checker& operator=(const checker&) = delete;
720
721 template<class T, class Advisor = null_advisor, class Self>
722 requires supports_equality_check<Mode, T, Advisor>
723 bool check(this Self& self, equality_check_t, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
724 {
725 return testing::check(equality, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
726 }
727
728 template<class T, class Advisor = null_advisor, class Self>
729 requires supports_simple_equality_check<Mode, T, Advisor>
730 bool check(this Self& self, simple_equality_check_t, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
731 {
732 return testing::check(simple_equality, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
733 }
734
735 template<class T, class U, minimal_reporting_permitted MinimalReporting, class Advisor = null_advisor, class Self>
736 requires supports_best_available_check<MinimalReporting, Mode, T, U, Advisor>
737 bool check(this Self& self, with_best_available_check_t<MinimalReporting>, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
738 {
739 return testing::check(with_best_available_check_t<MinimalReporting>{},
740 self.report(description),
741 self.m_Logger,
742 obtained,
743 prediction,
744 std::move(advisor));
745 }
746
747 template<class ValueBasedCustomizer, class T, class U, class Advisor = null_advisor, class Self>
748 requires supports_generalized_equivalence_check<general_equivalence_check_t<ValueBasedCustomizer>, Mode, T, U, Advisor>
749 bool check(this Self& self, general_equivalence_check_t<ValueBasedCustomizer> checker, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
750 {
751 return testing::check(checker, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
752 }
753
754 template<class ValueBasedCustomizer, class T, class U, class Advisor = null_advisor, class Self>
755 requires supports_generalized_equivalence_check<general_weak_equivalence_check_t<ValueBasedCustomizer>, Mode, T, U, Advisor>
756 bool check(this Self& self, general_weak_equivalence_check_t<ValueBasedCustomizer> checker, const reporter& description, const T& obtained, const U& prediction, tutor<Advisor> advisor = {})
757 {
758 return testing::check(checker, self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
759 }
760
761 template<class Compare, class T, class Advisor = null_advisor, class Self>
762 requires potential_comparator_for<Compare, T>
763 bool check(this Self& self, Compare compare, const reporter& description, const T& obtained, const T& prediction, tutor<Advisor> advisor = {})
764 {
765 return testing::check(std::move(compare), self.report(description), self.m_Logger, obtained, prediction, std::move(advisor));
766 }
767
768 template<class Advisor=null_advisor, class Self>
769 bool check(this Self& self, const reporter& description, const bool obtained, tutor<Advisor> advisor={})
770 {
771 return testing::check(self.report(description), self.m_Logger, obtained, std::move(advisor));
772 }
773
774 template
775 <
776 class Compare,
777 std::input_or_output_iterator Iter,
778 std::sentinel_for<Iter> Sentinel,
779 std::input_or_output_iterator PredictionIter,
780 std::sentinel_for<PredictionIter> PredictionSentinel,
781 class Advisor = null_advisor,
782 class Self
783 >
784 requires supports_iterator_range_check<Compare, Mode, Iter, PredictionIter, Advisor>
785 bool check(this Self& self,
786 Compare compare,
787 const reporter& description,
788 Iter first,
789 Sentinel last,
790 PredictionIter predictionFirst,
791 PredictionSentinel predictionLast,
792 tutor<Advisor> advisor={})
793 {
794 return testing::check(std::move(compare), self.report(description), self.m_Logger, first, last, predictionFirst, predictionLast, std::move(advisor));
795 }
796
797 template
798 <
799 class E,
800 class Fn,
802 class Self
803 >
804 bool check_exception_thrown(this Self& self, const reporter& description, Fn&& function, Postprocessor postprocessor={})
805 {
806 return testing::check_exception_thrown<E>(self.report(description), self.m_Logger, std::forward<Fn>(function), self.get_project_paths(), std::move(postprocessor));
807 }
808
809#define STATIC_CHECK(...) (check("", [&](){ static_assert(__VA_ARGS__); return true; }()))
810
811 template<class Stream>
813 friend Stream& operator<<(Stream& os, const checker& c)
814 {
815 os << c.m_Logger;
816 return os;
817 }
818
819 [[nodiscard]]
820 log_summary summary(std::string_view prefix, const log_summary::duration delta) const
821 {
822 return log_summary{prefix, m_Logger, delta};
823 }
824
825 void reset_results() noexcept { m_Logger.reset_results(); }
826
827 [[nodiscard]]
828 bool has_critical_failures() const noexcept
829 {
830 return m_Logger.results().critical_failures > 0;
831 }
832 protected:
833 explicit checker(active_recovery_files recovery)
834 : m_Logger{std::move(recovery)}
835 {}
836
837 checker(checker&&) noexcept = default;
838 checker& operator=(checker&&) noexcept = default;
839
840 ~checker() = default;
841
842 [[nodiscard]]
843 std::size_t checks() const noexcept { return m_Logger.checks(); }
844
845 [[nodiscard]]
846 std::size_t failures() const noexcept { return m_Logger.failures(); }
847
848 [[nodiscard]]
849 const uncaught_exception_info& exceptions_detected_by_sentinel() const noexcept
850 {
851 return m_Logger.exceptions_detected_by_sentinel();
852 }
853
854 [[nodiscard]]
855 sentinel<Mode> make_sentinel(std::string message)
856 {
857 return {m_Logger, std::move(message)};
858 }
859
860 [[nodiscard]]
861 std::string_view top_level_message() const
862 {
863 return m_Logger.top_level_message();
864 }
865
866 [[nodiscard]]
867 const failure_output& failure_messages() const noexcept
868 {
869 return m_Logger.results().failure_messages;
870 }
871 private:
872 test_logger<Mode> m_Logger;
873 };
874}
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:532
constexpr bool supports_generalized_equivalence_check
The workhorse for (weak) equivalence checking.
Definition: FreeCheckers.hpp:576
constexpr bool supports_best_available_check
Condition for applying the best available check.
Definition: FreeCheckers.hpp:626
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:379
constexpr bool supports_equality_check
Condition for applying an equality check.
Definition: FreeCheckers.hpp:476
constexpr bool supports_iterator_range_check
Condition for applying a check across a range of values.
Definition: FreeCheckers.hpp:362
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.
test_mode
Specifies whether tests are run as standard tests or in false postive/negative mode.
Definition: TestMode.hpp:20
Meta-programming utilities.
Exposes elementary check methods, with the option to plug in arbitrary Extenders to compose functiona...
Definition: FreeCheckers.hpp:710
Summaries data generated by the logger, for the purposes of reporting.
Definition: TestLogger.hpp:299
Paths used by the project.
Definition: ProjectPaths.hpp:467
Definition: Output.hpp:176
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:464
Definition: CoreInfrastructure.hpp:99
class template, specializations of which implement various comparisons for the specified type.
Definition: FreeCheckers.hpp:78
Definition: FreeCheckers.hpp:128