@micro-os-plus/micro-test-plus 3.1.1 → 3.1.2

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.
package/README.md CHANGED
@@ -1,1241 +1,27 @@
1
+ [![GitHub package.json version](https://img.shields.io/github/package-json/v/micro-os-plus/micro-test-plus-xpack)](https://github.com/micro-os-plus/micro-test-plus-xpack/blob/xpack/package.json)
2
+ [![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/micro-os-plus/micro-test-plus-xpack)](https://github.com/micro-os-plus/micro-test-plus-xpack/tags/)
3
+ [![npm (scoped)](https://img.shields.io/npm/v/@micro-os-plus/micro-test-plus.svg?color=blue)](https://www.npmjs.com/package/@micro-os-plus/micro-test-plus/)
1
4
  [![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/micro-os-plus/micro-test-plus-xpack/blob/xpack/LICENSE)
2
- [![CI on Push](https://github.com/micro-os-plus/micro-test-plus-xpack/actions/workflows/CI.yml/badge.svg)](https://github.com/micro-os-plus/micro-test-plus-xpack/actions/workflows/CI.yml)
5
+ [![CI on Push](https://github.com/micro-os-plus/micro-test-plus-xpack/actions/workflows/ci.yml/badge.svg)](https://github.com/micro-os-plus/micro-test-plus-xpack/actions/workflows/ci.yml)
6
+ [![Website](https://img.shields.io/website?url=https%3A%2F%2Fmicro-os-plus.github.io%2Fmicro-test-plus-xpack%2F)](https://micro-os-plus.github.io/micro-test-plus-xpack/)
3
7
 
4
- # A source library xPack with µTest++, a lightweight testing framework for embedded platforms
8
+ # A source code library with µTest++, a lightweight testing framework for embedded platforms
5
9
 
6
10
  The **µTest++** project (_micro test plus_) provides a small memory footprint
7
11
  testing framework, intended for running unit tests on embedded
8
12
  platforms.
9
13
 
10
- The project is hosted on GitHub as
11
- [micro-os-plus/micro-test-plus-xpack](https://github.com/micro-os-plus/micro-test-plus-xpack).
14
+ ## [Project documentation](https://micro-os-plus.github.io/micro-test-plus-xpack/)
12
15
 
13
- ## Maintainer info
14
-
15
- This page is addressed to developers who plan to include this source
16
- library into their own projects.
17
-
18
- For maintainer info, please see the
19
- [README-MAINTAINER](README-MAINTAINER.md) file.
20
-
21
- ## Install
22
-
23
- As a source library xPack, the easiest way to add it to a project is via
24
- **xpm**, but it can also be used as any Git project, for example as a submodule.
25
-
26
- ### Prerequisites
27
-
28
- A recent [xpm](https://xpack.github.io/xpm/),
29
- which is a portable [Node.js](https://nodejs.org/) command line application.
30
-
31
- For details please follow the instructions in the
32
- [xPack install](https://xpack.github.io/install/) page.
33
-
34
- ### xpm
35
-
36
- This package is available from npmjs.com as
37
- [`@micro-os-plus/micro-test-plus`](https://www.npmjs.com/package/@micro-os-plus/micro-test-plus)
38
- from the `npmjs.com` registry:
39
-
40
- ```sh
41
- cd my-project
42
- xpm init # Unless a package.json is already present
43
-
44
- xpm install @micro-os-plus/micro-test-plus@latest
45
-
46
- ls -l xpacks/micro-os-plus-micro-test-plus
47
- ```
48
-
49
- ### Git submodule
50
-
51
- If, for any reason, **xpm** is not available, the next recommended
52
- solution is to link it as a Git submodule, preferably below an `xpacks`
53
- folder.
54
-
55
- ```sh
56
- cd my-project
57
- git init # Unless already a Git project
58
- mkdir -p xpacks
59
-
60
- git submodule add \
61
- https://github.com/micro-os-plus/micro-test-plus-xpack.git \
62
- xpacks/micro-os-plus-micro-test-plus
63
- ```
64
-
65
- ## Branches
66
-
67
- Apart from the unused `master` branch, there are two active branches:
68
-
69
- - `xpack`, with the latest stable version (default)
70
- - `xpack-develop`, with the current development version
71
-
72
- All development is done in the `xpack-develop` branch, and contributions via
73
- Pull Requests should be directed to this branch.
74
-
75
- When new releases are published, the `xpack-develop` branch is merged
76
- into `xpack`.
77
-
78
- ## Developer info
79
-
80
- The xPack Build Framework already includes ready to use
81
- support for several testing frameworks:
82
-
83
- - [Google Test](https://github.com/xpack-3rd-party/googletest-xpack)
84
- - [Catch2](https://github.com/xpack-3rd-party/catch2-xpack)
85
- - [Boost UT](https://github.com/xpack-3rd-party/boost-ut-xpack)
86
-
87
- However, they all are quite heavy in terms of memory resources; also the
88
- learning curve for mastering them is quite steep.
89
-
90
- Thus, for embedded projects, a simpler solution, with a smaller
91
- memory footprint, was considered a useful addition.
92
-
93
- ### Overview
94
-
95
- The initial version of the **µTest++** framework was inspired mainly by
96
- [Node tap](https://node-tap.org) and aimed for simplicity.
97
- The later v3.x was a full rework inspired by
98
- [Boost UT](https://boost-ext.github.io/ut/).
99
-
100
- The main characteristics of µTest++, basically inherited from Boost UT, are:
101
-
102
- - intended to test **both C and C++** projects
103
- - modern C++ 20 code (this was also the reason
104
- to raise the bar to C++ 20 for the entire µOS++ project)
105
- - **macro free** (while preserving the nice feature of being able to report
106
- the file name and line number for failed tests)
107
- - **expectations**, **assumptions**, **exceptions**
108
- - **test cases**, **test suites**
109
- - automatic test suites registration
110
-
111
- As major differentiator from Boost UT:
112
-
113
- - **reduced memory footprint**, since there are no dependencies on
114
- the standard C++ stream library
115
- - a slightly **simplified API**
116
-
117
- ### Concepts and features
118
-
119
- - for complex applications, test cases can be grouped in test suites
120
- - test suites can be located in separate compilation units; they automatically
121
- register themselves to the runner;
122
- - a **test suite** is a named sequence of test cases;
123
- - a **test case** is a sequence of **test conditions**
124
- (or simply **tests**, or **checks**),
125
- which are expectations/assumptions,
126
- i.e. conditions expected to be true;
127
- - tests are based on logical expressions, which usually
128
- compute a result and compare it to an expected value
129
- - for C++ projects: it is also possible to check if, while evaluating
130
- an expression, **exceptions** are thrown or not;
131
- - each test either succeeds or fails;
132
- - for **expectations**, the runner keeps counts of them;
133
- - **assumptions** are hard conditions expected to be true in order for the test
134
- to be able to run;
135
- - failed assumptions abort the test;
136
- - the test progress is shown on STDOUT, with each tests on a
137
- separate line, prefixed with either a check sign (✓) or a cross sign (✗);
138
- - failed tests display the location in the file and, if possible,
139
- the actual values used in the expression evaluation;
140
- - the main result of the test is passed back to the system as the process
141
- exit code.
142
-
143
- A test suite is considered successful
144
- if there is at least one successful expectation
145
- and there are no failed tests.
146
-
147
- If all tests suites are successful, the process returns 0 as exit value.
148
-
149
- ### ISTQB Glossary
150
-
151
- The **International Software Testing Qualification Board** defines some terms
152
- used in testing frameworks:
153
-
154
- - **test condition**: a testable aspect of a component or system identified
155
- as a basis for testing (implemented in µTest++ as calls to `expect()` or
156
- `assume()` functions);
157
- - **test case**: a set of preconditions, inputs, actions (where applicable),
158
- expected results and postconditions, developed based on test conditions
159
- (implemented in µTest++ as calls to the `test_case()` function)
160
- - **test suite**: a set of test scripts or test procedures to be executed in
161
- a specific test run (implemented in µTest++ as instances of the
162
- `test_suite` class).
163
-
164
- For more details see: <http://glossary.istqb.org/en/search/test%20case>.
165
-
166
- ### Getting started
167
-
168
- The absolute minimal test has a single test case, with a single expectation;
169
- for example:
170
-
171
- ```c++
172
- #include <micro-os-plus/micro-test-plus.h>
173
-
174
- int
175
- main(int argc, char* argv[])
176
- {
177
- using namespace micro_os_plus::micro_test_plus;
178
-
179
- initialize(argc, argv, "Minimal");
180
-
181
- test_case ("Check truth", [] {
182
- expect (true);
183
- })
184
-
185
- return exit_code ();
186
- }
187
- ```
188
-
189
- When running this test, the output looks like:
190
-
191
- ```console
192
- • Minimal - test suite started
193
-
194
- ✓ Check truth - test case passed (1 check)
195
-
196
- ✓ Minimal - test suite passed (1 check in 1 test case)
197
- ```
198
-
199
- A slightly more useful example would check the result of a computed value;
200
- for example:
201
-
202
- ```c++
203
- #include <micro-os-plus/micro-test-plus.h>
204
-
205
- static int
206
- compute_answer()
207
- {
208
- return 42;
209
- }
210
-
211
- int
212
- main(int argc, char* argv[])
213
- {
214
- using namespace micro_os_plus::micro_test_plus;
215
-
216
- initialize(argc, argv, "The Answer");
217
-
218
- test_case ("Check answer", [] {
219
- expect (compute_answer() == 42) << "answer is 42";
220
- });
221
-
222
- return exit_code ();
223
- }
224
- ```
225
-
226
- ```console
227
- • The Answer - test suite started
228
-
229
- ✓ Check answer - test case passed (1 check)
230
-
231
- ✓ The Answer - test suite passed (1 check passed, 0 checks failed, in 1 test case)
232
- ```
233
-
234
- In case the function returns the wrong answer, the test will fail;
235
- for example:
236
-
237
- ```c++
238
- static int
239
- compute_answer()
240
- {
241
- return 42 + 1;
242
- }
243
- ```
244
-
245
- In this case the test will fail with:
246
-
247
- ```console
248
- • The Answer - test suite started
249
-
250
- • Check answer - test case started
251
- ✗ answer is 42 FAILED (answer.cpp:17)
252
- ✗ Check answer - test case FAILED (0 checks passed, 1 check failed)
253
-
254
- ✗ The Answer - test suite FAILED (0 checks passed, 1 check failed, in 1 test case)
255
- ```
256
-
257
- The output identifies the failed test as located at line 17, but does not
258
- provide more details, for example it does not tell what was the actual
259
- wrong answer.
260
-
261
- To get such a useful information, the test should be slightly more elaborate,
262
- and must use some custom comparators or operators; for example:
263
-
264
- ```c++
265
- // ...
266
-
267
- int
268
- main(int argc, char* argv[])
269
- {
270
- using namespace micro_os_plus::micro_test_plus;
271
-
272
- initialize(argc, argv, "The Answer");
273
-
274
- test_case ("Check answer with comparator", [] {
275
- expect (eq (compute_answer (), 42)) << "answer is 42";
276
- });
277
-
278
- test_case ("Check answer with operator", [] {
279
- using namespace micro_os_plus::micro_test_plus::operators;
280
- using namespace micro_os_plus::micro_test_plus::literals;
281
-
282
- expect (compute_answer () == 42_i) << "answer is 42";
283
- expect (_i {compute_answer ()} == 42) << "answer is 42";
284
- });
285
-
286
- return exit_code ();
287
- }
288
- ```
289
-
290
- The result would look like:
291
-
292
- ```console
293
- • The Answer - test suite started
294
-
295
- • Check answer with comparator - test case started
296
- ✗ answer is 42 FAILED (answer.cpp:17, 43 == 42)
297
- ✗ Check answer with comparator - test case FAILED (0 checks passed, 1 check failed)
298
-
299
- • Check answer with operator - test case started
300
- ✗ answer is 42 FAILED (answer.cpp:24, 43 == 42)
301
- ✗ answer is 42 FAILED (answer.cpp:25, 43 == 42)
302
- ✗ Check answer with operator - test case FAILED (0 checks passed, 1 check failed)
303
-
304
- ✗ The Answer - test suite FAILED (0 checks passed, 3 checks failed, in 2 test cases)
305
- ```
306
-
307
- In the first case, `eq()` is a function that basically compares almost
308
- everything and is able to keep track of the values of its operands.
309
- There are similar functions for all comparisons.
310
-
311
- In the second case, a custom operator is used. To avoid interferences
312
- with other operators, this custom operator is defined in a separate namespace
313
- (which must
314
- be explicitly referred to as shown) and matches only operands of
315
- some specific types.
316
-
317
- To cast the integer constant `42` to such a specific type, a custom literal
318
- is available (`_i`), which is also defined in a separate namespace.
319
-
320
- In addition to literals used to define constants, there are also definitions
321
- which can be used to cast expressions.
322
-
323
- For the custom operators to match, it is necessary for at least one of
324
- the operands
325
- to be of the specific type, usually the constant using a literal, but if both
326
- are expression, at least one of them must be casted.
327
-
328
- ### C++ API
329
-
330
- Aiming simplicity, µTest++ provides only a very limited number of primitives
331
- used to check expectations and assumptions.
332
-
333
- #### Expectations
334
-
335
- Expectations are checks whose results are counted and do not
336
- break the test (as opposed to assumptions, which abort the test).
337
-
338
- ```C++
339
- template <class Expr_T, type_traits::requires_t<....>>
340
- bool expect(const Expr_T& expr);
341
- ```
342
-
343
- The template matches only expressions that evaluate to
344
- a boolean or use custom comparators/operators derived from an
345
- internal `detail::op` type.
346
-
347
- For generic checks performed outside the testing framework, the results can
348
- be reported with `expect(true)` or `expect(false)` (see the example testing
349
- multiple exceptions below).
350
-
351
- #### Assumptions
352
-
353
- Assumptions are checks that abort the test if the results are false.
354
-
355
- ```C++
356
- template <class Expr_T, type_traits::requires_t<....>>
357
- bool assume(const Expr_T& expr);
358
- ```
359
-
360
- Similarly, the template matches only expressions that evaluate to
361
- a boolean and use custom comparators/operators derived from a
362
- internal `detail::op` type.
363
-
364
- #### Function comparators
365
-
366
- Expectations and assumptions can test any expression evaluating to a
367
- boolean value, but in order to nicely report the difference between expected
368
- and actual values in failed
369
- conditions, the following generic comparators are available:
370
-
371
- ```c++
372
- template <class Lhs_T, class Rhs_T>
373
- auto eq(const Lhs_T& lhs, const Rhs_T& rhs);
374
-
375
- template <class Lhs_T, class Rhs_T>
376
- auto ne(const Lhs_T& lhs, const Rhs_T& rhs);
377
-
378
- template <class Lhs_T, class Rhs_T>
379
- auto lt(const Lhs_T& lhs, const Rhs_T& rhs);
380
-
381
- template <class Lhs_T, class Rhs_T>
382
- auto le(const Lhs_T& lhs, const Rhs_T& rhs);
383
-
384
- template <class Lhs_T, class Rhs_T>
385
- auto gt(const Lhs_T& lhs, const Rhs_T& rhs);
386
-
387
- template <class Lhs_T, class Rhs_T>
388
- auto ge(const Lhs_T& lhs, const Rhs_T& rhs);
389
- ```
390
-
391
- Similar templates are defined for pointer comparators.
392
-
393
- Examples:
394
-
395
- ```c++
396
- expect (eq (compute_answer (), 42)) << "answer is 42";
397
- expect (ne (compute_answer (), 43)) << "answer is not 43";
398
- expect (lt (compute_answer (), 43)) << "answer is < 43";
399
- expect (le (compute_answer (), 43)) << "answer is <= 42";
400
- expect (gt (compute_answer (), 41)) << "answer is > 43";
401
- expect (ge (compute_answer (), 42)) << "answer is >= 42";
402
-
403
- expect (compute_condition ()) << "condition is true";
404
- ```
405
-
406
- When such comparator functions are used, failed checks also display the
407
- actual values compared during the test; for example:
408
-
409
- ```console
410
- Check failed comparisons
411
- ✗ actual != 42 FAILED (unit-test.cpp:286, 42 != 42)
412
- ✗ FAILED (unit-test.cpp:307, 42 != 42)
413
- ✗ 42 != 42_i FAILED (unit-test.cpp:310, 42 != 42)
414
- ✗ (actual == 42) and (actual != 42.0) FAILED (unit-test.cpp:781, (42 == 42 and 42.000000 != 42.000000))
415
- ```
416
-
417
- ### Logical function operators
418
-
419
- Complex expressions can be checked in a single line, using the logical
420
- `_and()`, `_or()` and `_not()` functions. The names are prefixed with
421
- underscore since
422
- `and`, `or` and `not` are reserved words in C/C++.
423
-
424
- ```c++
425
- template <class Lhs_T, class Rhs_T>
426
- auto _and (const Lhs_T& lhs, const Rhs_T& rhs);
427
-
428
- template <class Lhs_T, class Rhs_T>
429
- auto _or (const Lhs_T& lhs, const Rhs_T& rhs);
430
-
431
- template <class Expr_T>
432
- auto _not (const Expr_T& expr);
433
- ```
434
-
435
- Examples:
436
-
437
- ```c++
438
- expect(_and (eq (compute_answer (), 42), eq (compute_float (), 42.0)));
439
- ```
440
-
441
- A slightly more readable syntax is available with custom operators,
442
- as shown below.
443
-
444
- #### Comparing strings
445
-
446
- In C/C++, plain strings are actually pointers to characters, and simply
447
- comparing them does not compare the content but the memory addresses.
448
-
449
- For string comparisons to compare the content, use `string_view` objects:
450
-
451
- ```c++
452
- #include <string_view>
453
- using namespace std::literals; // For the "sv" literal.
454
- // ...
455
-
456
- expect (eq (std::string_view{ compute_ultimate_answer () }, "forty-two"sv))
457
- << "ultimate_answer is 'forty-two'";
458
- ```
459
-
460
- #### Comparing containers
461
-
462
- Containers can be compared for equality. The comparison
463
- is done by iterating and comparing each member.
464
-
465
- ```c++
466
- expect (eq (std::vector<int>{ 1, 2 }, std::vector<int>{ 1, 2 }))
467
- << "vector{ 1, 2 } eq vector{ 1, 2 }";
468
-
469
- expect (ne (std::vector<int>{ 1, 2, 3 }, std::vector<int>{ 1, 2, 4 })
470
- << "vector{ 1, 2, 3 } ne vector{ 1, 2, 4 }";
471
- ```
472
-
473
- #### Operators
474
-
475
- As in most other C++ test frameworks, it is
476
- also possible to overload the `==`, `!=`, `<`, `>`, `<=`, `>=` operators.
477
-
478
- To avoid possible interferences with other operators
479
- defined by the application, these operators match only for operands of
480
- specific types and are located in a separate namespace
481
- (`micro_test_plus::operators`); when applied to regular values, the
482
- standard operands are used; the comparisons are performed properly,
483
- but in case of failures the actual values are not shown.
484
-
485
- The following operators match only operands derived from the local
486
- `detail::op` type, which can be enforced for constant values by using the
487
- provided literals (like `1_i`) or, for dynamic values, by using the
488
- provided casts (like `_i {expression}`, which are actually the
489
- constructors of the internal classes):
490
-
491
- ```c++
492
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
493
- bool operator== (const Lhs_T& lhs, const Rhs_T& rhs);
494
-
495
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
496
- bool operator!= (const Lhs_T& lhs, const Rhs_T& rhs);
497
-
498
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
499
- bool operator< (const Lhs_T& lhs, const Rhs_T& rhs);
500
-
501
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
502
- bool operator<= (const Lhs_T& lhs, const Rhs_T& rhs);
503
-
504
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
505
- bool operator> (const Lhs_T& lhs, const Rhs_T& rhs);
506
-
507
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
508
- bool operator>= (const Lhs_T& lhs, const Rhs_T& rhs);
509
- ```
510
-
511
- Examples:
512
-
513
- ```c++
514
- test_case ("Operators", [] {
515
- using namespace micro_test_plus::operators;
516
- using namespace micro_test_plus::literals;
517
-
518
- expect (compute_answer () == 42_i) << "answer is 42 (with literal)";
519
- expect (_i {compute_answer ()} == 42) << "answer is 42 (with cast)";
520
- expect (compute_answer () != 43_i) << "answer is not 43";
521
- expect (compute_answer () < 43_i) << "answer is < 43";
522
- expect (compute_answer () <= 43_i) << "answer is <= 42";
523
- expect (compute_answer () > 41_i) << "answer is > 43";
524
- expect (compute_answer () >= 42_i) << "answer is >= 42";
525
- });
526
- ```
527
-
528
- In addition, equality operators are also provided for `string_view`
529
- objects and for iterable containers:
530
-
531
- ```c++
532
- bool operator== (std::string_view lhs, std::string_view rhs);
533
- bool operator!= (std::string_view lhs, std::string_view rhs);
534
-
535
- template <class T, type_traits::requires_t<type_traits::is_container_v<T>>>
536
- bool operator== (T&& lhs, T&& rhs);
537
-
538
- template <class T, type_traits::requires_t<type_traits::is_container_v<T>>>
539
- bool operator!= (T&& lhs, T&& rhs);
540
- ```
541
-
542
- Examples:
543
-
544
- ```c++
545
- #include <string_view>
546
- using namespace std::literals; // For the "sv" literal.
547
- // ...
548
-
549
- test_case ("Operators", [] {
550
- using namespace micro_test_plus::operators;
551
-
552
- expect (std::string_view{ compute_ultimate_answer () } == "forty-two"sv)
553
- << "ultimate answer == 'forty-two'";
554
-
555
- expect (std::vector<int>{ 1, 2 } == std::vector<int>{ 1, 2 })
556
- << "vector{ 1, 2 } == vector{ 1, 2 }";
557
-
558
- expect (std::vector<int>{ 1, 2, 3 } != std::vector<int>{ 1, 2, 4 })
559
- << "vector{ 1, 2, 3 } != vector{ 1, 2, 4 }";
560
- });
561
- ```
562
-
563
- #### Logical operators
564
-
565
- Similarly, logical operators are defined:
566
-
567
- ```c++
568
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
569
- bool operator and (const Lhs_T& lhs, const Rhs_T& rhs);
570
-
571
- template <class Lhs_T, class Rhs_T, type_traits::requires_t<....>>
572
- bool operator or (const Lhs_T& lhs, const Rhs_T& rhs);
573
-
574
- template <class T, type_traits::requires_t<....>>
575
- bool operator not (const T& t);
576
- ```
577
-
578
- They can be used in exactly the same way as standard operators, but the
579
- additional functionality is enabled only when matching the typed operands.
580
-
581
- Examples:
582
-
583
- ```c++
584
- expect (compute_answer () == 42_i && compute_float () == 42.0_f);
585
- ```
586
-
587
- #### Literals and wrappers
588
-
589
- For converting constants to recognised typed operands, the following
590
- literal operators are available in the separate namespace `literals`:
591
-
592
- ```c++
593
- namespace literals {
594
- auto operator""_i (); // int
595
- auto operator""_s (); // short
596
- auto operator""_c (); // char
597
- auto operator""_sc () // signed char
598
- auto operator""_l (); // long
599
- auto operator""_ll (); // long long
600
- auto operator""_u (); // unsigned
601
- auto operator""_uc (); // unsigned char
602
- auto operator""_us (); // unsigned short
603
- auto operator""_ul (); // unsigned long
604
- auto operator""_ull (); // unsigned long long
605
- auto operator""_i8 (); // int8_t
606
- auto operator""_i16 (); // int16_t
607
- auto operator""_i32 (); // int32_t
608
- auto operator""_i64 (); // int64_t
609
- auto operator""_u8 (); // uint8_t
610
- auto operator""_u16 (); // uint16_t
611
- auto operator""_u32 (); // uint32_t
612
- auto operator""_u64 (); // uint64_t
613
- auto operator""_f (); // float
614
- auto operator""_d (); // double
615
- auto operator""_ld (); // long double
616
- auto operator""_b (); // bool
617
- }
618
- ```
619
-
620
- Similarly, for dynamic values, there are wrappers that convert them to
621
- recognised types:
622
-
623
- ```c++
624
- using _b = type_traits::value<bool>;
625
- using _c = type_traits::value<char>;
626
- using _sc = type_traits::value<signed char>;
627
- using _s = type_traits::value<short>;
628
- using _i = type_traits::value<int>;
629
- using _l = type_traits::value<long>;
630
- using _ll = type_traits::value<long long>;
631
- using _u = type_traits::value<unsigned>;
632
- using _uc = type_traits::value<unsigned char>;
633
- using _us = type_traits::value<unsigned short>;
634
- using _ul = type_traits::value<unsigned long>;
635
- using _ull = type_traits::value<unsigned long long>;
636
- using _i8 = type_traits::value<std::int8_t>;
637
- using _i16 = type_traits::value<std::int16_t>;
638
- using _i32 = type_traits::value<std::int32_t>;
639
- using _i64 = type_traits::value<std::int64_t>;
640
- using _u8 = type_traits::value<std::uint8_t>;
641
- using _u16 = type_traits::value<std::uint16_t>;
642
- using _u32 = type_traits::value<std::uint32_t>;
643
- using _u64 = type_traits::value<std::uint64_t>;
644
- using _f = type_traits::value<float>;
645
- using _d = type_traits::value<double>;
646
- using _ld = type_traits::value<long double>;
647
-
648
- // Template for wrapping any other type.
649
- template <class T>
650
- struct _t : type_traits::value<T>
651
- {
652
- constexpr explicit _t (const T& t) : type_traits::value<T>{ t }
653
- {
654
- }
655
- };
656
- ```
657
-
658
- Examples:
659
-
660
- ```c++
661
- expect (_i {answer} == 42_i);
662
- expect (_f {expression} == 42_f);
663
- ```
664
-
665
- #### Function comparators vs. operators & literals
666
-
667
- Which to use, functions like `eq()` or the
668
- overloaded operators? A very good question!
669
-
670
- Functions guarantee that the nice feature of showing the actual values
671
- when expectations fail is always available. Also the syntax is more on the
672
- traditional side, and for some it may look simpler and easier to read.
673
-
674
- Operators are generally easier to recognise than function calls,
675
- but require the hack with the type wrappers and literals to enforce the
676
- types, otherwise the actual values will not be displayed when the
677
- expectations fail.
678
-
679
- Both syntaxes are functional, and, once the differences understood,
680
- the issue is a matter of personal preferences.
681
-
682
- For example, the µOS++ projects favour explicit comparator functions.
683
-
684
- #### Explicit namespace
685
-
686
- If for any reasons, the definitions in the `micro_test_plus` namespace
687
- interfere with application definitions, it is recommended to
688
- use the comparator functions, which can be more easily invoked
689
- with explicit namespaces, possibly aliased to shorter names.
690
-
691
- Example:
692
-
693
- ```c++
694
- {
695
- namespace mt = micro_os_plus::micro_test_plus;
696
-
697
- mt::test_case ("Check answer", [] {
698
- mt::expect (mt::eq (compute_answer (), 42)) << "answer is 42";
699
- });
700
- }
701
- ```
702
-
703
- #### Exceptions
704
-
705
- A C++ testing framework must be able to check if an expression
706
- (usually a function call), throws or not an exception.
707
-
708
- The following function templates allow to check various exceptions related
709
- conditions:
710
-
711
- ```C++
712
- // Check for any exception.
713
- template <class Callable_T>
714
- auto throws (const Callable_T& expr);
715
-
716
- // Check for a specific exception.
717
- template <class Exception_T, class Callable_T>
718
- auto throws (const Callable_T& expr);
719
-
720
- // Check for no exception at all.
721
- template <class Callable_T>
722
- auto nothrow (const Callable_T& expr);
723
- ```
724
-
725
- Examples:
726
-
727
- ```c++
728
- expect (throws ([] { exercise_throw (true); })) << "exception thrown";
729
-
730
- expect (throws<std::runtime_error> ([] { throw std::runtime_error{ "" }; }))
731
- << "std::runtime_error thrown";
732
-
733
- expect (nothrow ([] { exercise_throw (false); })) << "exception not thrown";
734
- ```
735
-
736
- If a more elaborate logic is required, for example for expecting multiple
737
- exceptions, use an explicit `try` with multiple `catch` statements and
738
- report the results with `expect(true)` or `expect(false)`.
739
-
740
- ```c++
741
- try
742
- {
743
- compute_answer ();
744
- }
745
- catch (const std::overflow_error& e)
746
- {
747
- expect (true) << "std::overflow_error thrown";
748
- }
749
- catch (const std::runtime_error& e)
750
- {
751
- expect (true) << "std::runtime_error thrown";
752
- }
753
- catch (...)
754
- {
755
- expect (false) << "known exception thrown";
756
- }
757
- ```
758
-
759
- #### Test cases
760
-
761
- Test cases group several checks done in the same environment.
762
-
763
- There can be any number of test cases, and each test case is performed
764
- by invoking
765
- a function, parametrised with a name, a callable (usually a lambda),
766
- and optional arguments:
767
-
768
- ```C++
769
- template <typename Callable_T, typename... Args_T>
770
- void test_case (const char* name, Callable_T&& func, Args_T&&... arguments);
771
- ```
772
-
773
- Examples:
774
-
775
- ```c++
776
- using namespace micro_os_plus::micro_test_plus;
777
-
778
- test_case ("Check various conditions", [] {
779
- expect (eq (compute_answer (), 42)) << "answer eq 42";
780
- expect (ne (compute_answer (), 43)) << "answer ne 43";
781
- });
782
-
783
- test_case ("Check various conditions with operators", [] {
784
- using namespace micro_os_plus::micro_test_plus::operators;
785
- using namespace micro_os_plus::micro_test_plus::literals;
786
-
787
- expect (compute_answer () == 42_i) << "answer == 42";
788
- expect (compute_answer () != 43_i) << "answer != 43";
789
- });
790
- ```
791
-
792
- #### Test runner initialization
793
-
794
- The test runner is initialised with the process arguments and a
795
- name, which is used for the default test suite:
796
-
797
- ```C++
798
- void initialize (int argc, char* argv[], const char* name = "Main");
799
- ```
800
-
801
- The arguments can be used for controlling the verbosity level.
802
-
803
- #### Return the test result
804
-
805
- The final test result that must be returned to the system
806
- (0 for pass, 1 for fail), can be obtained with:
807
-
808
- ```C++
809
- int exit_code (void);
810
- ```
811
-
812
- This call also triggers the execution of all global test suites.
813
-
814
- For examples, see before.
815
-
816
- #### Test suites
817
-
818
- Test suites are named sequences of test cases.
819
-
820
- The test cases defined in `main()` are considered to be part of
821
- the default (or main) test suite, and are executed immediately
822
- when invoked.
823
-
824
- For complex applications there can be multiple test
825
- suites, usually in separate source files.
826
-
827
- In order to make self-registration possible, test suites are classes,
828
- constructed with a name, a callable (usually a lambda
829
- which chains the execution of the test cases) and optional
830
- arguments:
831
-
832
- ```C++
833
- class test_suite : public test_suite_base
834
- {
835
- public:
836
- template <typename Callable_T, typename... Args_T>
837
- test_suite (const char* name, Callable_T&& callable,
838
- Args_T&&... arguments);
839
- // ...
840
- }
841
- ```
842
-
843
- It is recommended to instantiate the test suites as static objects.
844
-
845
- The self-registration is done in the constructor.
846
- Test suites defined in different compilation units can be executed in any
847
- order (since the order in which the
848
- static constructors are invoked is not specified);
849
- thus there should be no dependencies between test suites.
850
-
851
- The registered test suites are executed when the function
852
- `exit_code()` is invoked.
853
-
854
- Examples:
855
-
856
- ```c++
857
- // Test suite with generic parameters.
858
- static void
859
- test_suite_args (int ic, int iv, int& ir, int* ip1, int* ip2)
860
- {
861
- using namespace micro_os_plus::micro_test_plus;
862
-
863
- test_case ("args", [&] {
864
- expect (eq (ic, 42)) << "ic is 42";
865
- expect (eq (iv, 43)) << "iv is 43";
866
- expect (eq (ir, 44)) << "ir is 44";
867
- expect (eq (*ip1, 45)) << "*ip1 is 45";
868
- expect (eq (*ip2, 46)) << "*ip2 is 46";
869
- });
870
- }
871
-
872
- static int in = 43;
873
- static int in44 = 44;
874
- static int& ir = in44;
875
- static int in45 = 45;
876
- static int in46 = 46;
877
- static int* ip2 = &in46;
878
-
879
- static micro_os_plus::micro_test_plus::test_suite ts_args
880
- = { "Args", test_suite_args, 42, in, ir, &in45, ip2 };
881
- ```
882
-
883
- #### Utility functions
884
-
885
- For tests comparing strings, in addition to exact matches, it is also possible
886
- to check matches with patterns like `*` (for any characters) and `?` (for a
887
- single character):
888
-
889
- ```c++
890
- namespace utility {
891
- bool is_match (std::string_view input, std::string_view pattern);
892
- }
893
- ```
894
-
895
- Examples:
896
-
897
- ```c++
898
- expect (utility::is_match ("abc", "a?c")) << "abc matches a?c";
899
- expect (utility::is_match ("abc", "a*c")) << "abc matches a*c";
900
- ```
901
-
902
- Also for tests handling strings, the following function template allows to
903
- split a string into a vector of substrings, using a delimiter:
904
-
905
- ```c++
906
- namespace utility {
907
- template <class T, class Delim_T>
908
- auto split (T input, Delim_T delim) -> std::vector<T>;
909
- }
910
- ```
911
-
912
- Example:
913
-
914
- ```c++
915
- expect (std::vector<std::string_view>{ "a", "b" }
916
- == utility::split<std::string_view> ("a.b", "."))
917
- << "a.b splits into [a,b]";
918
- ```
919
-
920
- #### Custom types
921
-
922
- It is possible to extend the comparators with templates matching custom
923
- types, but this is a non-trivial task and requires a good knowledge of
924
- C++.
925
-
926
- TODO: add a test to show how to do this.
927
-
928
- ### Command line options
929
-
930
- #### Verbosity
931
-
932
- By default, the test reporter shows detailed results only for the failed
933
- test cases; successful test cases are shown as a single line with
934
- the total counts of passed/failed checks.
935
-
936
- To control the verbosity, use one of the following command line options:
937
-
938
- - `--verbose` - show all expectations, regardless of the result
939
- - `--quiet` - show only the test suite totals
940
- - `--silent` - suppress all output and only return the exit code
941
-
942
- ### Memory footprint
943
-
944
- The memory footprint of unit tests based on µTest++ is definitely smaller than
945
- that of traditional C++ testing framework, mainly because the `iostream`
946
- library is not used.
947
-
948
- However, the use of templates for implementing the comparators and
949
- operators should be carefully observed for platforms with really
950
- limited amounts of memory, since each pair of different operands
951
- contributes to the program size.
952
-
953
- At the limit, µTest++ can be used
954
- without custom comparators and operators
955
- (only with regular boolean expressions), and still be able to provide
956
- the basic functionality of testing various conditions, but without
957
- the optional features of displaying the actual values compared.
958
-
959
- Also, please note that the memory footprint on `debug` (built with `-O0`),
960
- is significantly larger than on `release`. If necessary, the optimization
961
- for the `debug` build can be increased to `-Og`, to save some memory.
962
-
963
- ### Status
964
-
965
- The **µTest++** source library is fully functional and is used to test the
966
- µOS++ packages.
967
-
968
- ### Build & integration info
969
-
970
- The project is written in C++, and the tests are expected to be
971
- written in C++ too, but the tested code can also be written in plain C.
972
- The framework source code was compiled with GCC 11, clang 12
973
- and arm-none-eabi-gcc 10, and should be warning free.
974
-
975
- To run **on embedded platforms**, the test framework requires a minimum
976
- of support from the system, like writing to the
977
- output stream. Any such environments are acceptable, but for standalone
978
- tests the most common solution is to use **Arm semihosting**.
979
-
980
- To ease the integration of this package into user projects, there
981
- are already made **CMake** and **meson** configuration files (see below).
982
-
983
- For other build systems, consider the following details:
984
-
985
- #### Include folders
986
-
987
- The following folders should be passed to the compiler during the build:
988
-
989
- - `include`
990
-
991
- The header files to be included in user projects are:
992
-
993
- ```c++
994
- #include <micro-os-plus/micro-test-plus.h>
995
- ```
996
-
997
- #### Source files
998
-
999
- The source files to be added to user projects are:
1000
-
1001
- - `src/micro-test-plus.cpp`
1002
- - `src/test-reporter.cpp`
1003
- - `src/test-runner.cpp`
1004
- - `src/test-suite.cpp`
1005
-
1006
- #### Preprocessor definitions
1007
-
1008
- - `MICRO_OS_PLUS_INCLUDE_CONFIG_H` - to include `<micro-os-plus/config.h>`
1009
- - `MICRO_OS_PLUS_TRACE` - to include the trace calls
1010
- - `MICRO_TEST_PLUS_TRACE` - to enable some tracing messages
1011
-
1012
- #### Compiler options
1013
-
1014
- - `-std=c++20` or higher for C++ sources
1015
-
1016
- #### C++ Namespaces
1017
-
1018
- - `micro_os_plus::micro_test_plus`
1019
- - `micro_os_plus::micro_test_plus::operators`
1020
- - `micro_os_plus::micro_test_plus::literals`
1021
- - `micro_os_plus::micro_test_plus::utility`
1022
-
1023
- `micro_os_plus` is the top µOS++ namespace, and `micro_test_plus` is the
1024
- µTest++ namespace.
1025
-
1026
- The `operators` namespace defines the custom operators, and the `literals`
1027
- namespace defines the literals (like `1_i`);
1028
-
1029
- #### C++ Classes
1030
-
1031
- - `micro_os_plus::micro_test_plus::test_suite`
1032
-
1033
- #### Dependencies
1034
-
1035
- - none
1036
-
1037
- #### CMake
1038
-
1039
- To integrate the µTest++ source library into a CMake application,
1040
- add this folder to the build:
1041
-
1042
- ```cmake
1043
- add_subdirectory("xpacks/micro-os-plus-micro-test-plus")`
1044
- ```
1045
-
1046
- The result is an interface library that can be added as an application
1047
- dependency with:
1048
-
1049
- ```cmake
1050
- target_link_libraries(your-target PRIVATE
1051
-
1052
- micro-os-plus::micro-test-plus
1053
- )
1054
- ```
1055
-
1056
- #### meson
1057
-
1058
- To integrate the µTest++ source library into a meson application,
1059
- add this folder to the build:
1060
-
1061
- ```meson
1062
- subdir('xpacks/micro-os-plus-micro-test-plus')
1063
- ```
1064
-
1065
- The result is a dependency object that can be added
1066
- to an application with:
1067
-
1068
- ```meson
1069
- exe = executable(
1070
- your-target,
1071
- link_with: [
1072
- # Nothing, not static.
1073
- ],
1074
- dependencies: [
1075
- micro_os_plus_micro_test_plus_dependency,
1076
- ]
1077
- )
1078
- ```
1079
-
1080
- ### Examples
1081
-
1082
- An example showing how to use the µTest++ framework is
1083
- available in
1084
- [tests/src/sample-test.cpp](tests/src/sample-test.cpp).
1085
-
1086
- Here are some excerpts:
1087
-
1088
- ```c++
1089
- #include <micro-os-plus/micro-test-plus.h>
1090
-
1091
- // ----------------------------------------------------------------------------
1092
-
1093
- // ...
1094
-
1095
- // The test suite.
1096
- int
1097
- main (int argc, char* argv[])
1098
- {
1099
- using namespace micro_os_plus::micro_test_plus;
1100
-
1101
- initialize (argc, argv, "Sample");
1102
-
1103
- test_case ("Check various conditions", [] {
1104
- expect (eq (compute_answer (), 42)) << "answer is 42";
1105
- expect (ne (compute_answer (), 43)) << "answer is not 43";
1106
- expect (compute_condition ()) << "condition() is true";
1107
- });
1108
-
1109
- test_case ("Check various conditions with operators", [] {
1110
- using namespace micro_test_plus::operators;
1111
- using namespace micro_test_plus::literals;
1112
-
1113
- expect (compute_answer () == 42_i) << "answer == 42 (with literal)";
1114
- expect (_i {compute_answer ()} == 42) << "answer == 42 (with cast)";
1115
- expect (compute_answer () != 43_i) << "answer != 43";
1116
- });
1117
-
1118
- test_case ("Check parametrised", [] {
1119
- auto f = [] (int i) { return i + 42; };
1120
- expect (eq (f (1), 43)) << "lambda == 43";
1121
- });
1122
-
1123
- #if defined(__EXCEPTIONS)
1124
-
1125
- test_case ("Check exceptions", [] {
1126
- auto exercise_throw = [] { throw std::runtime_error{ "" }; }
1127
- expect (throws<std::runtime_error> (exercise_throw))
1128
- << "std::runtime_error thrown";
1129
- });
1130
-
1131
- #endif // defined(__EXCEPTIONS)
1132
-
1133
- return exit_code ();
1134
- }
1135
-
1136
- // ----------------------------------------------------------------------------
1137
- ```
1138
-
1139
- The output of running such a test looks like:
1140
-
1141
- ```console
1142
- $ cd micro-test-plus-xpack.git
1143
- $ xpm install-all
1144
- ...
1145
- $ xpm run test-native
1146
- ...
1147
- > Executing task: xpm run test --config native-cmake-debug <
1148
-
1149
- > cd build/native-cmake-release && ctest -V
1150
- ...
1151
- Start 1: sample-test
1152
-
1153
- 1: Test command: /Users/ilg/My\ Files/WKS\ Projects/micro-os-plus.github/xPacks/micro-test-plus-xpack.git/build/native-cmake-release/platform-bin/sample-test "one" "two"
1154
- 1: Test timeout computed to be: 10000000
1155
- 1: Built with clang Apple LLVM 13.0.0 (clang-1300.0.29.30), no FP, with exceptions.
1156
- 1:
1157
- 1: • Sample - test suite started
1158
- 1:
1159
- 1: • Check various conditions - test case started
1160
- 1: ✓ compute_one() == 1
1161
- 1: ✓ compute_aaa() == 'aaa'
1162
- 1: ✓ condition() is true
1163
- 1: ✓ Check various conditions - test case passed (3 checks)
1164
- 1:
1165
- 1: • Check parametrised - test case started
1166
- 1: ✓ lambda == 43
1167
- 1: ✓ Check parametrised - test case passed (1 check)
1168
- 1:
1169
- 1: • Check exceptions - test case started
1170
- 1: ✓ std::runtime_error thrown
1171
- 1: ✓ Check exceptions - test case passed (1 check)
1172
- 1:
1173
- 1: ✓ Sample - test suite passed (5 tests in 3 test cases)
1174
- 1/2 Test #1: sample-test ...................... Passed 0.00 sec
1175
- ...
1176
- ```
1177
-
1178
- ### Known problems
1179
-
1180
- - none
1181
-
1182
- ### TODO
1183
-
1184
- - add code to show how to define custom comparators
1185
- - move documentation to future µOS++ web site
1186
-
1187
- ### Tests
1188
-
1189
- The project is fully tested via GitHub
1190
- [Actions](https://github.com/micro-os-plus/micro-test-plus-xpack/actions/)
1191
- on each push.
1192
-
1193
- The test platforms are **GNU/Linux**, **macOS** and **Windows**; native tests
1194
- are compiled with GCC and clang; tests for embedded platforms are compiled
1195
- with **arm-none-eabi-gcc** and run via **QEMU**.
1196
-
1197
- There are two sets of tests, one that runs on every push, with a
1198
- limited number of tests, and a set that is triggered manually,
1199
- usually before releases, and runs all tests on all supported
1200
- platforms.
1201
-
1202
- The full set can be run manually with the following commands:
1203
-
1204
- ```sh
1205
- cd ~Work/micro-test-plus-xpack.git
1206
-
1207
- xpm run install-all
1208
- xpm run test-all
1209
- ```
1210
-
1211
- ## Change log - incompatible changes
1212
-
1213
- According to [semver](https://semver.org) rules:
1214
-
1215
- > Major version X (X.y.z | X > 0) MUST be incremented if any
1216
- backwards incompatible changes are introduced to the public API.
1217
-
1218
- The incompatible changes, in reverse chronological order,
1219
- are:
1220
-
1221
- - **v3.x**: major rework, with full set of comparators, exceptions,
1222
- function templates for test cases and class templates for test suites;
1223
- - **v2.3.x**: deprecate `run_test_case(func, name)` in favour o
1224
- `run_test_case(name, func)`, to prepare for variadic templates
1225
- - **v2.x**: the C++ namespace was renamed from `os` to `micro_os_plus`;
1226
- - **v1.x**: the code was extracted from the mono-repo µOS++ project.
1227
-
1228
- ## Credits
1229
-
1230
- Many thanks to the [Boost UT](https://github.com/boost-ext/ut) project
1231
- for the inspiration and for major parts of the code.
16
+ For information on how to integrate and use this library, please refer to the
17
+ [project documentation](https://micro-os-plus.github.io/micro-test-plus-xpack/) web site.
1232
18
 
1233
19
  ## License
1234
20
 
1235
- The original content is released under the
1236
- [MIT License](https://opensource.org/licenses/MIT/),
21
+ Unless otherwise stated, the content is released under the terms of the
22
+ [MIT License](https://opensource.org/licenses/mit/),
1237
23
  with all rights reserved to
1238
- [Liviu Ionescu](https://github.com/ilg-ul/).
24
+ [Liviu Ionescu](https://github.com/ilg-ul).
1239
25
 
1240
26
  The code from Boost UT is released under the terms of the
1241
27
  [Boost Version 1.0 Software License](https://www.boost.org/LICENSE_1_0.txt).