Expand error status test coverage
All checks were successful
libakerror CI Build / cmake_build (push) Successful in 2m44s
libakerror CI Build / mutation_test (push) Successful in 7m46s

- Added explicit status validation across error handling tests.
- Added lifecycle and slot-leak checks to older tests.
- Improved unhandled-error propagation coverage.
- Added repository guidance and a test runner script.
- Verified all 23 CTest tests pass.

Co-Authored by Codex GPT 5.4
This commit is contained in:
2026-07-29 17:09:45 -04:00
parent 4212ff0b28
commit 4ae1decde2
16 changed files with 135 additions and 9 deletions

View File

@@ -63,26 +63,26 @@ int main(void)
akerr_ErrorContext *r;
r = zero_break(0);
AKERR_CHECK(r != NULL && r->status == AKERR_VALUE);
AKERR_CHECK_STATUS(r, AKERR_VALUE);
r = akerr_release_error(r);
AKERR_CHECK(zero_break(7) == NULL);
r = nonzero_break(7);
AKERR_CHECK(r != NULL && r->status == AKERR_INDEX);
AKERR_CHECK_STATUS(r, AKERR_INDEX);
r = akerr_release_error(r);
AKERR_CHECK(nonzero_break(0) == NULL);
r = always_break();
AKERR_CHECK(r != NULL && r->status == AKERR_IO);
AKERR_CHECK_STATUS(r, AKERR_IO);
r = akerr_release_error(r);
r = zero_return(0);
AKERR_CHECK(r != NULL && r->status == AKERR_KEY);
AKERR_CHECK_STATUS(r, AKERR_KEY);
r = akerr_release_error(r);
AKERR_CHECK(zero_return(7) == NULL);
r = nonzero_return(7);
AKERR_CHECK(r != NULL && r->status == AKERR_TYPE);
AKERR_CHECK_STATUS(r, AKERR_TYPE);
r = akerr_release_error(r);
AKERR_CHECK(nonzero_return(0) == NULL);

View File

@@ -75,6 +75,12 @@ static int __attribute__((unused)) akerr_slots_in_use(void)
} \
} while ( 0 )
#define AKERR_CHECK_STATUS(errctx, expected_status) \
do { \
AKERR_CHECK((errctx) != NULL); \
AKERR_CHECK((errctx)->status == (expected_status)); \
} while ( 0 )
#define AKERR_CHECK_CONTAINS(needle) \
AKERR_CHECK(strstr(akerr_capture_buf, (needle)) != NULL)

View File

@@ -1,4 +1,5 @@
#include "akerror.h"
#include "err_capture.h"
akerr_ErrorContext *func2(void)
{
@@ -31,6 +32,11 @@ int main(void)
} CLEANUP {
} PROCESS(errctx) {
} HANDLE(errctx, AKERR_NULLPOINTER) {
akerr_log_method("Caught exception");
AKERR_CHECK_STATUS(errctx, AKERR_NULLPOINTER);
akerr_log_method("Caught exception");
} FINISH_NORETURN(errctx);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_catch ok\n");
return 0;
}

View File

@@ -1,4 +1,5 @@
#include "akerror.h"
#include "err_capture.h"
int x;
@@ -34,10 +35,15 @@ int main(void)
} CLEANUP {
} PROCESS(errctx) {
} HANDLE(errctx, AKERR_NULLPOINTER) {
AKERR_CHECK_STATUS(errctx, AKERR_NULLPOINTER);
if ( x == 0 ) {
fprintf(stderr, "Cleanup works\n");
return 0;
akerr_log_method("Cleanup works\n");
} else {
return 1;
}
return 1;
} FINISH_NORETURN(errctx);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_cleanup ok\n");
return 0;
}

View File

@@ -37,6 +37,7 @@ int main(void)
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, EACCES) {
AKERR_CHECK_STATUS(e, EACCES);
handled = 1;
} FINISH_NORETURN(e);

View File

@@ -8,6 +8,7 @@
static int specific_fired = 0;
static int default_fired = 0;
static int default_status = 0;
akerr_ErrorContext *boom(void)
{
@@ -28,10 +29,12 @@ int main(void)
specific_fired = 1; /* must NOT run: error is AKERR_TYPE */
} HANDLE_DEFAULT(e) {
default_fired = 1;
default_status = e->status;
} FINISH_NORETURN(e);
AKERR_CHECK(specific_fired == 0);
AKERR_CHECK(default_fired == 1);
AKERR_CHECK(default_status == AKERR_TYPE);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_handle_default ok\n");
return 0;

View File

@@ -9,6 +9,7 @@
static int a_fired = 0;
static int b_fired = 0;
static int c_fired = 0;
static int b_status = 0;
akerr_ErrorContext *boom(void)
{
@@ -29,12 +30,14 @@ int main(void)
a_fired = 1;
} HANDLE(e, AKERR_TYPE) {
b_fired = 1;
b_status = e->status;
} HANDLE(e, AKERR_IO) {
c_fired = 1;
} FINISH_NORETURN(e);
AKERR_CHECK(a_fired == 0);
AKERR_CHECK(b_fired == 1);
AKERR_CHECK(b_status == AKERR_TYPE);
AKERR_CHECK(c_fired == 0);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_handle_dispatch ok\n");

