/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "dusktest.h" #include "entity/entitymanager.h" #include "entity/entity.h" #include "entity/entityjson.h" #include "entity/component.h" #include "entity/component/display/entityposition.h" #include "entity/component/display/entitycamera.h" #include "entity/component/display/entityrenderable.h" #include "entity/component/physics/entityphysics.h" #include "entity/component/trigger/entitytrigger.h" #include "util/memory.h" #include "log/log.h" #include static void test_entityjson_load(void **state) { yyjson_read_err readErr; yyjson_doc *doc = yyjson_read_file( DUSK_ENTITY_JSON_PATH, 0, NULL, &readErr ); assert_non_null(doc); yyjson_val *root = yyjson_doc_get_root(doc); assert_non_null(root); entityid_t entId = entityManagerAdd(); entityInit(entId); errorret_t ret = entityDeserialize(entId, root); assert_true(errorIsOk(ret)); logDebug("Loaded entity from: %s\n", DUSK_ENTITY_JSON_PATH); // Position componentid_t posComp = entityGetComponent(entId, COMPONENT_TYPE_POSITION); assert_int_not_equal(posComp, COMPONENT_ID_INVALID); entityposition_t *pos = componentGetData( entId, posComp, COMPONENT_TYPE_POSITION ); logDebug(" position:\n"); logDebug( " position: [%f, %f, %f]\n", pos->position[0], pos->position[1], pos->position[2] ); logDebug( " rotation: [%f, %f, %f]\n", pos->rotation[0], pos->rotation[1], pos->rotation[2] ); logDebug( " scale: [%f, %f, %f]\n", pos->scale[0], pos->scale[1], pos->scale[2] ); assert_float_equal(pos->position[0], 0.0f, 0.0001f); assert_float_equal(pos->position[1], 0.0f, 0.0001f); assert_float_equal(pos->position[2], 0.0f, 0.0001f); assert_float_equal(pos->scale[0], 1.0f, 0.0001f); assert_float_equal(pos->scale[1], 1.0f, 0.0001f); assert_float_equal(pos->scale[2], 1.0f, 0.0001f); // Camera componentid_t camComp = entityGetComponent(entId, COMPONENT_TYPE_CAMERA); assert_int_not_equal(camComp, COMPONENT_ID_INVALID); entitycamera_t *cam = componentGetData( entId, camComp, COMPONENT_TYPE_CAMERA ); const char_t *projStr = "orthographic"; if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE) { projStr = "perspective"; } else if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) { projStr = "perspective_flipped"; } logDebug(" camera:\n"); logDebug(" projType: %s\n", projStr); logDebug(" fov: %f\n", cam->perspective.fov); logDebug(" nearClip: %f\n", cam->nearClip); logDebug(" farClip: %f\n", cam->farClip); assert_int_equal( cam->projType, ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE ); assert_float_equal(cam->perspective.fov, 45.0f, 0.0001f); assert_float_equal(cam->nearClip, 0.1f, 0.0001f); assert_float_equal(cam->farClip, 5000.0f, 0.1f); // Renderable componentid_t rendComp = entityGetComponent( entId, COMPONENT_TYPE_RENDERABLE ); assert_int_not_equal(rendComp, COMPONENT_ID_INVALID); entityrenderable_t *rend = componentGetData( entId, rendComp, COMPONENT_TYPE_RENDERABLE ); const char_t *rendTypeStr = "custom"; if(rend->type == ENTITY_RENDERABLE_TYPE_SPRITEBATCH) { rendTypeStr = "spritebatch"; } else if(rend->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL) { rendTypeStr = "shader_material"; } logDebug(" renderable:\n"); logDebug(" type: %s\n", rendTypeStr); logDebug(" priority: %d\n", (int_t)rend->priority); logDebug( " shaderType: %d\n", (int_t)rend->data.material.shaderType ); logDebug( " stateFlags: %d\n", (int_t)rend->data.material.state.flags ); assert_int_equal(rend->type, ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL); assert_int_equal(rend->priority, 0); // Physics componentid_t physComp = entityGetComponent(entId, COMPONENT_TYPE_PHYSICS); assert_int_not_equal(physComp, COMPONENT_ID_INVALID); entityphysics_t *phys = componentGetData( entId, physComp, COMPONENT_TYPE_PHYSICS ); const char_t *bodyStr = "static"; if(phys->type == PHYSICS_BODY_DYNAMIC) { bodyStr = "dynamic"; } else if(phys->type == PHYSICS_BODY_KINEMATIC) { bodyStr = "kinematic"; } const char_t *shapeStr = "cube"; if(phys->shape.type == PHYSICS_SHAPE_SPHERE) { shapeStr = "sphere"; } else if(phys->shape.type == PHYSICS_SHAPE_CAPSULE) { shapeStr = "capsule"; } else if(phys->shape.type == PHYSICS_SHAPE_PLANE) { shapeStr = "plane"; } logDebug(" physics:\n"); logDebug(" bodyType: %s\n", bodyStr); logDebug(" shapeType: %s\n", shapeStr); logDebug(" gravityScale: %f\n", phys->gravityScale); assert_int_equal(phys->type, PHYSICS_BODY_DYNAMIC); assert_int_equal(phys->shape.type, PHYSICS_SHAPE_CUBE); assert_float_equal(phys->gravityScale, 1.0f, 0.0001f); // Trigger componentid_t trigComp = entityGetComponent( entId, COMPONENT_TYPE_TRIGGER ); assert_int_not_equal(trigComp, COMPONENT_ID_INVALID); entitytrigger_t *trig = componentGetData( entId, trigComp, COMPONENT_TYPE_TRIGGER ); logDebug(" trigger:\n"); logDebug( " min: [%f, %f, %f]\n", trig->min[0], trig->min[1], trig->min[2] ); logDebug( " max: [%f, %f, %f]\n", trig->max[0], trig->max[1], trig->max[2] ); assert_float_equal(trig->min[0], -0.5f, 0.0001f); assert_float_equal(trig->max[0], 0.5f, 0.0001f); entityDispose(entId); yyjson_doc_free(doc); assert_int_equal(memoryGetAllocatedCount(), 0); } static int groupSetup(void **state) { assertInit(); entityManagerInit(); return 0; } static int groupTeardown(void **state) { entityManagerDispose(); return 0; } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_entityjson_load), }; return cmocka_run_group_tests(tests, groupSetup, groupTeardown); }