micro-test-plus 3.2.0
µTest++, a lightweight testing framework for embedded platforms
Loading...
Searching...
No Matches
detail.h
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus/)
4 * Copyright (c) 2021 Liviu Ionescu.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from <https://opensource.org/licenses/MIT/>.
11 *
12 * Major parts of the code are inspired from v1.1.8 of the Boost UT project,
13 * released under the terms of the Boost Version 1.0 Software License,
14 * which can be obtained from <https://www.boost.org/LICENSE_1_0.txt>.
15 */
16
17#ifndef MICRO_TEST_PLUS_DETAIL_H_
18#define MICRO_TEST_PLUS_DETAIL_H_
19
20// ----------------------------------------------------------------------------
21
22#ifdef __cplusplus
23
24// ----------------------------------------------------------------------------
25
26#include <stdio.h>
27
28// ----------------------------------------------------------------------------
29
30#if defined(__GNUC__)
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wpadded"
33#pragma GCC diagnostic ignored "-Waggregate-return"
34#if defined(__clang__)
35#pragma clang diagnostic ignored "-Wc++98-compat"
36#endif
37#endif
38
40{
41 // --------------------------------------------------------------------------
42
46 namespace detail
47 {
52 template <class Expr_T>
58
59 // ------------------------------------------------------------------------
60
66 template <class T>
67 [[nodiscard]] constexpr auto
68 get_impl (const T& t, int) -> decltype (t.get ())
69 {
70 return t.get ();
71 }
72
77 template <class T>
78 [[nodiscard]] constexpr auto
79 get_impl (const T& t, ...) -> decltype (auto)
80 {
81 return t;
82 }
83
87 template <class T>
88 [[nodiscard]] constexpr auto
89 get (const T& t)
90 {
91 // Call the variadic function, basically to force it return `t`.
92 return get_impl (t, 0);
93 }
94
95 // ------------------------------------------------------------------------
96
101 template <class Lhs_T, class Rhs_T>
103 {
104 constexpr eq_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
105 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
106 // This lambda is called in the constructor to
107 // evaluate the comparison.
108 using std::operator==;
109 using std::operator<;
110
111#if defined(__GNUC__)
112#pragma GCC diagnostic push
113#pragma GCC diagnostic ignored "-Wfloat-equal"
114#pragma GCC diagnostic ignored "-Wconversion"
115#pragma GCC diagnostic ignored "-Wdouble-promotion"
116#pragma GCC diagnostic ignored "-Wsign-compare"
117#if defined(__clang__)
118#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
119#pragma clang diagnostic ignored "-Wpedantic"
120#endif
121#endif
124 {
125 // If both types have values (like numeric constants),
126 // compare them directly.
127 return Lhs_T::value == Rhs_T::value;
128 }
129 else if constexpr (type_traits::has_epsilon_v<Lhs_T>
131 {
132 // If both values have precision, compare them using
133 // the smalles precision.
134 return math::abs (get (lhs) - get (rhs))
135 < math::min_value (Lhs_T::epsilon, Rhs_T::epsilon);
136 }
137 else if constexpr (type_traits::has_epsilon_v<Lhs_T>)
138 {
139 // If only the left operand has precision, use it.
140 return math::abs (get (lhs) - get (rhs)) < Lhs_T::epsilon;
141 }
142 else if constexpr (type_traits::has_epsilon_v<Rhs_T>)
143 {
144 // If only the right operand has precision, use it.
145 return math::abs (get (lhs) - get (rhs)) < Rhs_T::epsilon;
146 }
147 else
148 {
149 // Call the generic getters, which might
150 // either call the type get() or return the value.
151 return get (lhs) == get (rhs);
152 }
153#if defined(__GNUC__)
154#pragma GCC diagnostic pop
155#endif
156 }() }
157 {
158 }
159
160 [[nodiscard]] constexpr
161 operator bool () const
162 {
163 return value_;
164 }
165
166 [[nodiscard]] constexpr auto
167 lhs () const
168 {
169 return get (lhs_);
170 }
171
172 [[nodiscard]] constexpr auto
173 rhs () const
174 {
175 return get (rhs_);
176 }
177
178 const Lhs_T lhs_{};
179 const Rhs_T rhs_{};
180 const bool value_{};
181 };
182
187 template <class Lhs_T, class Rhs_T>
189 {
190 constexpr ne_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
191 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
192 using std::operator==;
193 using std::operator!=;
194 using std::operator>;
195
196#if defined(__GNUC__)
197#pragma GCC diagnostic push
198#pragma GCC diagnostic ignored "-Wfloat-equal"
199#pragma GCC diagnostic ignored "-Wconversion"
200#pragma GCC diagnostic ignored "-Wdouble-promotion"
201#pragma GCC diagnostic ignored "-Wsign-compare"
202#if defined(__clang__)
203#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
204#pragma clang diagnostic ignored "-Wpedantic"
205#endif
206#endif
207 if constexpr (type_traits::has_value_v<Lhs_T>
208 and type_traits::has_value_v<Rhs_T>)
209 {
210 return Lhs_T::value != Rhs_T::value;
211 }
212 else if constexpr (type_traits::has_epsilon_v<Lhs_T>
213 and type_traits::has_epsilon_v<Rhs_T>)
214 {
215 return math::abs (get (lhs_) - get (rhs_))
216 > math::min_value (Lhs_T::epsilon, Rhs_T::epsilon);
217 }
218 else if constexpr (type_traits::has_epsilon_v<Lhs_T>)
219 {
220 return math::abs (get (lhs_) - get (rhs_)) > Lhs_T::epsilon;
221 }
222 else if constexpr (type_traits::has_epsilon_v<Rhs_T>)
223 {
224 return math::abs (get (lhs_) - get (rhs_)) > Rhs_T::epsilon;
225 }
226 else
227 {
228 return get (lhs_) != get (rhs_);
229 }
230#if defined(__GNUC__)
231#pragma GCC diagnostic pop
232#endif
233 }() }
234 {
235 }
236
237 [[nodiscard]] constexpr
238 operator bool () const
239 {
240 return value_;
241 }
242 [[nodiscard]] constexpr auto
243 lhs () const
244 {
245 return get (lhs_);
246 }
247 [[nodiscard]] constexpr auto
248 rhs () const
249 {
250 return get (rhs_);
251 }
252
253 const Lhs_T lhs_{};
254 const Rhs_T rhs_{};
255 const bool value_{};
256 };
257
262 template <class Lhs_T, class Rhs_T>
264 {
265 constexpr gt_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
266 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
267 using std::operator>;
268
269#if defined(__GNUC__)
270#pragma GCC diagnostic push
271#pragma GCC diagnostic ignored "-Wconversion"
272#pragma GCC diagnostic ignored "-Wdouble-promotion"
273#pragma GCC diagnostic ignored "-Wsign-compare"
274#if defined(__clang__)
275#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
276#pragma clang diagnostic ignored "-Wpedantic"
277#endif
278#endif
279 if constexpr (type_traits::has_value_v<Lhs_T>
280 and type_traits::has_value_v<Rhs_T>)
281 {
282 return Lhs_T::value > Rhs_T::value;
283 }
284 else
285 {
286 return get (lhs_) > get (rhs_);
287 }
288#if defined(__GNUC__)
289#pragma GCC diagnostic pop
290#endif
291 }() }
292 {
293 }
294
295 [[nodiscard]] constexpr
296 operator bool () const
297 {
298 return value_;
299 }
300 [[nodiscard]] constexpr auto
301 lhs () const
302 {
303 return get (lhs_);
304 }
305 [[nodiscard]] constexpr auto
306 rhs () const
307 {
308 return get (rhs_);
309 }
310
311 const Lhs_T lhs_{};
312 const Rhs_T rhs_{};
313 const bool value_{};
314 };
315
320 template <class Lhs_T, class Rhs_T>
322 {
323 constexpr ge_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
324 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
325 using std::operator>=;
326
327#if defined(__GNUC__)
328#pragma GCC diagnostic push
329#pragma GCC diagnostic ignored "-Wconversion"
330#pragma GCC diagnostic ignored "-Wdouble-promotion"
331#pragma GCC diagnostic ignored "-Wsign-compare"
332#if defined(__clang__)
333#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
334#pragma clang diagnostic ignored "-Wpedantic"
335#endif
336#endif
337 if constexpr (type_traits::has_value_v<Lhs_T>
338 and type_traits::has_value_v<Rhs_T>)
339 {
340 return Lhs_T::value >= Rhs_T::value;
341 }
342 else
343 {
344 return get (lhs_) >= get (rhs_);
345 }
346#if defined(__GNUC__)
347#pragma GCC diagnostic pop
348#endif
349 }() }
350 {
351 }
352
353 [[nodiscard]] constexpr
354 operator bool () const
355 {
356 return value_;
357 }
358 [[nodiscard]] constexpr auto
359 lhs () const
360 {
361 return get (lhs_);
362 }
363 [[nodiscard]] constexpr auto
364 rhs () const
365 {
366 return get (rhs_);
367 }
368
369 const Lhs_T lhs_{};
370 const Rhs_T rhs_{};
371 const bool value_{};
372 };
373
378 template <class Lhs_T, class Rhs_T>
380 {
381 constexpr lt_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
382 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
383 using std::operator<;
384
385#if defined(__GNUC__)
386#pragma GCC diagnostic push
387#pragma GCC diagnostic ignored "-Wconversion"
388#pragma GCC diagnostic ignored "-Wdouble-promotion"
389#pragma GCC diagnostic ignored "-Wsign-compare"
390#if defined(__clang__)
391#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
392#pragma clang diagnostic ignored "-Wpedantic"
393#endif
394#endif
395 if constexpr (type_traits::has_value_v<Lhs_T>
396 and type_traits::has_value_v<Rhs_T>)
397 {
398 return Lhs_T::value < Rhs_T::value;
399 }
400 else
401 {
402 return get (lhs_) < get (rhs_);
403 }
404#if defined(__GNUC__)
405#pragma GCC diagnostic pop
406#endif
407 }() }
408 {
409 }
410
411 [[nodiscard]] constexpr
412 operator bool () const
413 {
414 return value_;
415 }
416 [[nodiscard]] constexpr auto
417 lhs () const
418 {
419 return get (lhs_);
420 }
421 [[nodiscard]] constexpr auto
422 rhs () const
423 {
424 return get (rhs_);
425 }
426
427 private:
428 const Lhs_T lhs_{};
429 const Rhs_T rhs_{};
430 const bool value_{};
431 };
432
437 template <class Lhs_T, class Rhs_T>
439 {
440 constexpr le_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
441 : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
442 using std::operator<=;
443
444#if defined(__GNUC__)
445#pragma GCC diagnostic push
446#pragma GCC diagnostic ignored "-Wconversion"
447#pragma GCC diagnostic ignored "-Wdouble-promotion"
448#pragma GCC diagnostic ignored "-Wsign-compare"
449#if defined(__clang__)
450#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
451#pragma clang diagnostic ignored "-Wpedantic"
452#endif
453#endif
454 if constexpr (type_traits::has_value_v<Lhs_T>
455 and type_traits::has_value_v<Rhs_T>)
456 {
457 return Lhs_T::value <= Rhs_T::value;
458 }
459 else
460 {
461 return get (lhs_) <= get (rhs_);
462 }
463#if defined(__GNUC__)
464#pragma GCC diagnostic pop
465#endif
466 }() }
467 {
468 }
469
470 [[nodiscard]] constexpr
471 operator bool () const
472 {
473 return value_;
474 }
475
476 [[nodiscard]] constexpr auto
477 lhs () const
478 {
479 return get (lhs_);
480 }
481
482 [[nodiscard]] constexpr auto
483 rhs () const
484 {
485 return get (rhs_);
486 }
487
488 const Lhs_T lhs_{};
489 const Rhs_T rhs_{};
490 const bool value_{};
491 };
492
497 template <class Lhs_T, class Rhs_T>
499 {
500 constexpr and_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
501 : lhs_{ lhs }, rhs_{ rhs },
502 value_{ static_cast<bool> (lhs) and static_cast<bool> (rhs) }
503 {
504 }
505
506 [[nodiscard]] constexpr
507 operator bool () const
508 {
509 return value_;
510 }
511
512 [[nodiscard]] constexpr auto
513 lhs () const
514 {
515 return get (lhs_);
516 }
517
518 [[nodiscard]] constexpr auto
519 rhs () const
520 {
521 return get (rhs_);
522 }
523
524 const Lhs_T lhs_{};
525 const Rhs_T rhs_{};
526 const bool value_{};
527 };
528
533 template <class Lhs_T, class Rhs_T>
535 {
536 constexpr or_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
537 : lhs_{ lhs }, rhs_{ rhs },
538 value_{ static_cast<bool> (lhs) or static_cast<bool> (rhs) }
539 {
540 }
541
542 [[nodiscard]] constexpr
543 operator bool () const
544 {
545 return value_;
546 }
547
548 [[nodiscard]] constexpr auto
549 lhs () const
550 {
551 return get (lhs_);
552 }
553
554 [[nodiscard]] constexpr auto
555 rhs () const
556 {
557 return get (rhs_);
558 }
559
560 const Lhs_T lhs_{};
561 const Rhs_T rhs_{};
562 const bool value_{};
563 };
564
569 template <class T>
571 {
572 explicit constexpr not_ (const T& t = {})
573 : t_{ t }, value_{ not static_cast<bool> (t) }
574 {
575 }
576
577 [[nodiscard]] constexpr
578 operator bool () const
579 {
580 return value_;
581 }
582
583 [[nodiscard]] constexpr auto
584 value () const
585 {
586 return get (t_);
587 }
588
589 const T t_{};
590 const bool value_{};
591 };
592
593#if defined(__cpp_exceptions)
598 template <class Callable_T, class Exception_T = void>
600 {
601 constexpr explicit throws_ (const Callable_T& func)
602 : value_{ [&func] {
603 try
604 {
605 func ();
606 }
607 catch (const Exception_T&)
608 {
609 return true;
610 }
611 catch (...)
612 {
613 return false;
614 }
615 return false;
616 }() }
617 {
618 }
619
620 [[nodiscard]] constexpr
621 operator bool () const
622 {
623 return value_;
624 }
625
626 const bool value_{};
627 };
628
633 template <class Callable_T>
634 struct throws_<Callable_T, void> : type_traits::op
635 {
636 constexpr explicit throws_ (const Callable_T& func)
637 : value_{ [&func] {
638 try
639 {
640 func ();
641 }
642 catch (...)
643 {
644 return true;
645 }
646 return false;
647 }() }
648 {
649 }
650
651 [[nodiscard]] constexpr
652 operator bool () const
653 {
654 return value_;
655 }
656
657 const bool value_{};
658 };
659
664 template <class Callable_T>
666 {
667 constexpr explicit nothrow_ (const Callable_T& func)
668 : value_{ [&func] {
669 try
670 {
671 func ();
672 }
673 catch (...)
674 {
675 return false;
676 }
677 return true;
678 }() }
679 {
680 }
681
682 [[nodiscard]] constexpr
683 operator bool () const
684 {
685 return value_;
686 }
687
688 const bool value_{};
689 };
690#endif
691
692 // ------------------------------------------------------------------------
693
700 {
701 public:
702 deferred_reporter_base (bool value,
703 const reflection::source_location location);
704
706
707 template <class T>
708 auto&
709 operator<< (const T& msg);
710
711 [[nodiscard]] constexpr bool
712 value () const
713 {
714 return value_;
715 }
716
717 protected:
718 bool value_{};
719 bool abort_ = false;
721
726 std::string message_{};
727 };
728
734 template <class Expr_T>
736 {
737 public:
738 constexpr explicit deferred_reporter (
739 const Expr_T& expr, bool abort,
740 const reflection::source_location& location);
741
743
744 protected:
745 const Expr_T expr_{};
746 };
747
748 // ----------------------------------------------------------------------
749 } // namespace detail
750
751 // --------------------------------------------------------------------------
752} // namespace micro_os_plus::micro_test_plus
753
754#if defined(__GNUC__)
755#pragma GCC diagnostic pop
756#endif
757
758// ----------------------------------------------------------------------------
759
760#endif // __cplusplus
761
762// ----------------------------------------------------------------------------
763
764#endif // MICRO_TEST_PLUS_DETAIL_H_
765
766// ----------------------------------------------------------------------------
Base class for a deferred reporter, that collects the messages into a string.
Definition detail.h:700
Class template for a deferred reporter specific to an expression.
Definition detail.h:736
Local implementation of the std::source_location.
Definition reflection.h:58
constexpr auto get_impl(const T &t, int) -> decltype(t.get())
Generic getter implementation. If the type has a get() method, call it. It is recommended for custom ...
Definition detail.h:68
constexpr auto get(const T &t)
Generic getter, calling the getter implementation.
Definition detail.h:89
constexpr auto abs(const T t) -> T
Generic absolute of any value.
Definition math.h:56
constexpr auto min_value(const T &lhs, const T &rhs) -> const T &
Generic minimum of two values.
Definition math.h:66
constexpr and_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:500
An object used to pass assertion parameters to the evaluator.
Definition detail.h:54
reflection::source_location location
Definition detail.h:56
constexpr eq_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:104
Greater than or equal comparator.
Definition detail.h:322
constexpr ge_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:323
constexpr gt_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:265
Less than or equal comparator.
Definition detail.h:439
constexpr le_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:440
constexpr lt_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:381
constexpr ne_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:190
Operator to check if the expression does not throw any exception.
Definition detail.h:666
constexpr nothrow_(const Callable_T &func)
Definition detail.h:667
constexpr or_(const Lhs_T &lhs={}, const Rhs_T &rhs={})
Definition detail.h:536
Operator to check if the expression throws a specific exception.
Definition detail.h:600
constexpr throws_(const Callable_T &func)
Definition detail.h:601
Empty base class of all operators.