Fix AKERR_MAX_ERR_VALUE to cover all AKERR_* codes
AKERR_MAX_ERR_VALUE was AKERR_LAST_ERRNO_VALUE + 15, but the highest defined code, AKERR_BADEXC, is + 17 (AKERR_NOT_IMPLEMENTED is + 16). akerr_name_for_status rejects any status above the max, so those codes could never have a registered name and the AKERR_BADEXC registration in akerr_init was dead code -- a gap found by mutation testing. Bump the max to + 17. - err_maxval: new test asserting the reserved AKERR_* range exceeds the number of AKERR_* codes and that every code is individually indexable. Fails against the old + 15 value (verified), guarding against regression. - err_error_names: now also checks AKERR_BADEXC's name, which the fix makes reachable. Mutation score on src/error.c rises 71% -> 74%: the previously-dead BADEXC registration and the name_for_status upper-bound check are now killable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
52
tests/err_maxval.c
Normal file
52
tests/err_maxval.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "akerror.h"
|
||||
#include "err_capture.h"
|
||||
|
||||
/*
|
||||
* AKERR_MAX_ERR_VALUE sizes the __AKERR_ERROR_NAMES table and is the upper bound
|
||||
* akerr_name_for_status() will accept. If it is smaller than the highest AKERR_*
|
||||
* code, those codes silently lose their names (this was a real bug: the max was
|
||||
* +15 while AKERR_BADEXC is +17).
|
||||
*
|
||||
* Guard the invariant: the AKERR_* range reserved above AKERR_LAST_ERRNO_VALUE
|
||||
* must be larger than the number of AKERR_* codes defined, and every code must
|
||||
* be individually indexable.
|
||||
*/
|
||||
|
||||
/* Every AKERR_* library error code. Keep in sync with akerror.h. */
|
||||
static const int akerr_codes[] = {
|
||||
AKERR_NULLPOINTER,
|
||||
AKERR_OUTOFBOUNDS,
|
||||
AKERR_API,
|
||||
AKERR_ATTRIBUTE,
|
||||
AKERR_TYPE,
|
||||
AKERR_KEY,
|
||||
AKERR_INDEX,
|
||||
AKERR_FORMAT,
|
||||
AKERR_IO,
|
||||
AKERR_VALUE,
|
||||
AKERR_RELATIONSHIP,
|
||||
AKERR_EOF,
|
||||
AKERR_CIRCULAR_REFERENCE,
|
||||
AKERR_ITERATOR_BREAK,
|
||||
AKERR_NOT_IMPLEMENTED,
|
||||
AKERR_BADEXC,
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int n = (int)(sizeof(akerr_codes) / sizeof(akerr_codes[0]));
|
||||
|
||||
/* AKERR_MAX_ERR_VALUE must reserve more codes than are actually defined. */
|
||||
AKERR_CHECK((AKERR_MAX_ERR_VALUE - AKERR_LAST_ERRNO_VALUE) > n);
|
||||
|
||||
/* Stronger: every defined code must fall within the addressable range so
|
||||
* its name can be stored and retrieved. */
|
||||
for ( int i = 0; i < n; i++ ) {
|
||||
AKERR_CHECK(akerr_codes[i] > AKERR_LAST_ERRNO_VALUE);
|
||||
AKERR_CHECK(akerr_codes[i] <= AKERR_MAX_ERR_VALUE);
|
||||
}
|
||||
|
||||
fprintf(stderr, "err_maxval ok (%d codes, range %d)\n",
|
||||
n, AKERR_MAX_ERR_VALUE - AKERR_LAST_ERRNO_VALUE);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user