59 lines
2.2 KiB
C
59 lines
2.2 KiB
C
|
|
#include "akerror.h"
|
||
|
|
#include "err_capture.h"
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
/*
|
||
|
|
* __akerr_copy_string() is the only place in the library that writes through a
|
||
|
|
* caller-supplied pointer for a caller-supplied length, so it validates every
|
||
|
|
* argument and raises rather than returning quietly. Both in-library callers
|
||
|
|
* check their arguments before calling it, so this test is what drives those
|
||
|
|
* guards -- without it they are unreachable code that no build ever exercises.
|
||
|
|
*/
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
char buf[8];
|
||
|
|
|
||
|
|
akerr_capture_install();
|
||
|
|
akerr_init();
|
||
|
|
|
||
|
|
/* The happy path: bounded, and always terminated. */
|
||
|
|
memset(buf, 'x', sizeof(buf));
|
||
|
|
AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, (int)sizeof(buf), "abc"));
|
||
|
|
AKERR_CHECK(strcmp(buf, "abc") == 0);
|
||
|
|
|
||
|
|
/* A source longer than the buffer is truncated, never overrun. */
|
||
|
|
memset(buf, 'x', sizeof(buf));
|
||
|
|
AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, (int)sizeof(buf), "abcdefghijkl"));
|
||
|
|
AKERR_CHECK(strlen(buf) == sizeof(buf) - 1);
|
||
|
|
AKERR_CHECK(buf[sizeof(buf) - 1] == '\0');
|
||
|
|
AKERR_CHECK(strcmp(buf, "abcdefg") == 0);
|
||
|
|
|
||
|
|
/* A capacity of exactly one holds nothing but the terminator. */
|
||
|
|
memset(buf, 'x', sizeof(buf));
|
||
|
|
AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, 1, "abc"));
|
||
|
|
AKERR_CHECK(buf[0] == '\0');
|
||
|
|
AKERR_CHECK(buf[1] == 'x'); /* and wrote nothing past its capacity */
|
||
|
|
|
||
|
|
/* NULL pointers raise instead of faulting, and the message says which. */
|
||
|
|
AKERR_CHECK_RAISES(__akerr_copy_string(NULL, (int)sizeof(buf), "abc"),
|
||
|
|
AKERR_NULLPOINTER);
|
||
|
|
AKERR_CHECK_MESSAGE_CONTAINS("destination");
|
||
|
|
AKERR_CHECK_RAISES(__akerr_copy_string(buf, (int)sizeof(buf), NULL),
|
||
|
|
AKERR_NULLPOINTER);
|
||
|
|
AKERR_CHECK_MESSAGE_CONTAINS("source");
|
||
|
|
|
||
|
|
/* A capacity with no room for a terminator is a value error, not a write. */
|
||
|
|
memset(buf, 'x', sizeof(buf));
|
||
|
|
AKERR_CHECK_RAISES(__akerr_copy_string(buf, 0, "abc"), AKERR_VALUE);
|
||
|
|
AKERR_CHECK_MESSAGE_CONTAINS("capacity of 0");
|
||
|
|
AKERR_CHECK_RAISES(__akerr_copy_string(buf, -1, "abc"), AKERR_VALUE);
|
||
|
|
AKERR_CHECK(buf[0] == 'x'); /* nothing was written */
|
||
|
|
|
||
|
|
/* Each refusal handed its context back to the pool. */
|
||
|
|
AKERR_CHECK(akerr_slots_in_use() == 0);
|
||
|
|
|
||
|
|
fprintf(stderr, "err_copy_string ok\n");
|
||
|
|
return 0;
|
||
|
|
}
|