Give every exported function a declaration, and check that it stays that way
Closes internal-consistency items 7 through 15. Nineteen non-static functions were in the ABI with no declaration anywhere, so no consumer could call them and any consumer could collide with them. The four gamepad_handle_* functions are the ones that mattered: controller.h declared akgl_controller_handle_button_down and three siblings that did not exist, so anything compiled against the header alone failed to link. The definitions carry the declared names now, which also closes Defects -> Known and still open item 10, and their documentation moved to the header. The rest are either declared under a "part of the internal API" block -- akgl_game_save_actors and akgl_game_load_versioncmp, which tests/game.c had to declare for itself, plus six tilemap loader helpers the untested-loader work wants to reach -- or static, which is what the four save iterators and load_objectnamemap should always have been. akgl_path_relative_from is deleted: declared nowhere, called from nowhere, never wrote its output, and leaked a pooled string on every call, so it closes Known and still open item 4 and item 40 by ceasing to exist. scripts/check_api_surface.sh keeps it closed. It reads the built library's dynamic symbol table and every public header with comments stripped, and fails on an exported akgl_* symbol that is declared nowhere. Stripping comments is the whole point -- four of these were mentioned in controller.h prose, which is how they went unnoticed. The pool-size ceilings are defined once, in heap.h, so the #ifndef override hook fires for the first time; actor.h, sprite.h and character.h were defining the same four unconditionally from headers heap.h includes above its own guard. tests/header_pool_override.c fails the compile if that regresses. Also here: (void) rather than () on the twelve no-argument entry points, AKERR_NOIGNORE only on declarations, static helpers with the akgl_ prefix dropped, and the six parameter-name mismatches. akgl_get_json_with_default had its two contexts swapped rather than merely misspelled -- the incoming one was `err` and its own was `e`, which is the name reserved for an incoming one. 24/24 pass, reindent --check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,16 +24,6 @@
|
||||
|
||||
#include "testutil.h"
|
||||
|
||||
/*
|
||||
* akgl/controller.h declares these as akgl_controller_handle_*, but src has
|
||||
* always defined them as gamepad_handle_*. Declared here under the names that
|
||||
* actually link, so the tests can reach them without renaming shipped symbols.
|
||||
*/
|
||||
akerr_ErrorContext *gamepad_handle_button_down(void *appstate, SDL_Event *event);
|
||||
akerr_ErrorContext *gamepad_handle_button_up(void *appstate, SDL_Event *event);
|
||||
akerr_ErrorContext *gamepad_handle_added(void *appstate, SDL_Event *event);
|
||||
akerr_ErrorContext *gamepad_handle_removed(void *appstate, SDL_Event *event);
|
||||
|
||||
/** @brief Keyboard id the tests bind their control maps to. */
|
||||
#define TEST_KBID 11
|
||||
/** @brief Gamepad id the tests bind their control maps to. */
|
||||
@@ -424,7 +414,7 @@ akerr_ErrorContext *test_controller_gamepad_button_handlers(void)
|
||||
player->state = 0;
|
||||
player->movement_controls_face = false;
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_down(&appstate_placeholder, &event),
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_down(&appstate_placeholder, &event),
|
||||
"dpad down press handler");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HAS(player->state, AKGL_ACTOR_STATE_MOVING_DOWN),
|
||||
"the dpad down handler did not set MOVING_DOWN (state %d)", player->state);
|
||||
@@ -432,7 +422,7 @@ akerr_ErrorContext *test_controller_gamepad_button_handlers(void)
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HAS(player->state, AKGL_ACTOR_STATE_FACE_DOWN),
|
||||
"the dpad down handler did not set FACE_DOWN (state %d)", player->state);
|
||||
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_up(&appstate_placeholder, &event),
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_up(&appstate_placeholder, &event),
|
||||
"dpad down release handler");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HASNOT(player->state, AKGL_ACTOR_STATE_MOVING_DOWN),
|
||||
"the dpad down release handler did not clear MOVING_DOWN (state %d)", player->state);
|
||||
@@ -441,55 +431,55 @@ akerr_ErrorContext *test_controller_gamepad_button_handlers(void)
|
||||
|
||||
player->state = 0;
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_UP);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_down(&appstate_placeholder, &event), "dpad up press handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_down(&appstate_placeholder, &event), "dpad up press handler");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HAS(player->state, AKGL_ACTOR_STATE_MOVING_UP),
|
||||
"the dpad up handler did not set MOVING_UP (state %d)", player->state);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_up(&appstate_placeholder, &event), "dpad up release handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_up(&appstate_placeholder, &event), "dpad up release handler");
|
||||
|
||||
player->state = 0;
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_LEFT);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_down(&appstate_placeholder, &event), "dpad left press handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_down(&appstate_placeholder, &event), "dpad left press handler");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HAS(player->state, AKGL_ACTOR_STATE_MOVING_LEFT),
|
||||
"the dpad left handler did not set MOVING_LEFT (state %d)", player->state);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_up(&appstate_placeholder, &event), "dpad left release handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_up(&appstate_placeholder, &event), "dpad left release handler");
|
||||
|
||||
player->state = 0;
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_RIGHT);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_down(&appstate_placeholder, &event), "dpad right press handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_down(&appstate_placeholder, &event), "dpad right press handler");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HAS(player->state, AKGL_ACTOR_STATE_MOVING_RIGHT),
|
||||
"the dpad right handler did not set MOVING_RIGHT (state %d)", player->state);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_up(&appstate_placeholder, &event), "dpad right release handler");
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_up(&appstate_placeholder, &event), "dpad right release handler");
|
||||
|
||||
// With automatic facing on, the handler leaves facing to the actor's own
|
||||
// face function.
|
||||
player->state = 0;
|
||||
player->movement_controls_face = true;
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_button_down(&appstate_placeholder, &event),
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_button_down(&appstate_placeholder, &event),
|
||||
"dpad down press with automatic facing on");
|
||||
TEST_ASSERT(e, AKGL_BITMASK_HASNOT(player->state, AKGL_ACTOR_STATE_FACE_DOWN),
|
||||
"the handler set facing even though the actor faces automatically (state %d)",
|
||||
player->state);
|
||||
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, gamepad_handle_button_down(NULL, &event),
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, akgl_controller_handle_button_down(NULL, &event),
|
||||
"dpad press handler with a NULL appstate");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_button_down(&appstate_placeholder, NULL),
|
||||
akgl_controller_handle_button_down(&appstate_placeholder, NULL),
|
||||
"dpad press handler with a NULL event");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, gamepad_handle_button_up(NULL, &event),
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, akgl_controller_handle_button_up(NULL, &event),
|
||||
"dpad release handler with a NULL appstate");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_button_up(&appstate_placeholder, NULL),
|
||||
akgl_controller_handle_button_up(&appstate_placeholder, NULL),
|
||||
"dpad release handler with a NULL event");
|
||||
|
||||
// With no actor named "player" registered there is nothing to drive.
|
||||
CATCH(e, akgl_registry_init_actor());
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_BUTTON_DOWN, TEST_JSID, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_button_down(&appstate_placeholder, &event),
|
||||
akgl_controller_handle_button_down(&appstate_placeholder, &event),
|
||||
"dpad press handler with no player actor registered");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_button_up(&appstate_placeholder, &event),
|
||||
akgl_controller_handle_button_up(&appstate_placeholder, &event),
|
||||
"dpad release handler with no player actor registered");
|
||||
} CLEANUP {
|
||||
} PROCESS(e) {
|
||||
@@ -506,22 +496,22 @@ akerr_ErrorContext *test_controller_device_events(void)
|
||||
// The dummy drivers present no gamepads, so the add and remove handlers
|
||||
// take their "unknown device" paths. Neither may crash.
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_ADDED, 999, 0);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_added(&appstate_placeholder, &event),
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_added(&appstate_placeholder, &event),
|
||||
"handling an add for a device that cannot be opened");
|
||||
|
||||
make_button_event(&event, SDL_EVENT_GAMEPAD_REMOVED, 999, 0);
|
||||
TEST_EXPECT_OK(e, gamepad_handle_removed(&appstate_placeholder, &event),
|
||||
TEST_EXPECT_OK(e, akgl_controller_handle_removed(&appstate_placeholder, &event),
|
||||
"handling a remove for a device that was never open");
|
||||
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, gamepad_handle_added(NULL, &event),
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, akgl_controller_handle_added(NULL, &event),
|
||||
"add handler with a NULL appstate");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_added(&appstate_placeholder, NULL),
|
||||
akgl_controller_handle_added(&appstate_placeholder, NULL),
|
||||
"add handler with a NULL event");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, gamepad_handle_removed(NULL, &event),
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER, akgl_controller_handle_removed(NULL, &event),
|
||||
"remove handler with a NULL appstate");
|
||||
TEST_EXPECT_STATUS(e, AKERR_NULLPOINTER,
|
||||
gamepad_handle_removed(&appstate_placeholder, NULL),
|
||||
akgl_controller_handle_removed(&appstate_placeholder, NULL),
|
||||
"remove handler with a NULL event");
|
||||
} CLEANUP {
|
||||
} PROCESS(e) {
|
||||
|
||||
@@ -24,14 +24,6 @@
|
||||
|
||||
#include "testutil.h"
|
||||
|
||||
/*
|
||||
* Exported by src/game.c but not declared in akgl/game.h, because they are
|
||||
* savegame internals rather than part of the supported surface. Declared here
|
||||
* so the tests can reach them without widening the public API.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save_actors(FILE *fp);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(char *versiontype, char *newversion, char *curversion);
|
||||
|
||||
/** @brief Scratch savegame path, created and removed by the tests that use it. */
|
||||
static char savepath[] = "akgl_test_savegame.bin";
|
||||
/** @brief Scratch path for deliberately malformed savegames. */
|
||||
|
||||
42
tests/header_pool_override.c
Normal file
42
tests/header_pool_override.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file header_pool_override.c
|
||||
* @brief Checks that the compile-time pool-size overrides in heap.h actually fire.
|
||||
*
|
||||
* `heap.h` wraps every `AKGL_MAX_HEAP_*` ceiling in an `#ifndef` so a game that
|
||||
* needs more actors can define its own before including it. That mechanism was
|
||||
* dead until 0.5.0: `actor.h`, `sprite.h` and `character.h` defined the same
|
||||
* four unconditionally, and `heap.h` includes all three *above* its own
|
||||
* `#ifndef` block, so whichever landed first won and the guard never fired. The
|
||||
* override was documented, and did nothing.
|
||||
*
|
||||
* The assertion is the compile. Nothing here links against the pools -- it
|
||||
* cannot, because the library was built with the default ceilings and this
|
||||
* translation unit deliberately disagrees with it. That disagreement is the
|
||||
* documented consequence of overriding a ceiling, not something this file is
|
||||
* working around: the arrays are sized at compile time, so the library and
|
||||
* everything linking it have to agree.
|
||||
*/
|
||||
|
||||
#define AKGL_MAX_HEAP_ACTOR 128
|
||||
#define AKGL_MAX_HEAP_STRING 512
|
||||
|
||||
#include <akgl/heap.h>
|
||||
|
||||
#if AKGL_MAX_HEAP_ACTOR != 128
|
||||
#error "heap.h overrode a caller's AKGL_MAX_HEAP_ACTOR; the #ifndef guard is dead again"
|
||||
#endif
|
||||
|
||||
#if AKGL_MAX_HEAP_STRING != 512
|
||||
#error "heap.h overrode a caller's AKGL_MAX_HEAP_STRING; the #ifndef guard is dead again"
|
||||
#endif
|
||||
|
||||
/* The derived ceilings have to follow the override rather than a stale literal. */
|
||||
#if AKGL_MAX_HEAP_SPRITE != (128 * 16)
|
||||
#error "AKGL_MAX_HEAP_SPRITE no longer derives from AKGL_MAX_HEAP_ACTOR"
|
||||
#endif
|
||||
|
||||
int akgl_header_selftest_pool_override(void);
|
||||
int akgl_header_selftest_pool_override(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user