View File

@@ -11,6 +11,8 @@
static int group_fired = 0;
static int other_fired = 0;
static int group_status = 0;
static int other_status = 0;
akerr_ErrorContext *boom(int status)
{
@@ -28,8 +30,10 @@ akerr_ErrorContext *run(int status)
} HANDLE(e, AKERR_KEY)
HANDLE_GROUP(e, AKERR_INDEX) {
group_fired++;
group_status = e->status;
} HANDLE(e, AKERR_IO) {
other_fired++;
other_status = e->status;
} FINISH(e, false);
return e;
}
@@ -40,15 +44,18 @@ int main(void)
run(AKERR_KEY);
AKERR_CHECK(group_fired == 1);
AKERR_CHECK(group_status == AKERR_KEY);
AKERR_CHECK(other_fired == 0);
run(AKERR_INDEX);
AKERR_CHECK(group_fired == 2);
AKERR_CHECK(group_status == AKERR_INDEX);
AKERR_CHECK(other_fired == 0);
run(AKERR_IO);
AKERR_CHECK(group_fired == 2);
AKERR_CHECK(other_fired == 1);
AKERR_CHECK(other_status == AKERR_IO);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_handle_group ok\n");

View File

@@ -35,6 +35,7 @@ int main(void)
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_IO) {
AKERR_CHECK_STATUS(e, AKERR_IO);
handled = 1;
} FINISH_NORETURN(e);

View File

@@ -11,6 +11,8 @@
#define ITERATIONS 100000
static int handled_status = 0;
akerr_ErrorContext *boom(void)
{
PREPARE_ERROR(e);
@@ -31,6 +33,7 @@ akerr_ErrorContext *one_cycle(void)
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_VALUE) {
handled_status = e->status;
} FINISH(e, false);
return e;
}
@@ -42,7 +45,9 @@ int main(void)
AKERR_CHECK(akerr_slots_in_use() == 0);
for ( int iter = 0; iter < ITERATIONS; iter++ ) {
handled_status = 0;
(void)one_cycle();
AKERR_CHECK(handled_status == AKERR_VALUE);
}
AKERR_CHECK(akerr_slots_in_use() == 0);

View File

@@ -10,6 +10,8 @@
* library exit(1)s.
*/
static int handled_status = 0;
akerr_ErrorContext *validate(void)
{
PREPARE_ERROR(e);
@@ -31,6 +33,7 @@ akerr_ErrorContext *one_cycle(void)
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_KEY) {
handled_status = e->status;
} HANDLE(e, AKERR_VALUE) {
} FINISH(e, false);
return e;
@@ -42,7 +45,9 @@ int main(void)
AKERR_CHECK(akerr_slots_in_use() == 0);
for ( int i = 0; i < 32; i++ ) {
handled_status = 0;
(void)one_cycle();
AKERR_CHECK(handled_status == AKERR_KEY);
}
AKERR_CHECK(akerr_slots_in_use() == 0);

View File

@@ -27,6 +27,7 @@ int main(void)
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_VALUE) {
AKERR_CHECK_STATUS(e, AKERR_VALUE);
} FINISH_NORETURN(e);
AKERR_CHECK(e == NULL);

View File

@@ -9,6 +9,7 @@
*/
static int wrong_handler_fired = 0;
static int swallowed_status = 0;
akerr_ErrorContext *boom(void)
{
@@ -24,6 +25,7 @@ akerr_ErrorContext *swallow_it(void)
ATTEMPT {
CATCH(e, boom());
} CLEANUP {
swallowed_status = (e != NULL) ? e->status : 0;
} PROCESS(e) {
} HANDLE(e, AKERR_KEY) {
wrong_handler_fired = 1; /* does not match AKERR_VALUE */
@@ -38,6 +40,7 @@ int main(void)
akerr_ErrorContext *res = swallow_it();
AKERR_CHECK(wrong_handler_fired == 0);
AKERR_CHECK(swallowed_status == AKERR_VALUE);
AKERR_CHECK(res == NULL); /* released even though unhandled */
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_swallow ok\n");

View File

@@ -1,4 +1,10 @@
#include "akerror.h"
#include <stdlib.h>
static void expect_unhandled_nullpointer(akerr_ErrorContext *errctx)
{
exit((errctx != NULL && errctx->status == AKERR_NULLPOINTER) ? 1 : 0);
}
akerr_ErrorContext *func2(void)
{
@@ -25,6 +31,9 @@ akerr_ErrorContext *func1(void)
int main(void)
{
akerr_init();
akerr_handler_unhandled_error = &expect_unhandled_nullpointer;
PREPARE_ERROR(errctx);
ATTEMPT {
CATCH(errctx, func1());