/** * 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 const cutsceneitem_t CUTSCENE_TEST_INTERACT_ITEMS[] = { CUTSCENE_WAIT(1.0f) }; static const cutscene_t CUTSCENE_TEST_INTERACT = { .items = CUTSCENE_TEST_INTERACT_ITEMS, .itemCount = 1, .pause = CUTSCENE_PAUSE_NONE, .dataSize = 0 }; 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); }