/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "dusktest.h" #include "util/memory.h" #include "rpg/entity/entity.h" static void testEntitiesReset(void) { memoryZero(ENTITIES, sizeof(ENTITIES)); } static void testEntityPlace( const uint8_t index, const entitytype_t type, const vec3 position, const entitydir_t direction ) { entityInit(&ENTITIES[index], type); ENTITIES[index].direction = direction; const vec3 extents = ENTITY_PHYSICS_EXTENTS_DEFAULT; physicsBodyInit(&ENTITIES[index].body, position, extents); } static void test_entityGetFacingFindsEntityAhead(void **state) { testEntitiesReset(); testEntityPlace(0, ENTITY_TYPE_PLAYER, (vec3){ 0.0f, 0.0f, 0.0f }, ENTITY_DIR_EAST); testEntityPlace(1, ENTITY_TYPE_NPC, (vec3){ 1.0f, 0.0f, 0.0f }, ENTITY_DIR_NORTH); entity_t *result = entityGetFacing(&ENTITIES[0], ENTITY_INTERACT_RANGE); assert_ptr_equal(result, &ENTITIES[1]); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityGetFacingIgnoresEntityBehind(void **state) { testEntitiesReset(); testEntityPlace(0, ENTITY_TYPE_PLAYER, (vec3){ 0.0f, 0.0f, 0.0f }, ENTITY_DIR_EAST); testEntityPlace(1, ENTITY_TYPE_NPC, (vec3){ -2.0f, 0.0f, 0.0f }, ENTITY_DIR_NORTH); entity_t *result = entityGetFacing(&ENTITIES[0], ENTITY_INTERACT_RANGE); assert_null(result); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityGetFacingIgnoresEntityToSide(void **state) { testEntitiesReset(); testEntityPlace(0, ENTITY_TYPE_PLAYER, (vec3){ 0.0f, 0.0f, 0.0f }, ENTITY_DIR_EAST); testEntityPlace(1, ENTITY_TYPE_NPC, (vec3){ 0.0f, 3.0f, 0.0f }, ENTITY_DIR_NORTH); entity_t *result = entityGetFacing(&ENTITIES[0], ENTITY_INTERACT_RANGE); assert_null(result); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityGetFacingReturnsNullWhenNothingInRange(void **state) { testEntitiesReset(); testEntityPlace(0, ENTITY_TYPE_PLAYER, (vec3){ 0.0f, 0.0f, 0.0f }, ENTITY_DIR_EAST); entity_t *result = entityGetFacing(&ENTITIES[0], ENTITY_INTERACT_RANGE); assert_null(result); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityGetFacingPicksNearest(void **state) { testEntitiesReset(); testEntityPlace(0, ENTITY_TYPE_PLAYER, (vec3){ 0.0f, 0.0f, 0.0f }, ENTITY_DIR_EAST); // Farther candidate placed at the lower array index, to prove the // result is chosen by distance, not array/insertion order. testEntityPlace(1, ENTITY_TYPE_NPC, (vec3){ 1.5f, 0.0f, 0.0f }, ENTITY_DIR_NORTH); testEntityPlace(2, ENTITY_TYPE_NPC, (vec3){ 1.0f, 0.0f, 0.0f }, ENTITY_DIR_NORTH); entity_t *result = entityGetFacing(&ENTITIES[0], ENTITY_INTERACT_RANGE); assert_ptr_equal(result, &ENTITIES[2]); assert_int_equal(memoryGetAllocatedCount(), 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_entityGetFacingFindsEntityAhead), cmocka_unit_test(test_entityGetFacingIgnoresEntityBehind), cmocka_unit_test(test_entityGetFacingIgnoresEntityToSide), cmocka_unit_test(test_entityGetFacingReturnsNullWhenNothingInRange), cmocka_unit_test(test_entityGetFacingPicksNearest), }; return cmocka_run_group_tests(tests, NULL, NULL); }