All checks were successful
Eighty-five comments cited section numbers -- 1.1, 2.2.6, 3.6 -- from a numbering the file had already abandoned before the move to the tracker. They label completed work, so the pointer was the only wrong part. The citation is removed and the sentence kept, which is what issue #27 recommended: these are labels, not references, and a label carrying a version-dependent pointer goes stale again at the next reorganisation. Where a pointer earns its place it names what actually holds the content now -- UPGRADING.md for the confirmed defects, libakerror #15 for the target namespacing, issue #7 for the mutation survivors. README.md and akstdlib.h sent readers to TODO.md for 'what is still open'; they name the tracker. Verified: cmake --build build && ctest --test-dir build, 19/19. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
411 lines
15 KiB
C
411 lines
15 KiB
C
/*
|
|
* Cross-cutting properties every wrapper has to have.
|
|
*
|
|
* Two of them, and neither is about what any individual function computes:
|
|
*
|
|
* Error-pool accounting. libakerror hands out error contexts from a fixed
|
|
* process-global array of AKERR_MAX_ARRAY_ERROR slots. A wrapper that raises
|
|
* an error and forgets to release it does not fail visibly -- it fails
|
|
* AKERR_MAX_ARRAY_ERROR calls later, in whatever unrelated code happens to ask
|
|
* for a slot next, by which time the leak is nowhere near the symptom. So
|
|
* every failure path here is driven AKERR_MAX_ARRAY_ERROR + 10 times, which is
|
|
* past exhaustion several times over, with the pool checked after each round.
|
|
*
|
|
* Stack-trace content. An error that reports the wrong origin is worse than
|
|
* useless when the only debugging you get is a log file after the fact, which
|
|
* is the stated reason this library exists at all. Each assertion here names
|
|
* the function the error must say it came from and the source file it must
|
|
* name, so a FAIL that migrates into a helper is caught.
|
|
*
|
|
* AKSL_RUN already checks the pool after every test in every file. This one
|
|
* checks it inside the loop as well, because a leak of one slot per call needs
|
|
* more than one call to show up.
|
|
*/
|
|
|
|
#include "aksl_capture.h"
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
|
|
/* Rounds enough to exhaust the pool several times over. */
|
|
#define ROUNDS (AKERR_MAX_ARRAY_ERROR + 10)
|
|
|
|
/*
|
|
* Assert the last error came from `func` in a file whose name ends in `file`.
|
|
* The recorded fname is whatever __FILE__ expanded to at the FAIL site, which is
|
|
* an absolute path under CMake, so this matches on the tail rather than the
|
|
* whole thing.
|
|
*/
|
|
static int came_from(const char *func, const char *file)
|
|
{
|
|
size_t flen = strlen(file);
|
|
size_t rlen = strlen(aksl_last_file);
|
|
|
|
if ( strcmp(aksl_last_function, func) != 0 ) {
|
|
fprintf(stderr, " CHECK FAILED: error says it came from \"%s\", expected \"%s\"\n",
|
|
aksl_last_function, func);
|
|
return 1;
|
|
}
|
|
if ( rlen < flen || strcmp(aksl_last_file + (rlen - flen), file) != 0 ) {
|
|
fprintf(stderr, " CHECK FAILED: error names file \"%s\", expected one ending \"%s\"\n",
|
|
aksl_last_file, file);
|
|
return 1;
|
|
}
|
|
if ( aksl_last_line <= 0 ) {
|
|
fprintf(stderr, " CHECK FAILED: error records line %d\n", aksl_last_line);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Pool accounting */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
static int test_memory_wrappers_do_not_leak_slots(void)
|
|
{
|
|
void *ptr = NULL;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_malloc(32, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_malloc(0, &ptr), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_calloc(0, 1, &ptr), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_realloc(NULL, 8), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_free(NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_freep(NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_memset(NULL, 0, 1), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_memcpy(NULL, "a", 1), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_memmove(NULL, "a", 1), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_memcmp(NULL, "a", 1, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_memchr(NULL, 'a', 1, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_stream_wrappers_do_not_leak_slots(void)
|
|
{
|
|
FILE *fp = NULL;
|
|
size_t moved = 0;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_fopen(NULL, "r", &fp), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fopen("/nonexistent/aksl/x", "r", &fp), ENOENT);
|
|
AKSL_CHECK_STATUS(aksl_fread(NULL, 1, 1, stdin, &moved), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fwrite(NULL, 1, 1, stdout, &moved), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fclose(NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fseek(NULL, 0, SEEK_SET), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_ftell(NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fgetc(NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fputs(NULL, stdout), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_remove("/nonexistent/aksl/x"), ENOENT);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_format_wrappers_do_not_leak_slots(void)
|
|
{
|
|
char buf[16];
|
|
int count = 0;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_printf(NULL, "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_fprintf(NULL, stdout, "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_snprintf(NULL, buf, sizeof(buf), "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_snprintf(&count, buf, 4, "%s", "far too long"),
|
|
AKERR_OUTOFBOUNDS);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_conversion_wrappers_do_not_leak_slots(void)
|
|
{
|
|
int iout = 0;
|
|
long lout = 0;
|
|
unsigned long ulout = 0;
|
|
double dout = 0.0;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_atoi(NULL, &iout), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_atoi("junk", &iout), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_atoi("99999999999999999999", &iout), ERANGE);
|
|
AKSL_CHECK_STATUS(aksl_strtol("junk", NULL, 10, &lout), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_strtoul("-1", NULL, 10, &ulout), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_strtod("junk", NULL, &dout), AKERR_VALUE);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_string_wrappers_do_not_leak_slots(void)
|
|
{
|
|
char buf[8];
|
|
char *at = NULL;
|
|
size_t n = 0;
|
|
int r = 0;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_strlen(NULL, &n), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strcpy(buf, sizeof(buf), "far too long for eight"),
|
|
AKERR_OUTOFBOUNDS);
|
|
AKSL_CHECK_STATUS(aksl_strcat(buf, 0, "x"), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_strdup(NULL, &at), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strcmp(NULL, "b", &r), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strchr(NULL, 'a', &at), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strerror(0, buf, 0), AKERR_VALUE);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int test_collection_wrappers_do_not_leak_slots(void)
|
|
{
|
|
aksl_ListNode node;
|
|
aksl_ListNode *head = NULL;
|
|
aksl_List list;
|
|
aksl_TreeNode tree;
|
|
aksl_HashMap map;
|
|
aksl_HashEntry slots[4];
|
|
aksl_StrBuf strbuf;
|
|
size_t n = 0;
|
|
int i = 0;
|
|
|
|
AKSL_CHECK_OK(aksl_list_node_init(&node, NULL));
|
|
AKSL_CHECK_OK(aksl_list_init(&list));
|
|
AKSL_CHECK_OK(aksl_tree_node_init(&tree, NULL));
|
|
AKSL_CHECK_OK(aksl_hashmap_init(&map, slots, 4));
|
|
memset((void *)&strbuf, 0x00, sizeof(strbuf));
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
AKSL_CHECK_STATUS(aksl_list_append(NULL, &node), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_list_pop(&head, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_list_prepend(NULL, &node), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_list_length(&node, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_list_remove(&list, &node), AKERR_VALUE);
|
|
AKSL_CHECK_STATUS(aksl_tree_iterate(&tree, NULL, NULL, NULL,
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, NULL),
|
|
AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_tree_count(&tree, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_hashmap_get(&map, "absent", NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strbuf_append(&strbuf, "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK_STATUS(aksl_strhash_djb2(NULL, 0, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
(void)n;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* A traversal that fails part-way through has the most opportunities to leak: an
|
|
* error is raised inside a callback, propagated up through several frames, and
|
|
* handled or not at the top. Drive that repeatedly too.
|
|
*/
|
|
static akerr_ErrorContext AKERR_NOIGNORE *always_fails(aksl_TreeNode *node, void *data)
|
|
{
|
|
PREPARE_ERROR(e);
|
|
(void)node;
|
|
(void)data;
|
|
FAIL_RETURN(e, AKERR_VALUE, "callback always fails");
|
|
}
|
|
|
|
static akerr_ErrorContext AKERR_NOIGNORE *always_breaks(aksl_TreeNode *node, void *data)
|
|
{
|
|
PREPARE_ERROR(e);
|
|
(void)node;
|
|
(void)data;
|
|
FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "callback always breaks");
|
|
}
|
|
|
|
static int test_traversal_failures_do_not_leak_slots(void)
|
|
{
|
|
aksl_TreeNode tree[3];
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < 3; i++ ) {
|
|
AKSL_CHECK_OK(aksl_tree_node_init(&tree[i], NULL));
|
|
}
|
|
tree[0].left = &tree[1];
|
|
tree[0].right = &tree[2];
|
|
|
|
for ( i = 0; i < ROUNDS; i++ ) {
|
|
/* Propagated out of the recursion. */
|
|
AKSL_CHECK_STATUS(aksl_tree_iterate(&tree[0], &always_fails, NULL, NULL,
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, NULL),
|
|
AKERR_VALUE);
|
|
/* Swallowed at the top -- the released-not-returned path. */
|
|
AKSL_CHECK_OK(aksl_tree_iterate(&tree[0], &always_breaks, NULL, NULL,
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, NULL));
|
|
/* And through the breadth-first walk, which also drains a queue. */
|
|
AKSL_CHECK_STATUS(aksl_tree_iterate(&tree[0], &always_fails, NULL, NULL,
|
|
AKSL_TREE_SEARCH_BFS, NULL),
|
|
AKERR_VALUE);
|
|
AKSL_CHECK_OK(aksl_tree_iterate(&tree[0], &always_breaks, NULL, NULL,
|
|
AKSL_TREE_SEARCH_BFS, NULL));
|
|
AKSL_CHECK(aksl_slots_in_use() == 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Stack-trace content */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Each of these asserts that the error names the function that raised it and
|
|
* the file that function lives in. This is what catches a FAIL that gets moved
|
|
* into a shared helper during a refactor: the status stays right, the message
|
|
* stays right, and the origin quietly starts pointing at the wrong place.
|
|
*/
|
|
static int test_errors_name_their_origin_in_stdlib(void)
|
|
{
|
|
void *ptr = NULL;
|
|
int count = 0;
|
|
char resolved[PATH_MAX];
|
|
uint32_t h = 0;
|
|
aksl_ListNode node;
|
|
|
|
AKSL_CHECK_STATUS(aksl_malloc(32, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_malloc", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_free(NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_free", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_memcpy(NULL, "a", 1), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_memcpy", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_fopen(NULL, "r", (FILE **)&ptr), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_fopen", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_fclose(NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_fclose", "src/stdlib.c") == 0);
|
|
|
|
/*
|
|
* aksl_printf forwards to aksl_vprintf, so the error legitimately comes
|
|
* from the latter -- the variadic form is a three-line wrapper with no FAIL
|
|
* of its own. Asserting the real origin rather than the one a reader might
|
|
* expect is the point of recording it.
|
|
*/
|
|
AKSL_CHECK_STATUS(aksl_printf(NULL, "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_vprintf", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_snprintf(&count, NULL, 8, "x"), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_vsnprintf", "src/stdlib.c") == 0);
|
|
|
|
/* Likewise, the ato* forms are calls into the strto* ones. */
|
|
AKSL_CHECK_STATUS(aksl_atol("junk", (long *)&ptr), AKERR_VALUE);
|
|
AKSL_CHECK(came_from("aksl_strtol", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_realpath(NULL, resolved, sizeof(resolved)), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_realpath", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strhash_djb2(NULL, 0, &h), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_strhash_djb2", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_OK(aksl_list_node_init(&node, NULL));
|
|
AKSL_CHECK_STATUS(aksl_list_append(NULL, &node), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_list_append", "src/stdlib.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_tree_iterate(NULL, NULL, NULL, NULL,
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, NULL),
|
|
AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_tree_iterate", "src/stdlib.c") == 0);
|
|
return 0;
|
|
}
|
|
|
|
static int test_errors_name_their_origin_in_string_and_stream(void)
|
|
{
|
|
char buf[8];
|
|
size_t n = 0;
|
|
long pos = 0;
|
|
|
|
AKSL_CHECK_STATUS(aksl_strlen(NULL, &n), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_strlen", "src/string.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strcpy(buf, sizeof(buf), "far too long for eight"),
|
|
AKERR_OUTOFBOUNDS);
|
|
AKSL_CHECK(came_from("aksl_strcpy", "src/string.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strdup(NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_strdup", "src/string.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strerror(0, buf, 0), AKERR_VALUE);
|
|
AKSL_CHECK(came_from("aksl_strerror", "src/string.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_fseek(NULL, 0, SEEK_SET), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_fseek", "src/stream.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_ftell(NULL, &pos), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_ftell", "src/stream.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_getline(NULL, NULL, NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_getline", "src/stream.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_mkdtemp("no-placeholder"), AKERR_VALUE);
|
|
AKSL_CHECK(came_from("aksl_mkdtemp", "src/stream.c") == 0);
|
|
return 0;
|
|
}
|
|
|
|
static int test_errors_name_their_origin_in_collections(void)
|
|
{
|
|
aksl_ListNode node;
|
|
aksl_List list;
|
|
aksl_HashMap map;
|
|
aksl_HashEntry slots[4];
|
|
aksl_StrBuf strbuf;
|
|
char longkey[AKSL_HASHMAP_MAX_KEY + 4];
|
|
|
|
AKSL_CHECK_OK(aksl_list_node_init(&node, NULL));
|
|
AKSL_CHECK_OK(aksl_list_init(&list));
|
|
AKSL_CHECK_OK(aksl_hashmap_init(&map, slots, 4));
|
|
memset((void *)&strbuf, 0x00, sizeof(strbuf));
|
|
memset(longkey, 'k', sizeof(longkey) - 1);
|
|
longkey[sizeof(longkey) - 1] = '\0';
|
|
|
|
AKSL_CHECK_STATUS(aksl_list_prepend(NULL, &node), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_list_prepend", "src/collections.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_list_remove(&list, &node), AKERR_VALUE);
|
|
AKSL_CHECK(came_from("aksl_list_remove", "src/collections.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_tree_insert(NULL, NULL, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_tree_insert", "src/collections.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_hashmap_put(&map, longkey, NULL), AKERR_OUTOFBOUNDS);
|
|
AKSL_CHECK(came_from("aksl_hashmap_put", "src/collections.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strhash_fnv1a(NULL, 0, NULL), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_strhash_fnv1a", "src/collections.c") == 0);
|
|
|
|
AKSL_CHECK_STATUS(aksl_strbuf_reset(&strbuf), AKERR_NULLPOINTER);
|
|
AKSL_CHECK(came_from("aksl_strbuf_reset", "src/collections.c") == 0);
|
|
return 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int failures = 0;
|
|
|
|
akerr_init();
|
|
|
|
AKSL_RUN(failures, test_memory_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_stream_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_format_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_conversion_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_string_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_collection_wrappers_do_not_leak_slots);
|
|
AKSL_RUN(failures, test_traversal_failures_do_not_leak_slots);
|
|
|
|
AKSL_RUN(failures, test_errors_name_their_origin_in_stdlib);
|
|
AKSL_RUN(failures, test_errors_name_their_origin_in_string_and_stream);
|
|
AKSL_RUN(failures, test_errors_name_their_origin_in_collections);
|
|
|
|
AKSL_REPORT(failures);
|
|
}
|