diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3fe51d2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,182 @@ +{ + "[bat]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 4, + }, + "[c]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[cmake]": { + "editor.insertSpaces": false, + "editor.tabSize": 4, + }, + "[cpp]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[json]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.insertSpaces": true, + "editor.rulers": [ 51, 60, 61, 76 ], + "editor.tabSize": 4, + }, + "[ruby]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[shellscript]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 2, + }, + "[toml]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "cmake.configureOnOpen": false, + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.renderWhitespace": "all", + "editor.rulers": [ 76 ], + "editor.tabSize": 2, + "files.associations": { + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_03": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__memory": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "__verbose_abort": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "console_functions.h": "c", + "corecrt.h": "c", + "crtdefs.h": "c", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "execution": "cpp", + "fcntl.h": "c", + "format": "cpp", + "forward_list": "cpp", + "functional": "cpp", + "implicit_link.h": "c", + "initializer_list": "cpp", + "io.h": "c", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "semaphore": "cpp", + "set": "cpp", + "setenv.h": "c", + "shwild.h": "c", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stdio.h": "c", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "terse-api.h": "c", + "text_encoding": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "uio.h": "c", + "unixem.h": "c", + "unordered_map": "cpp", + "util.h": "c", + "utility": "cpp", + "variant": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtests.internal.string.c": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, +} diff --git a/CHANGES.md b/CHANGES.md index 1849ef6..f967f0b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,14 @@ # Pantheios.Extras.AtExit - Changes +## 0.1.3 - 31st August 2026 + +* Retargeted the current line from **0.1.2-alpha1** to **0.1.3**; +* Asserted **`pantheios_extras_atexit_init()`** `reserved0` / `reserved1` as `NULL` / `0`; +* Example **example.c.1** checks **`add`** return values; unit tests cover **`add`** without **`init`**, **`add`** after **`uninit`**, and version macros; +* Added a **README.md** rationale for why libc `atexit()` is insufficient and what this library is for; + + ## 0.1.2-alpha1 - 21st August 2026 * Modernised library version macros to computed `PANTHEIOS_EXTRAS_ATEXIT_VER` (`VER_MAJOR` / `VER_MINOR` / `VER_PATCH` / `VER_ALPHABETA`, with `VER_REVISION` alias) targeting **0.1.2-alpha1**; diff --git a/NEWS.md b/NEWS.md index 6ded513..1311512 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ | Date | News Item | | ---------------- | -------------------------------------------------------------------------------- | +| 31st August 2026 | Pantheios.Extras.AtExit 0.1.3 | | 21st August 2026 | Pantheios.Extras.AtExit 0.1.2-alpha1 | | 16th August 2026 | Pantheios.Extras.AtExit 0.1.1 recovered and released | diff --git a/README.md b/README.md index 80d9f03..c5560e6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Standalone C library that registers multiple `atexit`-style callbacks (function ## Table of Contents - [Introduction](#introduction) + - [Why at-exit functionality](#why-at-exit-functionality) - [Dependencies](#dependencies) - [Installation](#installation) - [Components](#components) @@ -28,13 +29,26 @@ Standalone C library that registers multiple `atexit`-style callbacks (function ## Introduction -**Pantheios.Extras.AtExit** is a small compiled **C** library in the [Pantheios](http://pantheios.org/) extras namespace. It is **not** a Pantheios (or STLSoft) dependency: the core target needs only the C standard library. +**Pantheios.Extras.AtExit** is a small compiled **C** library in the [Pantheios](http://pantheios.org/) extras namespace. Unlike most/all of the other Pantheios Extras libraries, it is **not** a Pantheios (or STLSoft) dependency: the core target needs only the C standard library. -It extends libc `atexit()` with an explicit callback list so client code can register many `(function, void* param)` pairs that are invoked in **LIFO** order — either when `pantheios_extras_atexit_uninit()` drains the list, or later via the single libc `atexit` hook registered at init. +Its raison d'être is to provide a richer alternative to the standard C library's `atexit()`, with an explicit callback list so client code can register many `(function, void* param)` pairs that are invoked in **LIFO** order — either when `pantheios_extras_atexit_uninit()` drains the list, or later via the single libc `atexit` hook registered at init. Importantly. each callback is also accompanied by a `void*` parameter that is given back to the callback when it is invoked, thereby enabling stateful cleanup. `pantheios_extras_atexit_init()` must be called at most once per process. Later calls fail (`EBUSY`) even after `uninit()`, because libc `atexit` handlers cannot be unregistered. After a drain, the registered hook is a no-op. +### Why at-exit functionality + +C programs often need last-chance cleanup: flushing diagnostics, releasing process-wide resources, or tearing down library state that has no natural owner once `main` has returned. libc `atexit()` is the portable hook for that, but it is a poor *unit of currency* for libraries and layered applications: + +* Handlers are `void (*)(void)`. Any context must live in globals, which couples unrelated components and makes reuse harder; +* The number of handlers is small and shared (`ATEXIT_MAX`, often 32). A library that registers one slot per subsystem, sink, or module can exhaust the table for the rest of the process; +* There is no unregister. A component that is done *before* process exit cannot drop its handler, and a second registration is another scarce slot; + +**Pantheios.Extras.AtExit** exists so that many callers can each register `(function, void* param)` without consuming a libc slot per callback. The library takes **one** `atexit` registration at `init` and maintains its own LIFO list. `uninit` drains that list early when the process is still in a well-defined state; if `uninit` is not used, the same list runs from the libc hook at exit. + +That is the same protocol as other **Pantheios.Extras** helpers: keep the core logging library free of this concern, and give C clients a small, stdlib-only facility instead of rolling an ad-hoc static list in every program. + + ### Dependencies | Component | Implemented in | Use in | Dependencies | diff --git a/TODO.md b/TODO.md index 763afa2..65503d5 100644 --- a/TODO.md +++ b/TODO.md @@ -13,7 +13,7 @@ ### Medium * [ ] Serialise **`init`**: `s_initialised` is a plain `int` and `init` is not under the lock, so two threads can register two `atexit` hooks; -* [ ] Align **`reserved0`** / **`reserved1`**: header says they must be `NULL` / `0`, but the implementation ignores them — `assert` or drop the requirement; +* [x] ~~~Align **`reserved0`** / **`reserved1`**: header says they must be `NULL` / `0`, but the implementation ignores them — `assert` or drop the requirement;~~~ ✅ * [ ] Stop treating **`atexit()`** failure as an `errno` / **`strerror()`** code; `EBUSY` / `ENOMEM` are errno values, `atexit` failure often is not; @@ -21,8 +21,8 @@ * [ ] Document **`add` without `init`**: the list grows, but process exit will not drain it unless **`uninit`** is called; * [ ] Initialise C11 `atomic_int s_mx` with **`ATOMIC_VAR_INIT(0)`** if compilers warn on `= 0`; -* [ ] Tests: **`add`** without **`init`** then **`uninit`**; **`add`** after **`uninit`**; version-macro unit test; keep process-exit coverage as scratch (or one automated case); -* [ ] Example: check **`add`** return values; +* [x] ~~~Tests: **`add`** without **`init`** then **`uninit`**; **`add`** after **`uninit`**; version-macro unit test; keep process-exit coverage as scratch (or one automated case);~~~ ✅ +* [x] ~~~Example: check **`add`** return values;~~~ ✅ ### Enhancements diff --git a/examples/c/example.c.1/example.c.1.c b/examples/c/example.c.1/example.c.1.c index 3b43bd0..78d173d 100644 --- a/examples/c/example.c.1/example.c.1.c +++ b/examples/c/example.c.1/example.c.1.c @@ -5,7 +5,7 @@ * callbacks (LIFO) and drain them via uninit(). * * Created: 30th December 2011 - * Updated: 16th August 2026 + * Updated: 31st August 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -30,6 +30,36 @@ fn2(void* param) } +static int +add( + void (*pfn)(void* param) +, void* param +) +{ + int const r = pantheios_extras_atexit_add(pfn, param); + + if (0 != r) + { +#ifdef _MSC_VER + char error_message[256]; + + strerror_s(error_message, sizeof(error_message), r); +#else + char const* error_message = strerror(r); +#endif + + fprintf( + stderr + , "failed to add Pantheios.Extras.AtExit callback : %s (%d)\n" + , error_message + , r + ); + } + + return r; +} + + int main(void) { @@ -56,10 +86,13 @@ main(void) } /* LIFO: last add is invoked first by uninit() / atexit */ - pantheios_extras_atexit_add(fn1, (void*)1); - pantheios_extras_atexit_add(fn2, (void*)2); - pantheios_extras_atexit_add(fn1, (void*)3); - pantheios_extras_atexit_add(fn2, (void*)4); + if (0 != add(fn1, (void*)1) || + 0 != add(fn2, (void*)2) || + 0 != add(fn1, (void*)3) || + 0 != add(fn2, (void*)4)) + { + return EXIT_FAILURE; + } pantheios_extras_atexit_uninit(); diff --git a/include/pantheios/extras/atexit/atexit.h b/include/pantheios/extras/atexit/atexit.h index d6dd9e4..ce115ce 100644 --- a/include/pantheios/extras/atexit/atexit.h +++ b/include/pantheios/extras/atexit/atexit.h @@ -4,7 +4,7 @@ * Purpose: Header file for Pantheios.Extras.AtExit. * * Created: 30th December 2011 - * Updated: 21st August 2026 + * Updated: 31st August 2026 * * Home: http://www.pantheios.org/ * @@ -55,8 +55,8 @@ #ifndef PANTHEIOS_DOCUMENTATION_SKIP_SECTION # define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_MAJOR 1 # define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_MINOR 2 -# define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_REVISION 0 -# define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_EDIT 6 +# define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_REVISION 2 +# define PANTHEIOS_EXTRAS_ATEXIT_VER_PANTHEIOS_EXTRAS_ATEXIT_H_ATEXIT_EDIT 8 #endif /* !PANTHEIOS_DOCUMENTATION_SKIP_SECTION */ /** \def PANTHEIOS_EXTRAS_ATEXIT_VER_MAJOR @@ -88,12 +88,13 @@ #ifndef PANTHEIOS_DOCUMENTATION_SKIP_SECTION # define PANTHEIOS_EXTRAS_ATEXIT_VER_0_1_1 0x000101ff # define PANTHEIOS_EXTRAS_ATEXIT_VER_0_1_2_ALPHA_1 0x00010241 +# define PANTHEIOS_EXTRAS_ATEXIT_VER_0_1_3 0x000103ff #endif /* !PANTHEIOS_DOCUMENTATION_SKIP_SECTION */ #define PANTHEIOS_EXTRAS_ATEXIT_VER_MAJOR 0 #define PANTHEIOS_EXTRAS_ATEXIT_VER_MINOR 1 -#define PANTHEIOS_EXTRAS_ATEXIT_VER_PATCH 2 -#define PANTHEIOS_EXTRAS_ATEXIT_VER_ALPHABETA 0x41 +#define PANTHEIOS_EXTRAS_ATEXIT_VER_PATCH 3 +#define PANTHEIOS_EXTRAS_ATEXIT_VER_ALPHABETA 0xFF #define PANTHEIOS_EXTRAS_ATEXIT_VER \ (0\ @@ -131,6 +132,9 @@ extern "C" { * \warning Failure to call this function will mean that no callbacks * registered by pantheios_extras_atexit_add() will be invoked at process * exit (they may still be invoked by pantheios_extras_atexit_uninit()). + * + * \pre (NULL == reserved0) + * \pre (0 == reserved1) */ int pantheios_extras_atexit_init( diff --git a/src/atexit.api.c b/src/atexit.api.c index 6c72c30..6624e74 100644 --- a/src/atexit.api.c +++ b/src/atexit.api.c @@ -55,28 +55,29 @@ * atomics */ -#if defined(_WIN32) +#if 0 +#elif defined(_WIN32) # include typedef LONG pantheios_extras_atexit_atomic_int_t; -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) InterlockedIncrement((p)) -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) InterlockedDecrement((p)) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) InterlockedIncrement((p)) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) InterlockedDecrement((p)) #elif defined(__STDC_NO_ATOMICS__) # if defined(__GNUC__) || defined(__clang__) typedef int pantheios_extras_atexit_atomic_int_t; -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) __sync_add_and_fetch((p), 1) -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) __sync_sub_and_fetch((p), 1) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) __sync_add_and_fetch((p), 1) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) __sync_sub_and_fetch((p), 1) # else # error Pantheios.Extras.AtExit requires C11 atomics, GCC/Clang __sync, or Windows Interlocked # endif #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # include typedef atomic_int pantheios_extras_atexit_atomic_int_t; -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) (atomic_fetch_add((p), 1) + 1) -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) ((void)atomic_fetch_sub((p), 1)) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) (atomic_fetch_add((p), 1) + 1) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) ((void)atomic_fetch_sub((p), 1)) #elif defined(__GNUC__) || defined(__clang__) typedef int pantheios_extras_atexit_atomic_int_t; -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) __sync_add_and_fetch((p), 1) -# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) __sync_sub_and_fetch((p), 1) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_INC_(p) __sync_add_and_fetch((p), 1) +# define PANTHEIOS_EXTRAS_ATEXIT_ATOMIC_DEC_(p) __sync_sub_and_fetch((p), 1) #else # error Pantheios.Extras.AtExit requires C11 atomics, GCC/Clang __sync, or Windows Interlocked #endif @@ -169,6 +170,9 @@ pantheios_extras_atexit_init( { int r; + assert(NULL == reserved0); + assert(0 == reserved1); + ((void)reserved0); ((void)reserved1); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 78d5028..cbcd22d 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(test.unit.atexit.api) +add_subdirectory(test.unit.version) # ############################## end of file ############################# # diff --git a/test/unit/test.unit.atexit.api/test.unit.atexit.api.c b/test/unit/test.unit.atexit.api/test.unit.atexit.api.c index e844c5a..d0dc38f 100644 --- a/test/unit/test.unit.atexit.api/test.unit.atexit.api.c +++ b/test/unit/test.unit.atexit.api/test.unit.atexit.api.c @@ -4,7 +4,7 @@ * Purpose: Unit tests for Pantheios.Extras.AtExit. * * Created: 16th August 2026 - * Updated: 16th August 2026 + * Updated: 21st August 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -23,6 +23,8 @@ static int s_tag1 = 1; static int s_tag2 = 2; static int s_tag3 = 3; static int s_tag7 = 7; +static int s_tag_pre = 11; +static int s_tag_post = 13; static void @@ -37,6 +39,19 @@ record(void* param) } +static void +test_add_without_init_then_uninit(void) +{ + s_ncalls = 0; + + XTESTS_TEST_INTEGER_EQUAL(0, pantheios_extras_atexit_add(record, &s_tag_pre)); + + pantheios_extras_atexit_uninit(); + + XTESTS_TEST_INTEGER_EQUAL(1, s_ncalls); + XTESTS_TEST_INTEGER_EQUAL(11, s_calls[0]); +} + static void test_init_succeeds(void) { @@ -98,6 +113,19 @@ test_init_after_uninit_fails(void) XTESTS_TEST_INTEGER_EQUAL(EBUSY, r); } +static void +test_add_after_uninit_then_uninit_again(void) +{ + s_ncalls = 0; + + XTESTS_TEST_INTEGER_EQUAL(0, pantheios_extras_atexit_add(record, &s_tag_post)); + + pantheios_extras_atexit_uninit(); + + XTESTS_TEST_INTEGER_EQUAL(1, s_ncalls); + XTESTS_TEST_INTEGER_EQUAL(13, s_calls[0]); +} + int main(int argc, char* argv[]) @@ -109,14 +137,18 @@ main(int argc, char* argv[]) if (XTESTS_START_RUNNER("test.unit.atexit.api", verbosity)) { - /* Order matters: first case performs the single process init. - * Later cases add/drain the list; process atexit is then a no-op. + /* Order matters: add-without-init must run before the single + * process init. Later cases add/drain the list; process atexit + * is then a no-op unless add-after-uninit leaves nodes (those + * are drained again before exit). */ + XTESTS_RUN_CASE(test_add_without_init_then_uninit); XTESTS_RUN_CASE(test_init_succeeds); XTESTS_RUN_CASE(test_second_init_fails); XTESTS_RUN_CASE(test_uninit_invokes_lifo); XTESTS_RUN_CASE(test_uninit_is_idempotent_for_callbacks); XTESTS_RUN_CASE(test_init_after_uninit_fails); + XTESTS_RUN_CASE(test_add_after_uninit_then_uninit_again); XTESTS_PRINT_RESULTS(); diff --git a/test/unit/test.unit.version/CMakeLists.txt b/test/unit/test.unit.version/CMakeLists.txt new file mode 100644 index 0000000..af5addc --- /dev/null +++ b/test/unit/test.unit.version/CMakeLists.txt @@ -0,0 +1 @@ +define_automated_test_program(test.unit.version test.unit.version.c) diff --git a/test/unit/test.unit.version/test.unit.version.c b/test/unit/test.unit.version/test.unit.version.c new file mode 100644 index 0000000..10ea1a4 --- /dev/null +++ b/test/unit/test.unit.version/test.unit.version.c @@ -0,0 +1,68 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.unit.version.c + * + * Purpose: Unit tests for Pantheios.Extras.AtExit version macros. + * + * Created: 21st August 2026 + * Updated: 21st August 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include + +#include + + +static void +test_version_components(void) +{ + XTESTS_TEST_INTEGER_EQUAL(0, PANTHEIOS_EXTRAS_ATEXIT_VER_MAJOR); + XTESTS_TEST_INTEGER_EQUAL(1, PANTHEIOS_EXTRAS_ATEXIT_VER_MINOR); + XTESTS_TEST_INTEGER_EQUAL(3, PANTHEIOS_EXTRAS_ATEXIT_VER_PATCH); + XTESTS_TEST_INTEGER_EQUAL(0xFF, PANTHEIOS_EXTRAS_ATEXIT_VER_ALPHABETA); + XTESTS_TEST_INTEGER_EQUAL(PANTHEIOS_EXTRAS_ATEXIT_VER_PATCH, PANTHEIOS_EXTRAS_ATEXIT_VER_REVISION); +} + +static void +test_version_composite(void) +{ + int const computed = + (0 + | ( PANTHEIOS_EXTRAS_ATEXIT_VER_MAJOR << 24 ) + | ( PANTHEIOS_EXTRAS_ATEXIT_VER_MINOR << 16 ) + | ( PANTHEIOS_EXTRAS_ATEXIT_VER_PATCH << 8 ) + | ( PANTHEIOS_EXTRAS_ATEXIT_VER_ALPHABETA << 0 ) + ); + + XTESTS_TEST_INTEGER_EQUAL(computed, PANTHEIOS_EXTRAS_ATEXIT_VER); + XTESTS_TEST_INTEGER_EQUAL(PANTHEIOS_EXTRAS_ATEXIT_VER_0_1_3, PANTHEIOS_EXTRAS_ATEXIT_VER); + XTESTS_TEST_INTEGER_EQUAL(0x000103ff, PANTHEIOS_EXTRAS_ATEXIT_VER); +} + + +int +main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.version", verbosity)) + { + XTESTS_RUN_CASE(test_version_components); + XTESTS_RUN_CASE(test_version_composite); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////// end of file //////////////////////////// */