#include "akerror.h" #include "err_capture.h" /* * Releasing an error context back to the pool must reset the state that affects * the next caller. In particular, a handled error must not make a fresh error * look handled when its slot is recycled. */ static int unhandled_calls = 0; static int unhandled_status = 0; static void test_unhandled_handler(akerr_ErrorContext *errctx) { unhandled_calls++; unhandled_status = (errctx != NULL) ? errctx->status : 0; } akerr_ErrorContext *boom(void) { PREPARE_ERROR(e); FAIL_RETURN(e, AKERR_VALUE, "first error is handled"); } int main(void) { akerr_capture_install(); akerr_init(); akerr_handler_unhandled_error = &test_unhandled_handler; /* Raise and fully handle an error; FINISH_NORETURN releases it to the pool. */ PREPARE_ERROR(e); ATTEMPT { CATCH(e, boom()); } CLEANUP { } PROCESS(e) { } HANDLE(e, AKERR_VALUE) { AKERR_CHECK_STATUS(e, AKERR_VALUE); } FINISH_NORETURN(e); AKERR_CHECK(e == NULL); /* A fresh error in the recycled slot must not inherit handled=true. */ PREPARE_ERROR(fresh); ATTEMPT { CATCH(fresh, boom()); } CLEANUP { } PROCESS(fresh) { } FINISH_NORETURN(fresh); AKERR_CHECK(unhandled_calls == 1); AKERR_CHECK(unhandled_status == AKERR_VALUE); AKERR_CHECK(fresh == NULL); /* The next context handed out is the same slot, with recycle state reset. */ akerr_ErrorContext *slot = akerr_next_error(); AKERR_CHECK(slot != NULL); AKERR_CHECK(slot->handled == false); AKERR_CHECK(slot->status == 0); AKERR_CHECK(slot->reported == false); AKERR_CHECK(slot->message[0] == '\0'); AKERR_CHECK(slot->fname[0] == '\0'); AKERR_CHECK(slot->function[0] == '\0'); AKERR_CHECK(slot->stacktracebuf[0] == '\0'); AKERR_CHECK(slot->stacktracebufptr == (char *)&slot->stacktracebuf); RELEASE_ERROR(slot); AKERR_CHECK(akerr_slots_in_use() == 0); fprintf(stderr, "err_release_clears ok\n"); return 0; }