diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 1ffaf68..d246fbb 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -21,7 +21,7 @@ jobs: # different libakerrors depending on where you built: the install went to # /usr/local, while the build below is top-level and so compiles # deps/libakerror at the pinned commit via add_subdirectory -- the - # installed one was never actually linked against. TODO.md 2.3. + # installed one was never actually linked against. # # The submodule wins. It is the version this repository pins, tests and # ships against, and a CI that tests a different one is testing something @@ -155,7 +155,7 @@ jobs: # new surface being argument validation whose mutants are frequently # equivalent. `errno = 0` deleted from a wrapper whose libc call always # sets errno cannot be distinguished by any test that could be written. - # The survivors worth acting on are named in TODO.md; raise the gate as + # The survivors worth acting on are named in issue #7; raise the gate as # they become assertions. - name: mutation testing run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 06da09b..b6d9965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.10) # akstdlibConfigVersion.cmake. Nothing else should spell a version number. # # 0.2.0, and the minor bump is an ABI break on purpose. Fixing the confirmed -# defects in TODO.md 2.1 changed documented behaviour and, in five places, +# defects listed in UPGRADING.md changed documented behaviour and, in five places, # signatures: # # aksl_realpath takes the destination's length; aksl_realpath_alloc is new @@ -54,7 +54,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() # Warnings. The only warning in the tree when these went on was the unused -# `queue` parameter of aksl_tree_iterate, which TODO.md 2.2.8 had already +# `queue` parameter of aksl_tree_iterate, which UPGRADING.md had already # recorded as a dead parameter -- so the cost of turning them on was one # already-known defect, and the cost of leaving them off was every future one. # @@ -63,7 +63,7 @@ endif() # requires at least one argument for the ...", which is a complaint about the # macro's shape rather than about anything at this call site. Every FAIL_* in # src/stdlib.c passes at least one argument regardless -- see the note in -# TODO.md 2.3 -- so the code is pedantic-clean; it is the expansion that is not. +# libakerror issue #15 -- so the code is pedantic-clean; it is the expansion that is not. if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$") add_compile_options(-Wall -Wextra) # CI turns this on. Locally it is off, because a warning that stops the build @@ -173,7 +173,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) # configure at all. Rename the dependency's on the way past rather than # dropping it: its coverage script drives its own instrumented build tree, so # `cmake --build build-coverage --target akerror_coverage` still does the right - # thing. Remove this once the dependency namespaces it upstream -- see TODO.md. + # thing. Remove this once the dependency namespaces it upstream -- libakerror issue #15. function(add_custom_target _name) if(AKSL_SUPPRESS_ADD_TEST AND _name STREQUAL "coverage") _add_custom_target(akerror_coverage ${ARGN}) @@ -329,7 +329,7 @@ set(AKSL_WILL_FAIL_TESTS # Empty, and that is the news. It held four entries -- convert_strict, # list_append_chain, list_iterate_head and tree_iterate_break -- one for each -# confirmed defect in TODO.md 2.1. All four are fixed, so each of those files +# confirmed defect listed in UPGRADING.md. All four are fixed, so each of those files # was folded back into the test for the thing it was testing (tests/ # test_convert.c, tests/test_linkedlist.c and tests/test_tree.c) where it now # has to keep passing rather than merely keep failing visibly. @@ -350,7 +350,7 @@ foreach(_test IN LISTS AKSL_TESTS AKSL_WILL_FAIL_TESTS AKSL_KNOWN_FAILING_TESTS) list(APPEND AKSL_TEST_TARGETS test_${_test}) endforeach() -# Negative compile tests -- TODO.md 1.3 and 1.9. +# Negative compile tests: the format attributes and AKERR_NOIGNORE. # # Two properties of this library are enforced by the compiler and by nothing # else: AKERR_NOIGNORE makes discarding a returned error context an error, and diff --git a/README.md b/README.md index e03e043..258d77e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ through [libakerror](https://source.starfort.tech/andrew/libakerror)'s and `errno`. It also provides data structures built on the same convention. Every entry point returns `akerr_ErrorContext *` and is marked `AKERR_NOIGNORE`. -See `TODO.md` for the current state of the library and `UPGRADING.md` if you are +Outstanding work is in [the issue tracker](https://source.starfort.tech/andrew/libakstdlib/issues). +See `TODO.md` for where the library stands and what is deliberately not wrapped, and `UPGRADING.md` if you are coming from 0.1.0, which this release breaks. ## What it wraps diff --git a/include/akstdlib.h b/include/akstdlib.h index 6dd2d6e..8fe8282 100644 --- a/include/akstdlib.h +++ b/include/akstdlib.h @@ -26,7 +26,8 @@ * takes a slot from it on any failure path. See README.md. * * @see README.md for the deviations from libc semantics, UPGRADING.md if you are - * coming from 0.1.0, and TODO.md for what is still open. + * coming from 0.1.0. Outstanding work is in the issue tracker; + * TODO.md is the record of where the library stands. */ #ifndef _AKSTDLIB_H_ @@ -69,7 +70,7 @@ * * It used to pull in stdlib.h and string.h as well, which nothing here needs and * which every consumer then got whether it wanted them or not. stddef.h in place - * of stdlib.h is the same size_t at a fraction of the namespace. TODO.md 2.2.16. + * of stdlib.h is the same size_t at a fraction of the namespace. */ #include #include @@ -85,7 +86,7 @@ extern "C" { /* * Restore the compile-time format/argument checking that callers otherwise lose * by going through a variadic wrapper: without it, printf("%d", "str") is caught - * and aksl_printf(&n, "%d", "str") is not. TODO.md 2.2.5. + * and aksl_printf(&n, "%d", "str") is not. * * tests/negative/format_mismatch.c is a compile that must fail, which is what * proves these are still attached. diff --git a/src/aksl_internal.h b/src/aksl_internal.h index 1937c7e..c851bc7 100644 --- a/src/aksl_internal.h +++ b/src/aksl_internal.h @@ -18,7 +18,7 @@ * the context still holds a pool slot: an error that is invisible and leaks at * the same time. Every errno-sourced status in this library goes through here, * and every wrapped call clears errno first so the value read back is its own. - * TODO.md 2.2.1. + * See UPGRADING.md. */ #define AKSL_ERRNO_OR(__fallback) (errno != 0 ? errno : (__fallback)) diff --git a/src/collections.c b/src/collections.c index 3ffe4c4..73403d7 100644 --- a/src/collections.c +++ b/src/collections.c @@ -1,5 +1,5 @@ /* - * Data structures -- TODO.md section 3.6. + * Data structures. * * Not libc wrappers. These are the parts of the list and tree API that were * visibly missing, plus the two structures the first real consumer had to write @@ -328,7 +328,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate_reverse(aksl_ListNode *tail * aksl_list_append has to walk the whole list to find the tail, so building a * list of n nodes with it is O(n^2). That is fine for the handful of nodes the * bare-node API was written for and wrong for anything larger, which is what - * TODO.md 3.6 means by "a head/tail-tracking container type so append is O(1)". + * the collections plan meant by "a head/tail-tracking container type so append is O(1)". * * The container holds the length as well, so aksl_list_length stops being a * walk. It owns no memory -- the nodes are still the caller's -- so there is no @@ -440,7 +440,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_clear(aksl_List *list, aksl_FreeFun * through an out-param and may raise, like every other callback here. * * These are the functions that set and read aksl_TreeNode.parent, which was - * declared and then never touched by anything in the library (TODO.md 2.2.15). + * declared and then never touched by anything in the library. * aksl_tree_remove needs it: relinking a node's replacement means telling that * node's parent about it, and finding the parent by walking from the root again * would turn a removal into a second search. @@ -691,7 +691,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_free_all(aksl_TreeNode **root, aksl /* ====================================================================== */ /* - * FNV-1a, the other half of TODO.md 3.6's hash request. It differs from djb2 in + * FNV-1a, the other half of the collections plan's hash request. It differs from djb2 in * XOR-then-multiply rather than multiply-then-add, which mixes the low bits * rather better -- worth having when the keys are short and share a prefix, * which is exactly what identifiers in a symbol table look like. @@ -730,7 +730,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_fnv1a_str(const char *str, uint3 /* * Fixed-capacity, open-addressed, linear-probing, string-keyed. * - * The shape is akbasic's src/symtab.c, which TODO.md 3.6 says is "worth lifting + * The shape is akbasic's src/symtab.c, which the collections plan called "worth lifting * more or less verbatim": the caller supplies the slot array, the map refuses * rather than resizes when full, and the keys are copied into fixed-size slots * so the map owns them and a caller cannot outlive its own key strings. @@ -939,7 +939,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_hashmap_iterate(aksl_HashMap *map, * * The bounded formatting wrappers are the right answer when the destination is * a fixed buffer, and no answer at all when the output length is not known in - * advance -- which is why TODO.md 3.6 asks for this to "make the snprintf and + * advance -- which is why the collections plan asked for this to "make the snprintf and * strcat wrappers pleasant to use". Building a diagnostic, a serialised record * or a generated line means appending to something that grows. * diff --git a/src/stdlib.c b/src/stdlib.c index db882bb..2fb5a59 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -99,7 +99,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_calloc(size_t nmemb, size_t size, void * * block valid*, so the near-universal `p = realloc(p, n)` leaks the original * every time it fails. Here the old pointer goes in and out through the same * out-param, and is left untouched -- still valid, still the caller's to free -- - * whenever an error is raised. TODO.md 3.1. + * whenever an error is raised. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_realloc(void **ptr, size_t size) { @@ -196,7 +196,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_free(void *ptr) /* * Frees and clears in one step, so the pointer cannot be used or freed twice. - * TODO.md 2.2.13 -- aksl_free leaves the caller holding a dangling pointer, and + * aksl_free leaves the caller holding a dangling pointer, and * "remember to NULL it afterwards" is exactly the discipline this library is * supposed to make unnecessary rather than merely possible. */ @@ -214,7 +214,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_freep(void **ptr) * memset(3) and memcpy(3) cannot fail. They return their destination pointer * unconditionally, so the old FAIL_ZERO_RETURN(e, memset(...), ...) and * (memcpy(...) == d) checks were dead code that read as though there were a - * failure mode to catch -- TODO.md 2.2.11. What is worth checking is the + * failure mode to catch. What is worth checking is the * arguments, which is all that is checked now. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_memset(void *s, int c, size_t n) @@ -289,7 +289,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_memchr(const void *s, int c, size_t n, v * pathname and mode are checked. fopen(NULL, ...) is undefined behaviour, and * this wrapper used to hand both straight through unexamined -- reachable from * user input in practice, which is why akbasic validates the filename itself - * before calling DLOAD/DSAVE with a comment pointing at TODO.md 2.2.2. + * before calling DLOAD/DSAVE with a comment pointing at. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_fopen( const char *pathname, @@ -312,7 +312,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fopen( /* * fread and fwrite both report how much they actually transferred, through a - * required out-param. Three things were wrong with the old pair (TODO.md 2.2.3), + * required out-param. Three things were wrong with the old pair, * and the count is the fix for the worst of them: a caller who got AKERR_EOF had * no way to find out how much data had arrived before the stream ran out, which * makes the EOF status almost useless for the partial-read case it exists to @@ -405,7 +405,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fclose(FILE *stream) * Formatted output. * * The va_list forms below do the work and the variadic forms are thin wrappers - * over them, which is both what ยง3.1 of TODO.md asked for -- so consumers can + * over them, which is both what the wrapper contract asked for -- so consumers can * build their own variadic wrappers -- and what makes the va_end rule below * checkable in one place instead of three. * @@ -415,7 +415,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fclose(FILE *stream) * one. Omitting it is undefined behaviour per the standard and leaks * register-save state on some ABIs. akbasic's text sink ran this UB on every * line of program output without anything visibly misbehaving, which is - * exactly what made it worth fixing before something did. TODO.md 2.1.4. + * exactly what made it worth fixing before something did. * - *count is written on every path. It used to be left holding vprintf's -1 * after a failure, so a caller who read the length rather than the status got * a negative byte count out of a function that had already failed. It is now @@ -426,7 +426,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fclose(FILE *stream) * aksl_sprintf is gone. It wrapped vsprintf, which cannot be bounded, and an * error-handling wrapper around an unbounded write is precisely the sharp edge * this library exists to remove. aksl_snprintf replaces it, and treats - * truncation as the failure it is rather than as a short success. TODO.md 2.2.4. + * truncation as the failure it is rather than as a short success. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_vprintf(int *count, const char *restrict format, va_list args) @@ -561,7 +561,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_vasprintf(int *count, char **dest, const * same arguments a few lines up, so the write cannot truncate. Guarding it * anyway would mean a failure branch nothing can reach and a free() beneath * it that nothing can execute -- dead code that reads as though there were a - * failure mode to catch, which is exactly what TODO.md 2.2.11 recorded + * failure mode to catch, which is exactly what was recorded * against the old aksl_memset and aksl_memcpy and what removing those was * for. The invariant is stated here instead, where it can be read. */ @@ -590,10 +590,10 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_asprintf(int *count, char **dest, const * atoi("99999999999999999999") handed back success and a wrapped value, because * atoi(3) has no error channel at all. A library whose entire value proposition * is turning silent libc failures into error contexts cannot ship that. - * TODO.md 2.1.5. + * See UPGRADING.md. * * The strto* wrappers below are the real implementation and the ato* wrappers - * are three-line calls into them, which is what TODO.md 3.1 asked for on its own + * are three-line calls into them, which is what the wrapper contract asked for on its own * account -- akbasic had to hand-write ~60 lines of exactly this (its * src/convert.c) because the library would not do it. * @@ -846,7 +846,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_atof(const char *nptr, double *dest) * realpath(3), with the destination buffer made expressible. * * The old two-argument form had three separate problems, all of them reachable - * from ordinary use (TODO.md 2.1.6): resolved_path was never NULL-checked, so + * from ordinary use: resolved_path was never NULL-checked, so * realpath(path, NULL) allocated a buffer the wrapper then discarded and leaked; * there was no way for a caller to say how big the buffer was, so everyone had * to know to supply PATH_MAX bytes; and the failure path formatted resolved_path @@ -904,7 +904,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath_alloc(const char *restrict path * negative value: the hash differed from canonical djb2, and -- worse -- differed * between platforms depending on the signedness of char. Benign for the 7-bit * ASCII identifiers akbasic hashes, and quietly wrong for the first caller to - * key a table on a filename or a UTF-8 string literal. TODO.md 2.2.6. + * key a table on a filename or a UTF-8 string literal. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(const char *str, size_t len, uint32_t *hashval) { @@ -921,7 +921,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(const char *str, size_t len SUCCEED_RETURN(e); } -/* The NUL-terminated convenience form TODO.md 3.6 asked for. */ +/* The NUL-terminated convenience form the collections plan asked for. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2_str(const char *str, uint32_t *hashval) { PREPARE_ERROR(e); @@ -941,7 +941,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(aksl_ListNode *list, aksl_Li * Two separate walks, deliberately. The Floyd pass answers "is this list * finite"; it says nothing about where the tail is, because `slow` stops at * the midpoint. Conflating the two is what made this function truncate every - * list of two or more nodes -- see TODO.md 2.1.1. + * list of two or more nodes. */ while ( fast != NULL && fast->next != NULL ) { slow = slow->next; @@ -973,7 +973,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(aksl_ListNode *list, aksl_Li /* * `head` is required, not optional. Popping the head node used to leave the * caller's own head pointer aimed at a node that is no longer in the list, and - * there was no way for the caller to learn the new one -- TODO.md 2.2.12. Taking + * there was no way for the caller to learn the new one. Taking * the head by reference makes the correct call the only call that compiles. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode **head, aksl_ListNode *node) @@ -998,7 +998,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode **head, aksl_List /* * Zeroing initialisers. Every caller previously had to remember to memset a node * before its first use, because append and iterate both read next/prev -- and a - * stack-allocated node that skipped it walked into garbage. TODO.md 2.2.14. + * stack-allocated node that skipped it walked into garbage. */ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_node_init(aksl_ListNode *node, void *data) { @@ -1027,7 +1027,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_node_init(aksl_TreeNode *node, void * aksl_ListNode: the walk needs to carry each node's depth alongside it, which is * how a cyclic tree is stopped without a visited-set. The caller's lalloc/lfree * allocate and release these -- which is what they were always documented to do - * and never actually did (TODO.md 2.2.8). + * and never actually did. */ typedef struct TreeQueueEntry { struct TreeQueueEntry *next; @@ -1165,12 +1165,12 @@ static akerr_ErrorContext AKERR_NOIGNORE *tree_bfs_walk( * unwinds every frame up to the public entry point, which swallows it exactly * once. In the old single-function form the frame that raised the break handled * it and returned success, the parent's PASS therefore saw nothing wrong, and - * the walk carried on into the sibling subtree -- TODO.md 2.1.3. + * the walk carried on into the sibling subtree. * * `path` is the chain of ancestors of `root` and `depth` its length. Checking * each node against its own ancestry turns a tree that loops back on itself from * infinite recursion into AKERR_CIRCULAR_REFERENCE, and the depth cap catches the - * degenerate chain that is merely too deep to recurse over (TODO.md 2.2.7). + * degenerate chain that is merely too deep to recurse over. */ static akerr_ErrorContext AKERR_NOIGNORE *tree_dfs_walk( aksl_TreeNode *root, @@ -1266,7 +1266,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_iterate( * assume it. The switch used to have no default at all, so searchmode 99 -- * and AKSL_TREE_SEARCH_VISIT, which the header documented but nothing * implemented -- fell straight through to success having visited nothing - * (TODO.md 2.2.9). + * See UPGRADING.md. */ switch ( searchmode ) { case AKSL_TREE_SEARCH_DFS_PREORDER: @@ -1328,7 +1328,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_L /* * From `list`, not from `slow`. The Floyd pass above leaves `slow` at the * midpoint, and starting the visit there skipped the whole first half of the - * list including the head -- see TODO.md 2.1.2. + * list including the head. */ while ( node != NULL ) { ATTEMPT { diff --git a/src/stream.c b/src/stream.c index 4d057cf..2e005ec 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1,5 +1,5 @@ /* - * stdio.h wrappers beyond fopen/fread/fwrite/fclose -- TODO.md section 3.1. + * stdio.h wrappers beyond fopen/fread/fwrite/fclose. * * Positioning, flushing, character and line I/O, stream state, formatted input, * and the file-level operations that go with them. diff --git a/src/string.c b/src/string.c index 6ccf1dc..a529918 100644 --- a/src/string.c +++ b/src/string.c @@ -1,12 +1,12 @@ /* - * string.h wrappers -- TODO.md section 3.1. + * string.h wrappers. * * This is the section akbasic needed most and could not have: across its source * it calls strlen 37 times, strcmp 16, strncpy 15 and strstr once, every one of * them raw because there was nothing here to call instead. Ten of those sites * are the same idiom written out by hand -- a length check, then strncpy, then * an explicit NUL -- which is exactly the "truncation reported as an error - * rather than silently accepted" that TODO.md 3.1 asks for. + * rather than silently accepted" that the wrapper contract asks for. * * Two conventions run through the whole file. * diff --git a/tests/negative/format_mismatch.c b/tests/negative/format_mismatch.c index 4d933b8..c9f554f 100644 --- a/tests/negative/format_mismatch.c +++ b/tests/negative/format_mismatch.c @@ -1,5 +1,5 @@ /* - * NEGATIVE COMPILE TEST -- TODO.md sections 1.3 and 2.2.5. + * NEGATIVE COMPILE TEST. * * This file must NOT compile. It is built by the CTest entry * `negative_format_mismatch` with -Werror, and that test is marked WILL_FAIL. diff --git a/tests/negative/noignore.c b/tests/negative/noignore.c index 0c67890..a456f43 100644 --- a/tests/negative/noignore.c +++ b/tests/negative/noignore.c @@ -1,5 +1,5 @@ /* - * NEGATIVE COMPILE TEST -- TODO.md section 1.9. + * NEGATIVE COMPILE TEST. * * This file must NOT compile. It is built by the CTest entry `negative_noignore` * with -Werror, and that test is marked WILL_FAIL, so a successful build is a diff --git a/tests/test_collections.c b/tests/test_collections.c index d7ac571..52b7510 100644 --- a/tests/test_collections.c +++ b/tests/test_collections.c @@ -1,5 +1,5 @@ /* - * List and tree additions -- src/collections.c, TODO.md section 3.6. + * List and tree additions -- src/collections.c. * * The bare-node list functions, the tracked aksl_List container, and the binary * search tree. The hash map and string buffer have their own files. @@ -407,7 +407,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *free_that_fails_once(void *ptr) * single walk. Only the first is kept and handed back; the rest have to be * released, or a walk over n nodes with a broken free would consume n pool slots * and exhaust the pool -- the failure mode the whole pool-accounting section of - * TODO.md 1.9 exists to catch. + * the cross-cutting wrapper contract exists to catch. */ static akerr_ErrorContext AKERR_NOIGNORE *free_that_always_fails(void *ptr) { @@ -800,7 +800,7 @@ static int test_tree_insert_orders_the_leaves(void) } /* - * TODO.md 2.2.15: aksl_TreeNode.parent was declared and never touched by + * aksl_TreeNode.parent was declared and never touched by * anything in the library. These are the functions that set it, and * aksl_tree_remove is the one that needs it. */ diff --git a/tests/test_convert.c b/tests/test_convert.c index 82422dd..dfdea71 100644 --- a/tests/test_convert.c +++ b/tests/test_convert.c @@ -1,7 +1,7 @@ /* * String -> number wrappers: aksl_atoi / atol / atoll / atof. * - * TODO.md section 1.4, complete. The cases that used to live in + * Numeric conversion, complete. The cases that used to live in * tests/test_convert_strict.c -- registered as a known failure because the ato* * family had no error channel at all (2.1.5) -- are folded back in here now that * they pass: non-numeric input, empty input, trailing junk and overflow are all @@ -95,7 +95,7 @@ static int test_trailing_junk_is_a_value_error(void) /* * "0x10" through the ato* forms is base 10, so parsing stops at the 'x' and the - * rest is trailing junk. TODO.md 1.4 left this open; the answer is that the + * rest is trailing junk. The wrapper plan left this open; the answer is that the * prefix-honouring parse is aksl_strtol(nptr, NULL, 0, &dest), and tests/ * test_strto.c holds that half. */ @@ -149,7 +149,7 @@ static int test_atoi_narrows_to_int_range(void) return 0; } -/* TODO.md 1.4: the type boundaries round-trip exactly rather than nearly. */ +/* The type boundaries round-trip exactly rather than nearly. */ static int test_type_boundaries_round_trip(void) { char buf[64]; @@ -229,7 +229,7 @@ static int test_atof_converts_and_rejects_null(void) } /* - * TODO.md 1.4 left "inf" and "nan" open. They are accepted, because strtod(3) + * The wrapper plan left "inf" and "nan" open. They are accepted, because strtod(3) * accepts them and because they are exact round-trips rather than approximations * of something else -- a caller who did not want them has a domain check to make * that this library cannot make for it. diff --git a/tests/test_format.c b/tests/test_format.c index 28f4b8c..39ba642 100644 --- a/tests/test_format.c +++ b/tests/test_format.c @@ -2,7 +2,7 @@ * Formatted-output wrappers: aksl_printf / aksl_fprintf / aksl_snprintf and * their va_list forms. * - * TODO.md section 1.3, now complete. Each happy path asserts both halves of the + * Formatted output, complete. Each happy path asserts both halves of the * contract -- the byte count handed back through *count and the text that * actually landed somewhere -- and every pointer argument is checked for its * NULL guard. @@ -11,7 +11,7 @@ * points at the formatted-output wrapper under test and not at the stream * wrappers, which tests/test_stream.c covers. * - * aksl_sprintf is gone (TODO.md 2.2.4) and aksl_snprintf takes its place, so the + * aksl_sprintf is gone and aksl_snprintf takes its place, so the * destination-overflow case that could not previously be written is here: it is * AKERR_OUTOFBOUNDS, not the short success snprintf(3) would have reported. */ @@ -139,7 +139,7 @@ static int test_fprintf_writes_to_stream(void) /* * vfprintf on a stream opened "r" fails outright, so the wrapper reports the * errno it saw (EBADF on glibc). *count is 0 afterwards, not vfprintf's -1: - * TODO.md 1.3 recorded the negative count as a contract gap, and this is the + * The wrapper plan recorded the negative count as a contract gap, and this is the * assertion that closes it. */ static int test_fprintf_to_read_only_stream_reports_errno(void) @@ -270,7 +270,7 @@ static int test_asprintf_allocates_to_fit(void) } /* - * The va_list forms are what the variadic ones are built on, and TODO.md 3.1 + * The va_list forms are what the variadic ones are built on, and the wrapper contract * wanted them exposed so consumers can write their own variadic wrappers. This * is a consumer doing exactly that. */ @@ -304,7 +304,7 @@ static int test_va_list_forms_are_usable_from_outside(void) } /* - * Regression cover for the missing va_end (TODO.md 2.1.4). Nothing here can + * Regression cover for the missing va_end. Nothing here can * assert on register-save state directly; the point is to run the variadic * wrappers enough times, with enough arguments, that the sanitizer build has * something to trip over. diff --git a/tests/test_hashmap.c b/tests/test_hashmap.c index bd61c76..47b5daa 100644 --- a/tests/test_hashmap.c +++ b/tests/test_hashmap.c @@ -1,5 +1,5 @@ /* - * The fixed-capacity hash map and FNV-1a -- src/collections.c, TODO.md 3.6. + * The fixed-capacity hash map and FNV-1a -- src/collections.c. * * "The single most obviously-missing data structure in the library", by the * TODO's own account: akbasic needed one three times over -- variables, diff --git a/tests/test_linkedlist.c b/tests/test_linkedlist.c index 4a74cda..a19661c 100644 --- a/tests/test_linkedlist.c +++ b/tests/test_linkedlist.c @@ -1,5 +1,5 @@ /* - * Linked list -- TODO.md section 1.7, complete. + * Linked list. * * The two confirmed list defects are fixed, so the tests that used to live in * tests/test_list_append_chain.c and tests/test_list_iterate_head.c are folded @@ -59,7 +59,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *record_visit(aksl_ListNode *node, void /* ---------------------------------------------------------------------- */ /* - * TODO.md 2.2.14: every caller used to have to remember to memset a node before + * every caller used to have to remember to memset a node before * its first use, and a stack node that skipped it walked straight into garbage. */ static int test_node_init_zeroes_the_links(void) @@ -103,7 +103,7 @@ static int test_append_single_node(void) * The defect that made this library's list unusable: `tail` was assigned from * Floyd's `slow` cursor *before* slow advanced, so it tracked the node behind * the midpoint rather than the last node. Appending n1..n4 to n0 produced the - * chain "n0 -> n4" and silently dropped n1, n2 and n3. TODO.md 2.1.1. + * chain "n0 -> n4" and silently dropped n1, n2 and n3. */ static int test_append_builds_the_whole_chain(void) { @@ -218,7 +218,7 @@ static int test_append_detects_cycle_below_the_head(void) } /* - * TODO.md 1.7 asked for the aliasing contract to be defined. It is refusal: + * The wrapper plan asked for the aliasing contract to be defined. It is refusal: * relinking a node that is already in the list would orphan everything between * its old position and the tail, so the tail walk -- which happens anyway -- * doubles as the check. @@ -281,7 +281,7 @@ static int test_iterate_single_node(void) * Every node, exactly once, in order, starting at the head. The cycle check * leaves Floyd's `slow` cursor at the list midpoint, and the visiting loop used * to start from there -- so the whole first half of the list, head included, was - * never passed to the callback at all. TODO.md 2.1.2. + * never passed to the callback at all. */ static int test_iterate_visits_every_node_from_the_head(void) { @@ -470,7 +470,7 @@ static int test_pop_middle_node(void) } /* - * TODO.md 2.2.12: popping the head used to leave the caller's own head pointer + * popping the head used to leave the caller's own head pointer * aimed at a node that was no longer in the list, with no way to learn the new * one. That is what the head out-param is for, and this is the assertion. */ @@ -572,7 +572,7 @@ static int test_pop_then_iterate(void) } /* - * TODO.md 1.7's pool-accounting case. AKSL_RUN already asserts that each test + * The wrapper plan's pool-accounting case. AKSL_RUN already asserts that each test * leaves the pool as it found it; this one drives enough failures in a row to * exhaust the pool several times over, which is where a wrapper that raises an * error and forgets to release it shows up as an outright exhaustion rather than diff --git a/tests/test_memory.c b/tests/test_memory.c index e3f4e66..d11aee3 100644 --- a/tests/test_memory.c +++ b/tests/test_memory.c @@ -1,8 +1,8 @@ /* - * Memory wrappers -- TODO.md section 1.1, now complete, plus the additions from + * Memory wrappers, complete, plus the additions from * section 3.1. * - * The three cases 1.1 left open are all pinned here: malloc(0) is AKERR_VALUE + * The three cases the wrapper plan left open are all pinned here: malloc(0) is AKERR_VALUE * rather than whatever errno happened to hold when the platform's malloc(0) * returned NULL; an allocation the system cannot satisfy reports ENOMEM and * leaves *dst NULL rather than garbage; and overlapping memcpy is refused with @@ -32,7 +32,7 @@ static int test_malloc_rejects_null_destination(void) } /* - * TODO.md 1.1 asked for this contract to be pinned down. malloc(0) is allowed to + * The wrapper plan asked for this contract to be pinned down. malloc(0) is allowed to * return either a unique pointer or NULL, and a NULL there is not a failure and * need not set errno -- so the old wrapper could raise an error whose status was * 0, which every DETECT downstream reads as success while the context holds a @@ -296,7 +296,7 @@ static int test_memcpy_zero_length_is_noop(void) } /* - * TODO.md 1.1's open question, decided: overlap is AKERR_VALUE. memcpy(3) calls + * The wrapper plan's open question, decided: overlap is AKERR_VALUE. memcpy(3) calls * it undefined behaviour, which in practice means "works until the day a * compiler version or a length changes and it does not". Callers who mean to * overlap want aksl_memmove, and the message says so. diff --git a/tests/test_path.c b/tests/test_path.c index b870d1e..f768349 100644 --- a/tests/test_path.c +++ b/tests/test_path.c @@ -1,12 +1,12 @@ /* - * aksl_realpath and aksl_realpath_alloc -- TODO.md section 1.5, now complete. + * aksl_realpath and aksl_realpath_alloc. * * The happy paths compare against realpath(3) itself rather than against a * hard-coded string, because $TMPDIR may itself be a symlink (/tmp -> /private/tmp * and friends) and the resolved answer is what the platform says it is. * * The failure cases now pass an *uninitialised* resolved_path on purpose. That - * used to be the crash case (TODO.md 2.1.6): the wrapper's own error path + * used to be the crash case: the wrapper's own error path * formatted the buffer with %s while realpath(3) leaves its contents * unspecified on failure, so the library read uninitialised memory while * reporting an error. The message names only the input path now, and this test @@ -122,7 +122,7 @@ static int test_rejects_null_arguments(void) AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_realpath(NULL, resolved, sizeof(resolved)), AKERR_NULLPOINTER, "path="); /* - * TODO.md 2.1.6: this used to be unchecked, and realpath(path, NULL) + * this used to be unchecked, and realpath(path, NULL) * allocated a buffer that the wrapper then discarded and leaked. */ AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_realpath("/tmp", NULL, PATH_MAX), diff --git a/tests/test_pool.c b/tests/test_pool.c index 4509be8..c22869c 100644 --- a/tests/test_pool.c +++ b/tests/test_pool.c @@ -1,5 +1,5 @@ /* - * Cross-cutting properties every wrapper has to have -- TODO.md section 1.9. + * Cross-cutting properties every wrapper has to have. * * Two of them, and neither is about what any individual function computes: * diff --git a/tests/test_strbuf.c b/tests/test_strbuf.c index 4e25ae2..640770e 100644 --- a/tests/test_strbuf.c +++ b/tests/test_strbuf.c @@ -1,5 +1,5 @@ /* - * The growable string buffer -- src/collections.c, TODO.md 3.6. + * The growable string buffer -- src/collections.c. * * The bounded formatting wrappers are the right answer when the destination is * a fixed buffer and no answer at all when the length is not known in advance. diff --git a/tests/test_stream.c b/tests/test_stream.c index 5a9833f..8c2a67a 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1,7 +1,7 @@ /* * Stream wrappers: aksl_fopen / aksl_fread / aksl_fwrite / aksl_fclose. * - * TODO.md section 1.2, now complete. The happy paths, the round trip, every + * Stream wrappers, complete. The happy paths, the round trip, every * NULL guard, both stream-error statuses, the transferred-member count that * aksl_fread and aksl_fwrite report through nmemb_out, and the three cases that * needed a hostile file to produce: a mode-denied path (EACCES), a full device @@ -81,7 +81,7 @@ static int test_fopen_rejects_null_arguments(void) AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fopen(path, "r", NULL), AKERR_NULLPOINTER, "fp="); - /* TODO.md 2.2.2: both of these used to go straight through to fopen(3). */ + /* both of these used to go straight through to fopen(3). */ AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fopen(NULL, "r", &fp), AKERR_NULLPOINTER, "pathname="); AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fopen(path, NULL, &fp), @@ -144,7 +144,7 @@ static int test_fread_short_read_is_eof_and_reports_the_count(void) AKSL_CHECK_OK(aksl_fopen(path, "r", &fp)); AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fread(buf, 1, sizeof(buf), fp, &moved), AKERR_EOF, "EOF"); - /* TODO.md 2.2.3: this is what the caller could not previously find out. */ + /* this is what the caller could not previously find out. */ AKSL_CHECK(moved == 4); AKSL_CHECK_OK(aksl_fclose(fp)); @@ -160,7 +160,7 @@ static int test_fread_short_read_is_eof_and_reports_the_count(void) * * That is a change from the old wrapper, which read ferror() and reported * AKERR_IO without ever consulting errno. Routing it through AKSL_ERRNO_OR - * (TODO.md 2.2.1) keeps AKERR_IO as the fallback for the case where the stream + * keeps AKERR_IO as the fallback for the case where the stream * is in error and errno says nothing, and hands back the real reason otherwise. */ static int test_fread_from_write_only_stream_reports_errno(void) @@ -194,7 +194,7 @@ static int test_fread_rejects_null_arguments(void) AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fread(buf, 1, sizeof(buf), NULL, &moved), AKERR_NULLPOINTER, "fp="); - /* TODO.md 2.2.3: ptr was never checked in either direction. */ + /* ptr was never checked in either direction. */ AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fread(NULL, 1, sizeof(buf), fp, &moved), AKERR_NULLPOINTER, "ptr="); AKSL_CHECK_STATUS_MSG_CONTAINS(aksl_fread(buf, 1, sizeof(buf), fp, NULL), diff --git a/tests/test_streamio.c b/tests/test_streamio.c index cb090be..7312448 100644 --- a/tests/test_streamio.c +++ b/tests/test_streamio.c @@ -1,5 +1,5 @@ /* - * Stream wrappers beyond open/read/write/close -- src/stream.c, TODO.md 3.1. + * Stream wrappers beyond open/read/write/close -- src/stream.c. * * tests/test_stream.c covers fopen/fread/fwrite/fclose. This one covers * positioning, flushing, character and line I/O, stream state, and formatted diff --git a/tests/test_strhash.c b/tests/test_strhash.c index fb90db1..5ab4dca 100644 --- a/tests/test_strhash.c +++ b/tests/test_strhash.c @@ -1,5 +1,5 @@ /* - * aksl_strhash_djb2 -- TODO.md section 1.6. + * aksl_strhash_djb2. * * The expected values are the canonical djb2 ones: h = 5381, then * h = h * 33 + byte for each of len bytes, truncated to 32 bits. They were @@ -7,7 +7,7 @@ * * Most vectors here are 7-bit ASCII, where signed and unsigned char agree and * the test therefore says nothing either way about byte signedness. The high-bit - * vector is the one that pins TODO.md 2.2.6 down. + * vector is the one that pins the sign-extension defect down. */ #include "aksl_capture.h" @@ -47,7 +47,7 @@ static int test_known_answer_vectors(void) } /* - * TODO.md 2.2.6, pinned. The cursor is an unsigned char * now, so bytes at or + * Pinned. The cursor is an unsigned char * now, so bytes at or * above 0x80 contribute their unsigned value. Iterating a plain char * on x86 or * ARM Linux made them negative, giving 5859874 here instead of 5868578 -- a hash * that disagreed with canonical djb2 and, worse, disagreed with itself across @@ -68,7 +68,7 @@ static int test_high_bit_bytes_are_unsigned(void) return 0; } -/* The NUL-terminated convenience form (TODO.md 3.6) agrees with the length one. */ +/* The NUL-terminated convenience form agrees with the length one. */ static int test_str_form_matches_the_length_form(void) { const char *s = "libakstdlib"; diff --git a/tests/test_string.c b/tests/test_string.c index 620ed4c..b453b24 100644 --- a/tests/test_string.c +++ b/tests/test_string.c @@ -1,5 +1,5 @@ /* - * String wrappers -- src/string.c, TODO.md section 3.1. + * String wrappers -- src/string.c. * * The two contracts worth testing hardest are the ones that differ from libc: * every copying function takes the destination size and treats truncation as an diff --git a/tests/test_strto.c b/tests/test_strto.c index ea98800..ff84461 100644 --- a/tests/test_strto.c +++ b/tests/test_strto.c @@ -1,5 +1,5 @@ /* - * The strto* family -- TODO.md section 3.1. + * The strto* family. * * These are the real implementation behind the ato* wrappers and the thing * akbasic had to hand-write for itself (its src/convert.c, ~60 lines) because diff --git a/tests/test_tree.c b/tests/test_tree.c index 339fb1b..93a00e4 100644 --- a/tests/test_tree.c +++ b/tests/test_tree.c @@ -1,5 +1,5 @@ /* - * Tree traversal -- TODO.md section 1.8, complete. + * Tree traversal. * * The old version of this file counted steps, which cannot tell the three * depth-first orders apart because all three visit all seven nodes -- and could @@ -183,7 +183,7 @@ static int test_dfs_is_an_alias_for_preorder(void) /* * BFS was AKERR_NOT_IMPLEMENTED, and the lalloc/lfree parameters that existed to - * serve it were defaulted and then never called -- TODO.md 2.2.8 and 2.2.10. + * serve it were defaulted and then never called. See UPGRADING.md. * Both modes work now, and the allocator test below proves the queue is real. */ static int test_bfs_visits_level_by_level(void) @@ -249,7 +249,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *counting_free(void *ptr) } /* - * TODO.md 1.8: "Custom lalloc/lfree are actually invoked -- currently they are + * The wrapper plan asked that "custom lalloc/lfree are actually invoked -- currently they are * stored and never called". They are called now, once per node enqueued, and * every allocation is released. The depth-first modes allocate nothing at all, * which is the other half of the contract. @@ -382,7 +382,7 @@ static int test_degenerate_chains(void) } /* - * TODO.md 1.8 / 2.2.7: a chain deeper than the recursion can take. It used to + * A chain deeper than the recursion can take. It used to * overflow the stack; it is AKERR_OUTOFBOUNDS now, and the message names the * documented limit. Built one node past the cap so the failure is the cap itself * and not some incidental shortfall. `static` because AKSL_TREE_MAX_DEPTH nodes @@ -488,7 +488,7 @@ static int test_cyclic_tree_is_caught(void) * that raised the break handled it in its own PROCESS/HANDLE block and returned * success, so the parent frame's PASS saw nothing wrong and carried straight on * into the sibling subtree. All seven nodes were visited no matter where the - * break was raised. TODO.md 2.1.3. + * break was raised. * * One case per order, each breaking on a node that is *not* last in that order -- * which is precisely what the old test could not do, because it hid its target @@ -579,7 +579,7 @@ static int test_null_arguments(void) } /* - * TODO.md 2.2.9: the switch had no default, so an unrecognised mode -- and + * the switch had no default, so an unrecognised mode -- and * AKSL_TREE_SEARCH_VISIT, which the header documented but nothing implemented -- * fell straight through to SUCCEED_RETURN having visited nothing at all. A * traversal that silently did not happen, reported as success. diff --git a/tests/test_version.c b/tests/test_version.c index 53177d0..89c65ba 100644 --- a/tests/test_version.c +++ b/tests/test_version.c @@ -1,5 +1,5 @@ /* - * Version reporting -- TODO.md section 2.2.16. + * Version reporting. * * There are two versions in play and the whole point of this API is that they * are allowed to differ: