/** * 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 "entity/entitymanager.h" #include "entity/component/display/entityposition.h" static void test_entityPositionLocalGetSet(void **state) { entitymanager_t mgr; entityManagerInit(&mgr); entityid_t entity = entityManagerAdd(&mgr); componentid_t comp = entityAddComponent( &mgr, entity, COMPONENT_TYPE_POSITION ); vec3 setPos = { 1.0f, 2.0f, 3.0f }; entityPositionSetLocalPosition(&mgr, entity, comp, setPos); vec3 getPos; entityPositionGetLocalPosition(&mgr, entity, comp, getPos); assert_float_equal(getPos[0], 1.0f, 0.0001f); assert_float_equal(getPos[1], 2.0f, 0.0001f); assert_float_equal(getPos[2], 3.0f, 0.0001f); // World position of a parentless entity matches local position. vec3 worldPos; entityPositionGetWorldPosition(&mgr, entity, comp, worldPos); assert_float_equal(worldPos[0], 1.0f, 0.0001f); assert_float_equal(worldPos[1], 2.0f, 0.0001f); assert_float_equal(worldPos[2], 3.0f, 0.0001f); entityManagerDispose(&mgr); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityPositionParentChildWorldTransform(void **state) { entitymanager_t mgr; entityManagerInit(&mgr); entityid_t parent = entityManagerAdd(&mgr); componentid_t parentComp = entityAddComponent( &mgr, parent, COMPONENT_TYPE_POSITION ); entityid_t child = entityManagerAdd(&mgr); componentid_t childComp = entityAddComponent( &mgr, child, COMPONENT_TYPE_POSITION ); vec3 parentPos = { 10.0f, 0.0f, 0.0f }; entityPositionSetLocalPosition(&mgr, parent, parentComp, parentPos); vec3 childLocalPos = { 1.0f, 0.0f, 0.0f }; entityPositionSetLocalPosition(&mgr, child, childComp, childLocalPos); entityPositionSetParent(&mgr, child, childComp, parent, parentComp); vec3 childWorldPos; entityPositionGetWorldPosition(&mgr, child, childComp, childWorldPos); assert_float_equal(childWorldPos[0], 11.0f, 0.0001f); assert_float_equal(childWorldPos[1], 0.0f, 0.0001f); assert_float_equal(childWorldPos[2], 0.0f, 0.0001f); // Moving the parent should lazily update the child's world position too. vec3 parentPosMoved = { 20.0f, 5.0f, 0.0f }; entityPositionSetLocalPosition(&mgr, parent, parentComp, parentPosMoved); entityPositionGetWorldPosition(&mgr, child, childComp, childWorldPos); assert_float_equal(childWorldPos[0], 21.0f, 0.0001f); assert_float_equal(childWorldPos[1], 5.0f, 0.0001f); assert_float_equal(childWorldPos[2], 0.0f, 0.0001f); // Detaching does not preserve world position -- the child's local // position (never touched since entityPositionSetLocalPosition above) is // now its world position too, since it no longer has a parent. entityPositionSetParent( &mgr, child, childComp, ENTITY_ID_INVALID, COMPONENT_ID_INVALID ); vec3 parentPosMovedAgain = { 100.0f, 100.0f, 100.0f }; entityPositionSetLocalPosition( &mgr, parent, parentComp, parentPosMovedAgain ); entityPositionGetWorldPosition(&mgr, child, childComp, childWorldPos); assert_float_equal(childWorldPos[0], childLocalPos[0], 0.0001f); assert_float_equal(childWorldPos[1], childLocalPos[1], 0.0001f); assert_float_equal(childWorldPos[2], childLocalPos[2], 0.0001f); entityManagerDispose(&mgr); assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_entityPositionDisposeDeep(void **state) { entitymanager_t mgr; entityManagerInit(&mgr); entityid_t parent = entityManagerAdd(&mgr); componentid_t parentComp = entityAddComponent( &mgr, parent, COMPONENT_TYPE_POSITION ); entityid_t child = entityManagerAdd(&mgr); componentid_t childComp = entityAddComponent( &mgr, child, COMPONENT_TYPE_POSITION ); entityPositionSetParent(&mgr, child, childComp, parent, parentComp); entityPositionDisposeDeep(&mgr, parent, parentComp); assert_true((mgr.entities[parent].state & ENTITY_STATE_ACTIVE) == 0); assert_true((mgr.entities[child].state & ENTITY_STATE_ACTIVE) == 0); entityManagerDispose(&mgr); assert_int_equal(memoryGetAllocatedCount(), 0); } int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_entityPositionLocalGetSet), cmocka_unit_test(test_entityPositionParentChildWorldTransform), cmocka_unit_test(test_entityPositionDisposeDeep), }; return cmocka_run_group_tests(tests, NULL, NULL); }