#include "akerror.h" #include "err_capture.h" #include /* * Reserving a range used to be pure bookkeeping: akerr_name_for_status() would * name any status for any caller, so two components could still register names * for the same code -- and HANDLE the same code -- with nothing detecting it. * Reservation only caught components that both opted in AND declared ranges * that happened to overlap. * * Naming a status is now permitted only inside a reservation: * - akerr_register_status_name() requires the range to belong to the caller; * - the legacy two-argument akerr_name_for_status() set path cannot identify * its caller, so it can only require that *some* reservation covers the * status -- still enough to stop a code nobody claimed. * Every refusal is logged, because a name that fails to register degrades the * status to "Unknown Error" in every later stack trace. */ int main(void) { akerr_capture_install(); akerr_init(); AKERR_CHECK(akerr_reserve_status_range(256, 16, "lib-a") == AKERR_STATUS_RANGE_OK); AKERR_CHECK(akerr_reserve_status_range(512, 16, "lib-b") == AKERR_STATUS_RANGE_OK); /* The owner of a range may name statuses inside it. */ AKERR_CHECK(akerr_register_status_name("lib-a", 256, "A Parse Error") == AKERR_STATUS_NAME_OK); AKERR_CHECK(akerr_register_status_name("lib-a", 271, "A Last Error") == AKERR_STATUS_NAME_OK); AKERR_CHECK(strcmp(akerr_name_for_status(256, NULL), "A Parse Error") == 0); /* Naming another owner's status is refused and names the real owner. */ akerr_capture_reset(); AKERR_CHECK(akerr_register_status_name("lib-b", 256, "B Hijack") == AKERR_STATUS_NAME_FOREIGN); AKERR_CHECK_CONTAINS("lib-a"); AKERR_CHECK_CONTAINS("lib-b"); AKERR_CHECK(strcmp(akerr_name_for_status(256, NULL), "A Parse Error") == 0); /* Including the library's own reserved band. */ akerr_capture_reset(); AKERR_CHECK(akerr_register_status_name("lib-b", AKERR_VALUE, "B Value") == AKERR_STATUS_NAME_FOREIGN); AKERR_CHECK_CONTAINS(AKERR_LIBRARY_OWNER); AKERR_CHECK(strcmp(akerr_name_for_status(AKERR_VALUE, NULL), "Value Error") == 0); /* A status nobody reserved cannot be named through either entry point. */ akerr_capture_reset(); AKERR_CHECK(akerr_register_status_name("lib-a", 9999, "Unclaimed") == AKERR_STATUS_NAME_UNRESERVED); AKERR_CHECK_CONTAINS("no reserved range"); AKERR_CHECK(strcmp(akerr_name_for_status(9999, NULL), "Unknown Error") == 0); akerr_capture_reset(); AKERR_CHECK(strcmp(akerr_name_for_status(9999, "Unclaimed Legacy"), "Unknown Error") == 0); AKERR_CHECK_CONTAINS("no reserved range"); AKERR_CHECK(strcmp(akerr_name_for_status(9999, NULL), "Unknown Error") == 0); /* Boundaries: just outside lib-a's range is not lib-a's to name. */ AKERR_CHECK(akerr_register_status_name("lib-a", 255, "Below") == AKERR_STATUS_NAME_FOREIGN); AKERR_CHECK(akerr_register_status_name("lib-a", 272, "Above") == AKERR_STATUS_NAME_UNRESERVED); /* The legacy set path still works inside any reservation. */ AKERR_CHECK(strcmp(akerr_name_for_status(513, "B Legacy"), "B Legacy") == 0); AKERR_CHECK(strcmp(akerr_name_for_status(513, NULL), "B Legacy") == 0); /* Re-registering your own status overwrites the name. */ AKERR_CHECK(akerr_register_status_name("lib-a", 256, "A Renamed") == AKERR_STATUS_NAME_OK); AKERR_CHECK(strcmp(akerr_name_for_status(256, NULL), "A Renamed") == 0); /* Argument validation. */ AKERR_CHECK(akerr_register_status_name(NULL, 257, "No Owner") == AKERR_STATUS_NAME_INVALID); AKERR_CHECK(akerr_register_status_name("", 257, "Empty Owner") == AKERR_STATUS_NAME_INVALID); AKERR_CHECK(akerr_register_status_name("lib-a", 257, NULL) == AKERR_STATUS_NAME_INVALID); /* A refused registration must not consume a slot or leave a partial entry. */ AKERR_CHECK(strcmp(akerr_name_for_status(257, NULL), "Unknown Error") == 0); /* Lookup is unaffected by ownership -- anyone may read any name. */ AKERR_CHECK(strcmp(akerr_name_for_status(271, NULL), "A Last Error") == 0); fprintf(stderr, "err_name_ownership ok\n"); return 0; }