/** * 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 "physics/physicsshape.h" static yyjson_val *test_roundTripToImmutable( yyjson_mut_doc *doc, yyjson_mut_val *root, yyjson_doc **outReadDoc ) { size_t len = 0; char_t *jsonStr = yyjson_mut_write(doc, 0, &len); assert_non_null(jsonStr); yyjson_mut_doc_free(doc); *outReadDoc = yyjson_read(jsonStr, len, 0); free(jsonStr); assert_non_null(*outReadDoc); return yyjson_doc_get_root(*outReadDoc); } static void test_physicsShapeCubeRoundTrip(void **state) { physicsshape_t shape = { .type = PHYSICS_SHAPE_CUBE, .data.cube.halfExtents = { 1.0f, 2.0f, 3.0f } }; yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); assert_true(errorIsOk(physicsShapeSerialize(doc, root, &shape))); yyjson_doc *readDoc; yyjson_val *root2 = test_roundTripToImmutable(doc, root, &readDoc); physicsshape_t got; assert_true(errorIsOk( physicsShapeDeserialize(yyjson_obj_get(root2, "shape"), &got) )); yyjson_doc_free(readDoc); assert_int_equal(got.type, PHYSICS_SHAPE_CUBE); assert_float_equal(got.data.cube.halfExtents[0], 1.0f, 0.0001f); assert_float_equal(got.data.cube.halfExtents[1], 2.0f, 0.0001f); assert_float_equal(got.data.cube.halfExtents[2], 3.0f, 0.0001f); } static void test_physicsShapeSphereRoundTrip(void **state) { physicsshape_t shape = { .type = PHYSICS_SHAPE_SPHERE, .data.sphere.radius = 4.5f }; yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); assert_true(errorIsOk(physicsShapeSerialize(doc, root, &shape))); yyjson_doc *readDoc; yyjson_val *root2 = test_roundTripToImmutable(doc, root, &readDoc); physicsshape_t got; assert_true(errorIsOk( physicsShapeDeserialize(yyjson_obj_get(root2, "shape"), &got) )); yyjson_doc_free(readDoc); assert_int_equal(got.type, PHYSICS_SHAPE_SPHERE); assert_float_equal(got.data.sphere.radius, 4.5f, 0.0001f); } static void test_physicsShapeCapsuleRoundTrip(void **state) { physicsshape_t shape = { .type = PHYSICS_SHAPE_CAPSULE, .data.capsule = { .radius = 0.5f, .halfHeight = 1.5f } }; yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); assert_true(errorIsOk(physicsShapeSerialize(doc, root, &shape))); yyjson_doc *readDoc; yyjson_val *root2 = test_roundTripToImmutable(doc, root, &readDoc); physicsshape_t got; assert_true(errorIsOk( physicsShapeDeserialize(yyjson_obj_get(root2, "shape"), &got) )); yyjson_doc_free(readDoc); assert_int_equal(got.type, PHYSICS_SHAPE_CAPSULE); assert_float_equal(got.data.capsule.radius, 0.5f, 0.0001f); assert_float_equal(got.data.capsule.halfHeight, 1.5f, 0.0001f); } static void test_physicsShapePlaneRoundTrip(void **state) { physicsshape_t shape = { .type = PHYSICS_SHAPE_PLANE, .data.plane = { .normal = { 0.0f, 1.0f, 0.0f }, .distance = 2.0f } }; yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); assert_true(errorIsOk(physicsShapeSerialize(doc, root, &shape))); yyjson_doc *readDoc; yyjson_val *root2 = test_roundTripToImmutable(doc, root, &readDoc); physicsshape_t got; assert_true(errorIsOk( physicsShapeDeserialize(yyjson_obj_get(root2, "shape"), &got) )); yyjson_doc_free(readDoc); assert_int_equal(got.type, PHYSICS_SHAPE_PLANE); assert_float_equal(got.data.plane.normal[1], 1.0f, 0.0001f); assert_float_equal(got.data.plane.distance, 2.0f, 0.0001f); } static void test_physicsShapeDeserializeUnknownTypeFails(void **state) { const char_t *json = "{\"shape\":{\"type\":\"NOT_A_SHAPE\"}}"; yyjson_doc *readDoc = yyjson_read(json, strlen(json), YYJSON_READ_NOFLAG); assert_non_null(readDoc); physicsshape_t got; errorret_t ret = physicsShapeDeserialize( yyjson_obj_get(yyjson_doc_get_root(readDoc), "shape"), &got ); assert_true(errorIsNotOk(ret)); errorCatch(ret); yyjson_doc_free(readDoc); } int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_physicsShapeCubeRoundTrip), cmocka_unit_test(test_physicsShapeSphereRoundTrip), cmocka_unit_test(test_physicsShapeCapsuleRoundTrip), cmocka_unit_test(test_physicsShapePlaneRoundTrip), cmocka_unit_test(test_physicsShapeDeserializeUnknownTypeFails), }; return cmocka_run_group_tests(tests, NULL, NULL); }