@micro-os-plus/micro-test-plus 2.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,733 @@
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
+
39
+ namespace micro_os_plus::micro_test_plus
40
+ {
41
+ // --------------------------------------------------------------------------
42
+
43
+ /**
44
+ * @brief Implementation details, not part of the public API.
45
+ */
46
+ namespace detail
47
+ {
48
+ /**
49
+ * @brief An object used to pass assertion parameters to the evaluator.
50
+ */
51
+ template <class Expr_T>
52
+ struct assertion
53
+ {
54
+ Expr_T expr{};
55
+ reflection::source_location location{};
56
+ };
57
+
58
+ // ------------------------------------------------------------------------
59
+
60
+ /**
61
+ * @brief Generic getter implementation. If the type has
62
+ * a get() method, call it. It is recommended for custom types
63
+ * to define a get() method.
64
+ */
65
+ template <class T>
66
+ [[nodiscard]] constexpr auto
67
+ get_impl (const T& t, int) -> decltype (t.get ())
68
+ {
69
+ return t.get ();
70
+ }
71
+
72
+ /**
73
+ * @brief Variadic getter implementation that returns the
74
+ * first argument and discards the rest.
75
+ */
76
+ template <class T>
77
+ [[nodiscard]] constexpr auto
78
+ get_impl (const T& t, ...) -> decltype (auto)
79
+ {
80
+ return t;
81
+ }
82
+
83
+ /**
84
+ * @brief Generic getter, calling the getter implementation.
85
+ */
86
+ template <class T>
87
+ [[nodiscard]] constexpr auto
88
+ get (const T& t)
89
+ {
90
+ // Call the variadic function, besically to force it return `t`.
91
+ return get_impl (t, 0);
92
+ }
93
+
94
+ // ------------------------------------------------------------------------
95
+
96
+ /**
97
+ * @brief Equality comparator.
98
+ */
99
+ template <class Lhs_T, class Rhs_T>
100
+ struct eq_ : type_traits::op
101
+ {
102
+ constexpr eq_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
103
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
104
+ // This lambda is called in the constructor to
105
+ // evaluate the comparison.
106
+ using std::operator==;
107
+ using std::operator<;
108
+
109
+ #if defined(__GNUC__)
110
+ #pragma GCC diagnostic push
111
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
112
+ #pragma GCC diagnostic ignored "-Wconversion"
113
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
114
+ #pragma GCC diagnostic ignored "-Wsign-compare"
115
+ #if defined(__clang__)
116
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
117
+ #pragma clang diagnostic ignored "-Wpedantic"
118
+ #endif
119
+ #endif
120
+ if constexpr (type_traits::has_value_v<
121
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
122
+ {
123
+ // If both types have values (like numeric constants),
124
+ // compare them directly.
125
+ return Lhs_T::value == Rhs_T::value;
126
+ }
127
+ else if constexpr (
128
+ type_traits::has_epsilon_v<
129
+ Lhs_T> and type_traits::has_epsilon_v<Rhs_T>)
130
+ {
131
+ // If both values have precision, compare them using
132
+ // the smalles precision.
133
+ return math::abs (get (lhs) - get (rhs))
134
+ < math::min_value (Lhs_T::epsilon, Rhs_T::epsilon);
135
+ }
136
+ else if constexpr (type_traits::has_epsilon_v<Lhs_T>)
137
+ {
138
+ // If only the left operand has precision, use it.
139
+ return math::abs (get (lhs) - get (rhs)) < Lhs_T::epsilon;
140
+ }
141
+ else if constexpr (type_traits::has_epsilon_v<Rhs_T>)
142
+ {
143
+ // If only the right operand has precision, use it.
144
+ return math::abs (get (lhs) - get (rhs)) < Rhs_T::epsilon;
145
+ }
146
+ else
147
+ {
148
+ // Call the generic getters, which might
149
+ // either call the type get() or return the value.
150
+ return get (lhs) == get (rhs);
151
+ }
152
+ #if defined(__GNUC__)
153
+ #pragma GCC diagnostic pop
154
+ #endif
155
+ }() }
156
+ {
157
+ }
158
+
159
+ [[nodiscard]] constexpr operator bool () const
160
+ {
161
+ return value_;
162
+ }
163
+
164
+ [[nodiscard]] constexpr auto
165
+ lhs () const
166
+ {
167
+ return get (lhs_);
168
+ }
169
+
170
+ [[nodiscard]] constexpr auto
171
+ rhs () const
172
+ {
173
+ return get (rhs_);
174
+ }
175
+
176
+ const Lhs_T lhs_{};
177
+ const Rhs_T rhs_{};
178
+ const bool value_{};
179
+ };
180
+
181
+ /**
182
+ * @brief Non-equality comparator.
183
+ */
184
+ template <class Lhs_T, class Rhs_T>
185
+ struct ne_ : type_traits::op
186
+ {
187
+ constexpr ne_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
188
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
189
+ using std::operator==;
190
+ using std::operator!=;
191
+ using std::operator>;
192
+
193
+ #if defined(__GNUC__)
194
+ #pragma GCC diagnostic push
195
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
196
+ #pragma GCC diagnostic ignored "-Wconversion"
197
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
198
+ #pragma GCC diagnostic ignored "-Wsign-compare"
199
+ #if defined(__clang__)
200
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
201
+ #pragma clang diagnostic ignored "-Wpedantic"
202
+ #endif
203
+ #endif
204
+ if constexpr (type_traits::has_value_v<
205
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
206
+ {
207
+ return Lhs_T::value != Rhs_T::value;
208
+ }
209
+ else if constexpr (
210
+ type_traits::has_epsilon_v<
211
+ Lhs_T> and type_traits::has_epsilon_v<Rhs_T>)
212
+ {
213
+ return math::abs (get (lhs_) - get (rhs_))
214
+ > math::min_value (Lhs_T::epsilon, Rhs_T::epsilon);
215
+ }
216
+ else if constexpr (type_traits::has_epsilon_v<Lhs_T>)
217
+ {
218
+ return math::abs (get (lhs_) - get (rhs_)) > Lhs_T::epsilon;
219
+ }
220
+ else if constexpr (type_traits::has_epsilon_v<Rhs_T>)
221
+ {
222
+ return math::abs (get (lhs_) - get (rhs_)) > Rhs_T::epsilon;
223
+ }
224
+ else
225
+ {
226
+ return get (lhs_) != get (rhs_);
227
+ }
228
+ #if defined(__GNUC__)
229
+ #pragma GCC diagnostic pop
230
+ #endif
231
+ }() }
232
+ {
233
+ }
234
+
235
+ [[nodiscard]] constexpr operator bool () const
236
+ {
237
+ return value_;
238
+ }
239
+ [[nodiscard]] constexpr auto
240
+ lhs () const
241
+ {
242
+ return get (lhs_);
243
+ }
244
+ [[nodiscard]] constexpr auto
245
+ rhs () const
246
+ {
247
+ return get (rhs_);
248
+ }
249
+
250
+ const Lhs_T lhs_{};
251
+ const Rhs_T rhs_{};
252
+ const bool value_{};
253
+ };
254
+
255
+ /**
256
+ * @brief Greater than comparator.
257
+ */
258
+ template <class Lhs_T, class Rhs_T>
259
+ struct gt_ : type_traits::op
260
+ {
261
+ constexpr gt_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
262
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
263
+ using std::operator>;
264
+
265
+ #if defined(__GNUC__)
266
+ #pragma GCC diagnostic push
267
+ #pragma GCC diagnostic ignored "-Wconversion"
268
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
269
+ #pragma GCC diagnostic ignored "-Wsign-compare"
270
+ #if defined(__clang__)
271
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
272
+ #pragma clang diagnostic ignored "-Wpedantic"
273
+ #endif
274
+ #endif
275
+ if constexpr (type_traits::has_value_v<
276
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
277
+ {
278
+ return Lhs_T::value > Rhs_T::value;
279
+ }
280
+ else
281
+ {
282
+ return get (lhs_) > get (rhs_);
283
+ }
284
+ #if defined(__GNUC__)
285
+ #pragma GCC diagnostic pop
286
+ #endif
287
+ }() }
288
+ {
289
+ }
290
+
291
+ [[nodiscard]] constexpr operator bool () const
292
+ {
293
+ return value_;
294
+ }
295
+ [[nodiscard]] constexpr auto
296
+ lhs () const
297
+ {
298
+ return get (lhs_);
299
+ }
300
+ [[nodiscard]] constexpr auto
301
+ rhs () const
302
+ {
303
+ return get (rhs_);
304
+ }
305
+
306
+ const Lhs_T lhs_{};
307
+ const Rhs_T rhs_{};
308
+ const bool value_{};
309
+ };
310
+
311
+ /**
312
+ * @brief Greater than or equal comparator.
313
+ */
314
+ template <class Lhs_T, class Rhs_T>
315
+ struct ge_ : type_traits::op
316
+ {
317
+ constexpr ge_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
318
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
319
+ using std::operator>=;
320
+
321
+ #if defined(__GNUC__)
322
+ #pragma GCC diagnostic push
323
+ #pragma GCC diagnostic ignored "-Wconversion"
324
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
325
+ #pragma GCC diagnostic ignored "-Wsign-compare"
326
+ #if defined(__clang__)
327
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
328
+ #pragma clang diagnostic ignored "-Wpedantic"
329
+ #endif
330
+ #endif
331
+ if constexpr (type_traits::has_value_v<
332
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
333
+ {
334
+ return Lhs_T::value >= Rhs_T::value;
335
+ }
336
+ else
337
+ {
338
+ return get (lhs_) >= get (rhs_);
339
+ }
340
+ #if defined(__GNUC__)
341
+ #pragma GCC diagnostic pop
342
+ #endif
343
+ }() }
344
+ {
345
+ }
346
+
347
+ [[nodiscard]] constexpr operator bool () const
348
+ {
349
+ return value_;
350
+ }
351
+ [[nodiscard]] constexpr auto
352
+ lhs () const
353
+ {
354
+ return get (lhs_);
355
+ }
356
+ [[nodiscard]] constexpr auto
357
+ rhs () const
358
+ {
359
+ return get (rhs_);
360
+ }
361
+
362
+ const Lhs_T lhs_{};
363
+ const Rhs_T rhs_{};
364
+ const bool value_{};
365
+ };
366
+
367
+ /**
368
+ * @brief Less than comparator.
369
+ */
370
+ template <class Lhs_T, class Rhs_T>
371
+ struct lt_ : type_traits::op
372
+ {
373
+ constexpr lt_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
374
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
375
+ using std::operator<;
376
+
377
+ #if defined(__GNUC__)
378
+ #pragma GCC diagnostic push
379
+ #pragma GCC diagnostic ignored "-Wconversion"
380
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
381
+ #pragma GCC diagnostic ignored "-Wsign-compare"
382
+ #if defined(__clang__)
383
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
384
+ #pragma clang diagnostic ignored "-Wpedantic"
385
+ #endif
386
+ #endif
387
+ if constexpr (type_traits::has_value_v<
388
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
389
+ {
390
+ return Lhs_T::value < Rhs_T::value;
391
+ }
392
+ else
393
+ {
394
+ return get (lhs_) < get (rhs_);
395
+ }
396
+ #if defined(__GNUC__)
397
+ #pragma GCC diagnostic pop
398
+ #endif
399
+ }() }
400
+ {
401
+ }
402
+
403
+ [[nodiscard]] constexpr operator bool () const
404
+ {
405
+ return value_;
406
+ }
407
+ [[nodiscard]] constexpr auto
408
+ lhs () const
409
+ {
410
+ return get (lhs_);
411
+ }
412
+ [[nodiscard]] constexpr auto
413
+ rhs () const
414
+ {
415
+ return get (rhs_);
416
+ }
417
+
418
+ private:
419
+ const Lhs_T lhs_{};
420
+ const Rhs_T rhs_{};
421
+ const bool value_{};
422
+ };
423
+
424
+ /**
425
+ * @brief Less than or equal comparator.
426
+ */
427
+ template <class Lhs_T, class Rhs_T>
428
+ struct le_ : type_traits::op
429
+ {
430
+ constexpr le_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
431
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ [&] {
432
+ using std::operator<=;
433
+
434
+ #if defined(__GNUC__)
435
+ #pragma GCC diagnostic push
436
+ #pragma GCC diagnostic ignored "-Wconversion"
437
+ #pragma GCC diagnostic ignored "-Wdouble-promotion"
438
+ #pragma GCC diagnostic ignored "-Wsign-compare"
439
+ #if defined(__clang__)
440
+ #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
441
+ #pragma clang diagnostic ignored "-Wpedantic"
442
+ #endif
443
+ #endif
444
+ if constexpr (type_traits::has_value_v<
445
+ Lhs_T> and type_traits::has_value_v<Rhs_T>)
446
+ {
447
+ return Lhs_T::value <= Rhs_T::value;
448
+ }
449
+ else
450
+ {
451
+ return get (lhs_) <= get (rhs_);
452
+ }
453
+ #if defined(__GNUC__)
454
+ #pragma GCC diagnostic pop
455
+ #endif
456
+ }() }
457
+ {
458
+ }
459
+
460
+ [[nodiscard]] constexpr operator bool () const
461
+ {
462
+ return value_;
463
+ }
464
+
465
+ [[nodiscard]] constexpr auto
466
+ lhs () const
467
+ {
468
+ return get (lhs_);
469
+ }
470
+
471
+ [[nodiscard]] constexpr auto
472
+ rhs () const
473
+ {
474
+ return get (rhs_);
475
+ }
476
+
477
+ const Lhs_T lhs_{};
478
+ const Rhs_T rhs_{};
479
+ const bool value_{};
480
+ };
481
+
482
+ /**
483
+ * @brief Logical and operator.
484
+ */
485
+ template <class Lhs_T, class Rhs_T>
486
+ struct and_ : type_traits::op
487
+ {
488
+ constexpr and_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
489
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ static_cast<bool> (lhs)
490
+ and static_cast<bool> (rhs) }
491
+ {
492
+ }
493
+
494
+ [[nodiscard]] constexpr operator bool () const
495
+ {
496
+ return value_;
497
+ }
498
+
499
+ [[nodiscard]] constexpr auto
500
+ lhs () const
501
+ {
502
+ return get (lhs_);
503
+ }
504
+
505
+ [[nodiscard]] constexpr auto
506
+ rhs () const
507
+ {
508
+ return get (rhs_);
509
+ }
510
+
511
+ const Lhs_T lhs_{};
512
+ const Rhs_T rhs_{};
513
+ const bool value_{};
514
+ };
515
+
516
+ /**
517
+ * @brief Logical or operator.
518
+ */
519
+ template <class Lhs_T, class Rhs_T>
520
+ struct or_ : type_traits::op
521
+ {
522
+ constexpr or_ (const Lhs_T& lhs = {}, const Rhs_T& rhs = {})
523
+ : lhs_{ lhs }, rhs_{ rhs }, value_{ static_cast<bool> (lhs)
524
+ or static_cast<bool> (rhs) }
525
+ {
526
+ }
527
+
528
+ [[nodiscard]] constexpr operator bool () const
529
+ {
530
+ return value_;
531
+ }
532
+
533
+ [[nodiscard]] constexpr auto
534
+ lhs () const
535
+ {
536
+ return get (lhs_);
537
+ }
538
+
539
+ [[nodiscard]] constexpr auto
540
+ rhs () const
541
+ {
542
+ return get (rhs_);
543
+ }
544
+
545
+ const Lhs_T lhs_{};
546
+ const Rhs_T rhs_{};
547
+ const bool value_{};
548
+ };
549
+
550
+ /**
551
+ * @brief Logical not operator.
552
+ */
553
+ template <class T>
554
+ struct not_ : type_traits::op
555
+ {
556
+ explicit constexpr not_ (const T& t = {})
557
+ : t_{ t }, value_{ not static_cast<bool> (t) }
558
+ {
559
+ }
560
+
561
+ [[nodiscard]] constexpr operator bool () const
562
+ {
563
+ return value_;
564
+ }
565
+
566
+ [[nodiscard]] constexpr auto
567
+ value () const
568
+ {
569
+ return get (t_);
570
+ }
571
+
572
+ const T t_{};
573
+ const bool value_{};
574
+ };
575
+
576
+ #if defined(__cpp_exceptions)
577
+ /**
578
+ * @brief Operator to check if the expression throws a specific exception.
579
+ */
580
+ template <class Callable_T, class Exception_T = void>
581
+ struct throws_ : type_traits::op
582
+ {
583
+ constexpr explicit throws_ (const Callable_T& func)
584
+ : value_{ [&func] {
585
+ try
586
+ {
587
+ func ();
588
+ }
589
+ catch (const Exception_T&)
590
+ {
591
+ return true;
592
+ }
593
+ catch (...)
594
+ {
595
+ return false;
596
+ }
597
+ return false;
598
+ }() }
599
+ {
600
+ }
601
+
602
+ [[nodiscard]] constexpr operator bool () const
603
+ {
604
+ return value_;
605
+ }
606
+
607
+ const bool value_{};
608
+ };
609
+
610
+ /**
611
+ * @brief Operator to check if the expression throws any exception.
612
+ */
613
+ template <class Callable_T>
614
+ struct throws_<Callable_T, void> : type_traits::op
615
+ {
616
+ constexpr explicit throws_ (const Callable_T& func)
617
+ : value_{ [&func] {
618
+ try
619
+ {
620
+ func ();
621
+ }
622
+ catch (...)
623
+ {
624
+ return true;
625
+ }
626
+ return false;
627
+ }() }
628
+ {
629
+ }
630
+
631
+ [[nodiscard]] constexpr operator bool () const
632
+ {
633
+ return value_;
634
+ }
635
+
636
+ const bool value_{};
637
+ };
638
+
639
+ /**
640
+ * @brief Operator to check if the expression does not throw any exception.
641
+ */
642
+ template <class Callable_T>
643
+ struct nothrow_ : type_traits::op
644
+ {
645
+ constexpr explicit nothrow_ (const Callable_T& func)
646
+ : value_{ [&func] {
647
+ try
648
+ {
649
+ func ();
650
+ }
651
+ catch (...)
652
+ {
653
+ return false;
654
+ }
655
+ return true;
656
+ }() }
657
+ {
658
+ }
659
+
660
+ [[nodiscard]] constexpr operator bool () const
661
+ {
662
+ return value_;
663
+ }
664
+
665
+ const bool value_{};
666
+ };
667
+ #endif
668
+
669
+ // ------------------------------------------------------------------------
670
+
671
+ class deferred_reporter_base
672
+ {
673
+ public:
674
+ deferred_reporter_base (bool value,
675
+ const reflection::source_location location);
676
+
677
+ ~deferred_reporter_base ();
678
+
679
+ template <class T>
680
+ auto&
681
+ operator<< (const T& msg);
682
+
683
+ [[nodiscard]] constexpr bool
684
+ value () const
685
+ {
686
+ return value_;
687
+ }
688
+
689
+ protected:
690
+ bool value_{};
691
+ bool abort_ = false;
692
+ const reflection::source_location location_{};
693
+
694
+ /**
695
+ * @brief String to collect the expectation message passed via
696
+ * `operator<<()`.
697
+ */
698
+ std::string message_{};
699
+ };
700
+
701
+ template <class Expr_T>
702
+ class deferred_reporter : public deferred_reporter_base
703
+ {
704
+ public:
705
+ constexpr explicit deferred_reporter (
706
+ const Expr_T& expr, bool abort,
707
+ const reflection::source_location& location);
708
+
709
+ ~deferred_reporter ();
710
+
711
+ protected:
712
+ const Expr_T expr_{};
713
+ };
714
+
715
+ // ----------------------------------------------------------------------
716
+ } // namespace detail
717
+
718
+ // --------------------------------------------------------------------------
719
+ } // namespace micro_os_plus::micro_test_plus
720
+
721
+ #if defined(__GNUC__)
722
+ #pragma GCC diagnostic pop
723
+ #endif
724
+
725
+ // ----------------------------------------------------------------------------
726
+
727
+ #endif // __cplusplus
728
+
729
+ // ----------------------------------------------------------------------------
730
+
731
+ #endif // MICRO_TEST_PLUS_DETAIL_H_
732
+
733
+ // ----------------------------------------------------------------------------