cutsceneAppend adds items to the end of a cutscene_t's item array; cutsceneAppendNext inserts them at a given index instead (e.g. CUTSCENE_SYSTEM.currentItem + 1, to run immediately after the currently-executing item), shifting everything from that index onward to make room. Both are capacity-bounded against the caller- supplied itemsMax, matching cutsceneParseDoc's convention of never assuming ownership of the backing buffer's size. cutscene_t.items drops its const qualifier to allow this in-place mutation; cutsceneitem_t backing arrays in the test fixtures that get assigned into a mutable cutscene_t.items are no longer declared const either, since a const source would otherwise silently violate the field's new type. Co-Authored-By: Claude Sonnet 5 <[email protected]>
135 lines
3.8 KiB
C
135 lines
3.8 KiB
C
/**
|
|
* Copyright (c) 2026 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "dusktest.h"
|
|
#include "entitytestfixture.h"
|
|
#include "ui/rpg/textbox/uitextboxmain.h"
|
|
#include "ui/focus/uifocus.h"
|
|
#include "rpg/cutscene/cutscenesystem.h"
|
|
|
|
static cutsceneitem_t CUTSCENE_TEST_INTERACT_ITEMS[] = {
|
|
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 1.0f }
|
|
};
|
|
static const cutscene_t CUTSCENE_TEST_INTERACT = {
|
|
.items = CUTSCENE_TEST_INTERACT_ITEMS,
|
|
.itemCount = 1,
|
|
.pause = CUTSCENE_PAUSE_NONE
|
|
};
|
|
|
|
static entity_t *player;
|
|
static entity_t *target;
|
|
|
|
static void resetInteractFixture(void) {
|
|
entityTestFixtureReset();
|
|
uiFocusInit();
|
|
uiTextboxMainInit();
|
|
uiTextboxMainFocusClosed(NULL);// force-clear stale focus from a prior test
|
|
cutsceneSystemInit();
|
|
|
|
entityInit(&ENTITIES[0], ENTITY_TYPE_PLAYER);
|
|
entityInit(&ENTITIES[1], ENTITY_TYPE_NPC);
|
|
player = &ENTITIES[0];
|
|
target = &ENTITIES[1];
|
|
player->direction = ENTITY_DIR_NORTH;
|
|
}
|
|
|
|
static void test_entityInteractWithNull(void **state) {
|
|
|
|
resetInteractFixture();
|
|
|
|
target->interact.type = ENTITY_INTERACT_NULL;
|
|
entityInteractWith(player, target);// should not crash or change anything
|
|
assert_int_equal(target->interact.type, ENTITY_INTERACT_NULL);
|
|
}
|
|
|
|
static void test_entityInteractWithPrintTurnsNpcToFacePlayer(void **state) {
|
|
|
|
resetInteractFixture();
|
|
|
|
target->interact.type = ENTITY_INTERACT_PRINT;
|
|
target->interact.data.message = "Hello!";
|
|
|
|
entityInteractWith(player, target);
|
|
|
|
assert_true(uiTextboxMainIsActive());
|
|
assert_int_equal(
|
|
target->data.npc.interactState, NPC_INTERACT_STATE_CONVERSING
|
|
);
|
|
// NPC turns to face the opposite of the player's facing direction.
|
|
assert_int_equal(target->direction, entityDirGetOpposite(player->direction));
|
|
}
|
|
|
|
static entity_t *callbackPlayerArg;
|
|
static entity_t *callbackTargetArg;
|
|
static uint8_t callbackCount;
|
|
|
|
static void recordInteractCallback(entity_t *p, entity_t *t) {
|
|
callbackPlayerArg = p;
|
|
callbackTargetArg = t;
|
|
callbackCount++;
|
|
}
|
|
|
|
static void test_entityInteractWithCallback(void **state) {
|
|
|
|
resetInteractFixture();
|
|
callbackCount = 0;
|
|
|
|
target->interact.type = ENTITY_INTERACT_CALLBACK;
|
|
target->interact.data.callback = recordInteractCallback;
|
|
|
|
entityInteractWith(player, target);
|
|
|
|
assert_int_equal(callbackCount, 1);
|
|
assert_ptr_equal(callbackPlayerArg, player);
|
|
assert_ptr_equal(callbackTargetArg, target);
|
|
}
|
|
|
|
static void test_entityInteractWithCallbackRequiresNonNull(void **state) {
|
|
|
|
resetInteractFixture();
|
|
|
|
target->interact.type = ENTITY_INTERACT_CALLBACK;
|
|
target->interact.data.callback = NULL;
|
|
|
|
expect_assert_failure(entityInteractWith(player, target));
|
|
}
|
|
|
|
static void test_entityInteractWithCutsceneStartsIt(void **state) {
|
|
|
|
resetInteractFixture();
|
|
|
|
target->interact.type = ENTITY_INTERACT_CUTSCENE;
|
|
target->interact.data.cutscene = &CUTSCENE_TEST_INTERACT;
|
|
|
|
entityInteractWith(player, target);
|
|
|
|
assert_ptr_equal(CUTSCENE_SYSTEM.scene, &CUTSCENE_TEST_INTERACT);
|
|
assert_ptr_equal(CUTSCENE_SYSTEM.entityInteract, player);
|
|
assert_ptr_equal(CUTSCENE_SYSTEM.entityInteracted, target);
|
|
}
|
|
|
|
static void test_entityInteractWithRequiresNonNullEntities(void **state) {
|
|
|
|
resetInteractFixture();
|
|
|
|
expect_assert_failure(entityInteractWith(NULL, target));
|
|
expect_assert_failure(entityInteractWith(player, NULL));
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test(test_entityInteractWithNull),
|
|
cmocka_unit_test(test_entityInteractWithPrintTurnsNpcToFacePlayer),
|
|
cmocka_unit_test(test_entityInteractWithCallback),
|
|
cmocka_unit_test(test_entityInteractWithCallbackRequiresNonNull),
|
|
cmocka_unit_test(test_entityInteractWithCutsceneStartsIt),
|
|
cmocka_unit_test(test_entityInteractWithRequiresNonNullEntities),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|