serialization_test.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. #include "core/component.h"
  2. #include "core/entity.h"
  3. #include "core/serialization.h"
  4. #include "core/world.h"
  5. #include "systems/nation_id.h"
  6. #include "units/spawn_type.h"
  7. #include "units/troop_type.h"
  8. #include <QJsonArray>
  9. #include <QJsonDocument>
  10. #include <QJsonObject>
  11. #include <QTemporaryFile>
  12. #include <gtest/gtest.h>
  13. using namespace Engine::Core;
  14. class SerializationTest : public ::testing::Test {
  15. protected:
  16. void SetUp() override { world = std::make_unique<World>(); }
  17. void TearDown() override { world.reset(); }
  18. std::unique_ptr<World> world;
  19. };
  20. TEST_F(SerializationTest, EntitySerializationBasic) {
  21. auto *entity = world->create_entity();
  22. ASSERT_NE(entity, nullptr);
  23. auto entity_id = entity->get_id();
  24. QJsonObject json = Serialization::serializeEntity(entity);
  25. EXPECT_TRUE(json.contains("id"));
  26. EXPECT_EQ(json["id"].toVariant().toULongLong(),
  27. static_cast<qulonglong>(entity_id));
  28. }
  29. TEST_F(SerializationTest, TransformComponentSerialization) {
  30. auto *entity = world->create_entity();
  31. auto *transform = entity->add_component<TransformComponent>();
  32. transform->position.x = 10.5F;
  33. transform->position.y = 20.3F;
  34. transform->position.z = 30.1F;
  35. transform->rotation.x = 0.5F;
  36. transform->rotation.y = 1.0F;
  37. transform->rotation.z = 1.5F;
  38. transform->scale.x = 2.0F;
  39. transform->scale.y = 2.5F;
  40. transform->scale.z = 3.0F;
  41. transform->has_desired_yaw = true;
  42. transform->desired_yaw = 45.0F;
  43. QJsonObject json = Serialization::serializeEntity(entity);
  44. ASSERT_TRUE(json.contains("transform"));
  45. QJsonObject transform_obj = json["transform"].toObject();
  46. EXPECT_FLOAT_EQ(transform_obj["pos_x"].toDouble(), 10.5);
  47. EXPECT_FLOAT_EQ(transform_obj["pos_y"].toDouble(), 20.3);
  48. EXPECT_FLOAT_EQ(transform_obj["pos_z"].toDouble(), 30.1);
  49. EXPECT_FLOAT_EQ(transform_obj["rot_x"].toDouble(), 0.5);
  50. EXPECT_FLOAT_EQ(transform_obj["rot_y"].toDouble(), 1.0);
  51. EXPECT_FLOAT_EQ(transform_obj["rot_z"].toDouble(), 1.5);
  52. EXPECT_FLOAT_EQ(transform_obj["scale_x"].toDouble(), 2.0);
  53. EXPECT_FLOAT_EQ(transform_obj["scale_y"].toDouble(), 2.5);
  54. EXPECT_FLOAT_EQ(transform_obj["scale_z"].toDouble(), 3.0);
  55. EXPECT_TRUE(transform_obj["has_desired_yaw"].toBool());
  56. EXPECT_FLOAT_EQ(transform_obj["desired_yaw"].toDouble(), 45.0);
  57. }
  58. TEST_F(SerializationTest, UnitComponentSerialization) {
  59. auto *entity = world->create_entity();
  60. auto *unit = entity->add_component<UnitComponent>();
  61. unit->health = 80;
  62. unit->max_health = 100;
  63. unit->speed = 5.5F;
  64. unit->vision_range = 15.0F;
  65. unit->spawn_type = Game::Units::SpawnType::Archer;
  66. unit->owner_id = 1;
  67. unit->nation_id = Game::Systems::NationID::RomanRepublic;
  68. QJsonObject json = Serialization::serializeEntity(entity);
  69. ASSERT_TRUE(json.contains("unit"));
  70. QJsonObject unit_obj = json["unit"].toObject();
  71. EXPECT_EQ(unit_obj["health"].toInt(), 80);
  72. EXPECT_EQ(unit_obj["max_health"].toInt(), 100);
  73. EXPECT_FLOAT_EQ(unit_obj["speed"].toDouble(), 5.5);
  74. EXPECT_FLOAT_EQ(unit_obj["vision_range"].toDouble(), 15.0);
  75. EXPECT_EQ(unit_obj["unit_type"].toString(), QString("archer"));
  76. EXPECT_EQ(unit_obj["owner_id"].toInt(), 1);
  77. EXPECT_EQ(unit_obj["nation_id"].toString(), QString("roman_republic"));
  78. }
  79. TEST_F(SerializationTest, MovementComponentSerialization) {
  80. auto *entity = world->create_entity();
  81. auto *movement = entity->add_component<MovementComponent>();
  82. movement->has_target = true;
  83. movement->target_x = 50.0F;
  84. movement->target_y = 60.0F;
  85. movement->goal_x = 55.0F;
  86. movement->goal_y = 65.0F;
  87. movement->vx = 1.5F;
  88. movement->vz = 2.0F;
  89. movement->path_pending = false;
  90. movement->pending_request_id = 42;
  91. movement->repath_cooldown = 1.0F;
  92. movement->last_goal_x = 45.0F;
  93. movement->last_goal_y = 55.0F;
  94. movement->time_since_last_path_request = 0.5F;
  95. movement->path.emplace_back(10.0F, 20.0F);
  96. movement->path.emplace_back(30.0F, 40.0F);
  97. QJsonObject json = Serialization::serializeEntity(entity);
  98. ASSERT_TRUE(json.contains("movement"));
  99. QJsonObject movement_obj = json["movement"].toObject();
  100. EXPECT_TRUE(movement_obj["has_target"].toBool());
  101. EXPECT_FLOAT_EQ(movement_obj["target_x"].toDouble(), 50.0);
  102. EXPECT_FLOAT_EQ(movement_obj["target_y"].toDouble(), 60.0);
  103. EXPECT_FLOAT_EQ(movement_obj["goal_x"].toDouble(), 55.0);
  104. EXPECT_FLOAT_EQ(movement_obj["goal_y"].toDouble(), 65.0);
  105. EXPECT_FLOAT_EQ(movement_obj["vx"].toDouble(), 1.5);
  106. EXPECT_FLOAT_EQ(movement_obj["vz"].toDouble(), 2.0);
  107. EXPECT_FALSE(movement_obj["path_pending"].toBool());
  108. EXPECT_EQ(movement_obj["pending_request_id"].toVariant().toULongLong(),
  109. 42ULL);
  110. ASSERT_TRUE(movement_obj.contains("path"));
  111. QJsonArray path_array = movement_obj["path"].toArray();
  112. ASSERT_EQ(path_array.size(), 2);
  113. QJsonObject waypoint1 = path_array[0].toObject();
  114. EXPECT_FLOAT_EQ(waypoint1["x"].toDouble(), 10.0);
  115. EXPECT_FLOAT_EQ(waypoint1["y"].toDouble(), 20.0);
  116. QJsonObject waypoint2 = path_array[1].toObject();
  117. EXPECT_FLOAT_EQ(waypoint2["x"].toDouble(), 30.0);
  118. EXPECT_FLOAT_EQ(waypoint2["y"].toDouble(), 40.0);
  119. }
  120. TEST_F(SerializationTest, AttackComponentSerialization) {
  121. auto *entity = world->create_entity();
  122. auto *attack = entity->add_component<AttackComponent>();
  123. attack->range = 10.0F;
  124. attack->damage = 25;
  125. attack->cooldown = 2.0F;
  126. attack->time_since_last = 0.5F;
  127. attack->melee_range = 2.0F;
  128. attack->melee_damage = 15;
  129. attack->melee_cooldown = 1.5F;
  130. attack->preferred_mode = AttackComponent::CombatMode::Ranged;
  131. attack->current_mode = AttackComponent::CombatMode::Ranged;
  132. attack->can_melee = true;
  133. attack->can_ranged = true;
  134. attack->max_height_difference = 5.0F;
  135. attack->in_melee_lock = false;
  136. attack->melee_lock_target_id = 0;
  137. QJsonObject json = Serialization::serializeEntity(entity);
  138. ASSERT_TRUE(json.contains("attack"));
  139. QJsonObject attack_obj = json["attack"].toObject();
  140. EXPECT_FLOAT_EQ(attack_obj["range"].toDouble(), 10.0);
  141. EXPECT_EQ(attack_obj["damage"].toInt(), 25);
  142. EXPECT_FLOAT_EQ(attack_obj["cooldown"].toDouble(), 2.0);
  143. EXPECT_FLOAT_EQ(attack_obj["time_since_last"].toDouble(), 0.5);
  144. EXPECT_FLOAT_EQ(attack_obj["melee_range"].toDouble(), 2.0);
  145. EXPECT_EQ(attack_obj["melee_damage"].toInt(), 15);
  146. EXPECT_FLOAT_EQ(attack_obj["melee_cooldown"].toDouble(), 1.5);
  147. EXPECT_EQ(attack_obj["preferred_mode"].toString(), QString("ranged"));
  148. EXPECT_EQ(attack_obj["current_mode"].toString(), QString("ranged"));
  149. EXPECT_TRUE(attack_obj["can_melee"].toBool());
  150. EXPECT_TRUE(attack_obj["can_ranged"].toBool());
  151. EXPECT_FLOAT_EQ(attack_obj["max_height_difference"].toDouble(), 5.0);
  152. EXPECT_FALSE(attack_obj["in_melee_lock"].toBool());
  153. }
  154. TEST_F(SerializationTest, EntityDeserializationRoundTrip) {
  155. auto *original_entity = world->create_entity();
  156. auto *transform = original_entity->add_component<TransformComponent>();
  157. transform->position.x = 100.0F;
  158. transform->position.y = 200.0F;
  159. transform->position.z = 300.0F;
  160. auto *unit = original_entity->add_component<UnitComponent>();
  161. unit->health = 75;
  162. unit->max_health = 100;
  163. unit->speed = 6.0F;
  164. QJsonObject json = Serialization::serializeEntity(original_entity);
  165. auto *new_entity = world->create_entity();
  166. Serialization::deserializeEntity(new_entity, json);
  167. auto *deserialized_transform =
  168. new_entity->get_component<TransformComponent>();
  169. ASSERT_NE(deserialized_transform, nullptr);
  170. EXPECT_FLOAT_EQ(deserialized_transform->position.x, 100.0F);
  171. EXPECT_FLOAT_EQ(deserialized_transform->position.y, 200.0F);
  172. EXPECT_FLOAT_EQ(deserialized_transform->position.z, 300.0F);
  173. auto *deserialized_unit = new_entity->get_component<UnitComponent>();
  174. ASSERT_NE(deserialized_unit, nullptr);
  175. EXPECT_EQ(deserialized_unit->health, 75);
  176. EXPECT_EQ(deserialized_unit->max_health, 100);
  177. EXPECT_FLOAT_EQ(deserialized_unit->speed, 6.0F);
  178. }
  179. TEST_F(SerializationTest, DeserializationWithMissingFields) {
  180. QJsonObject json;
  181. json["id"] = 1;
  182. QJsonObject unit_obj;
  183. unit_obj["health"] = 50;
  184. json["unit"] = unit_obj;
  185. auto *entity = world->create_entity();
  186. Serialization::deserializeEntity(entity, json);
  187. auto *unit = entity->get_component<UnitComponent>();
  188. ASSERT_NE(unit, nullptr);
  189. EXPECT_EQ(unit->health, 50);
  190. EXPECT_EQ(unit->max_health, Defaults::kUnitDefaultHealth);
  191. }
  192. TEST_F(SerializationTest, DeserializationWithMalformedJSON) {
  193. QJsonObject json;
  194. json["id"] = 1;
  195. QJsonObject transform_obj;
  196. transform_obj["pos_x"] = "not_a_number";
  197. json["transform"] = transform_obj;
  198. auto *entity = world->create_entity();
  199. EXPECT_NO_THROW({ Serialization::deserializeEntity(entity, json); });
  200. auto *transform = entity->get_component<TransformComponent>();
  201. ASSERT_NE(transform, nullptr);
  202. EXPECT_FLOAT_EQ(transform->position.x, 0.0F);
  203. }
  204. TEST_F(SerializationTest, WorldSerializationRoundTrip) {
  205. auto *entity1 = world->create_entity();
  206. auto *transform1 = entity1->add_component<TransformComponent>();
  207. transform1->position.x = 10.0F;
  208. auto *entity2 = world->create_entity();
  209. auto *transform2 = entity2->add_component<TransformComponent>();
  210. transform2->position.x = 20.0F;
  211. QJsonDocument doc = Serialization::serializeWorld(world.get());
  212. ASSERT_TRUE(doc.isObject());
  213. QJsonObject world_obj = doc.object();
  214. EXPECT_TRUE(world_obj.contains("entities"));
  215. EXPECT_TRUE(world_obj.contains("nextEntityId"));
  216. EXPECT_TRUE(world_obj.contains("schemaVersion"));
  217. auto new_world = std::make_unique<World>();
  218. Serialization::deserializeWorld(new_world.get(), doc);
  219. const auto &entities = new_world->get_entities();
  220. EXPECT_EQ(entities.size(), 2UL);
  221. }
  222. TEST_F(SerializationTest, SaveAndLoadFromFile) {
  223. auto *entity = world->create_entity();
  224. auto *transform = entity->add_component<TransformComponent>();
  225. transform->position.x = 42.0F;
  226. transform->position.y = 43.0F;
  227. transform->position.z = 44.0F;
  228. QJsonDocument doc = Serialization::serializeWorld(world.get());
  229. QTemporaryFile temp_file;
  230. ASSERT_TRUE(temp_file.open());
  231. QString filename = temp_file.fileName();
  232. temp_file.close();
  233. EXPECT_TRUE(Serialization::saveToFile(filename, doc));
  234. QJsonDocument loaded_doc = Serialization::loadFromFile(filename);
  235. EXPECT_FALSE(loaded_doc.isNull());
  236. auto new_world = std::make_unique<World>();
  237. Serialization::deserializeWorld(new_world.get(), loaded_doc);
  238. const auto &entities = new_world->get_entities();
  239. EXPECT_EQ(entities.size(), 1UL);
  240. if (!entities.empty()) {
  241. auto *loaded_entity = entities.begin()->second.get();
  242. auto *loaded_transform = loaded_entity->get_component<TransformComponent>();
  243. ASSERT_NE(loaded_transform, nullptr);
  244. EXPECT_FLOAT_EQ(loaded_transform->position.x, 42.0F);
  245. EXPECT_FLOAT_EQ(loaded_transform->position.y, 43.0F);
  246. EXPECT_FLOAT_EQ(loaded_transform->position.z, 44.0F);
  247. }
  248. }
  249. TEST_F(SerializationTest, ProductionComponentSerialization) {
  250. auto *entity = world->create_entity();
  251. auto *production = entity->add_component<ProductionComponent>();
  252. production->in_progress = true;
  253. production->build_time = 10.0F;
  254. production->time_remaining = 5.0F;
  255. production->produced_count = 3;
  256. production->max_units = 10;
  257. production->product_type = Game::Units::TroopType::Archer;
  258. production->rally_x = 100.0F;
  259. production->rally_z = 200.0F;
  260. production->rally_set = true;
  261. production->villager_cost = 2;
  262. production->production_queue.push_back(Game::Units::TroopType::Spearman);
  263. production->production_queue.push_back(Game::Units::TroopType::Archer);
  264. QJsonObject json = Serialization::serializeEntity(entity);
  265. ASSERT_TRUE(json.contains("production"));
  266. QJsonObject prod_obj = json["production"].toObject();
  267. EXPECT_TRUE(prod_obj["in_progress"].toBool());
  268. EXPECT_FLOAT_EQ(prod_obj["build_time"].toDouble(), 10.0);
  269. EXPECT_FLOAT_EQ(prod_obj["time_remaining"].toDouble(), 5.0);
  270. EXPECT_EQ(prod_obj["produced_count"].toInt(), 3);
  271. EXPECT_EQ(prod_obj["max_units"].toInt(), 10);
  272. EXPECT_EQ(prod_obj["product_type"].toString(), QString("archer"));
  273. EXPECT_FLOAT_EQ(prod_obj["rally_x"].toDouble(), 100.0);
  274. EXPECT_FLOAT_EQ(prod_obj["rally_z"].toDouble(), 200.0);
  275. EXPECT_TRUE(prod_obj["rally_set"].toBool());
  276. EXPECT_EQ(prod_obj["villager_cost"].toInt(), 2);
  277. ASSERT_TRUE(prod_obj.contains("queue"));
  278. QJsonArray queue = prod_obj["queue"].toArray();
  279. EXPECT_EQ(queue.size(), 2);
  280. EXPECT_EQ(queue[0].toString(), QString("spearman"));
  281. EXPECT_EQ(queue[1].toString(), QString("archer"));
  282. }
  283. TEST_F(SerializationTest, PatrolComponentSerialization) {
  284. auto *entity = world->create_entity();
  285. auto *patrol = entity->add_component<PatrolComponent>();
  286. patrol->current_waypoint = 1;
  287. patrol->patrolling = true;
  288. patrol->waypoints.emplace_back(10.0F, 20.0F);
  289. patrol->waypoints.emplace_back(30.0F, 40.0F);
  290. patrol->waypoints.emplace_back(50.0F, 60.0F);
  291. QJsonObject json = Serialization::serializeEntity(entity);
  292. ASSERT_TRUE(json.contains("patrol"));
  293. QJsonObject patrol_obj = json["patrol"].toObject();
  294. EXPECT_EQ(patrol_obj["current_waypoint"].toInt(), 1);
  295. EXPECT_TRUE(patrol_obj["patrolling"].toBool());
  296. ASSERT_TRUE(patrol_obj.contains("waypoints"));
  297. QJsonArray waypoints = patrol_obj["waypoints"].toArray();
  298. EXPECT_EQ(waypoints.size(), 3);
  299. QJsonObject wp0 = waypoints[0].toObject();
  300. EXPECT_FLOAT_EQ(wp0["x"].toDouble(), 10.0);
  301. EXPECT_FLOAT_EQ(wp0["y"].toDouble(), 20.0);
  302. }
  303. TEST_F(SerializationTest, RenderableComponentSerialization) {
  304. auto *entity = world->create_entity();
  305. auto *renderable =
  306. entity->add_component<RenderableComponent>("mesh.obj", "texture.png");
  307. renderable->mesh_path = "models/archer.obj";
  308. renderable->texture_path = "textures/archer_diffuse.png";
  309. renderable->renderer_id = "archer_renderer";
  310. renderable->visible = true;
  311. renderable->mesh = RenderableComponent::MeshKind::Capsule;
  312. renderable->color = {0.8F, 0.2F, 0.5F};
  313. QJsonObject json = Serialization::serializeEntity(entity);
  314. ASSERT_TRUE(json.contains("renderable"));
  315. QJsonObject renderable_obj = json["renderable"].toObject();
  316. EXPECT_EQ(renderable_obj["mesh_path"].toString(),
  317. QString("models/archer.obj"));
  318. EXPECT_EQ(renderable_obj["texture_path"].toString(),
  319. QString("textures/archer_diffuse.png"));
  320. EXPECT_EQ(renderable_obj["renderer_id"].toString(),
  321. QString("archer_renderer"));
  322. EXPECT_TRUE(renderable_obj["visible"].toBool());
  323. EXPECT_EQ(renderable_obj["mesh"].toInt(),
  324. static_cast<int>(RenderableComponent::MeshKind::Capsule));
  325. ASSERT_TRUE(renderable_obj.contains("color"));
  326. QJsonArray color = renderable_obj["color"].toArray();
  327. EXPECT_EQ(color.size(), 3);
  328. EXPECT_FLOAT_EQ(color[0].toDouble(), 0.8);
  329. EXPECT_FLOAT_EQ(color[1].toDouble(), 0.2);
  330. EXPECT_FLOAT_EQ(color[2].toDouble(), 0.5);
  331. }
  332. TEST_F(SerializationTest, RenderableComponentRoundTrip) {
  333. auto *original_entity = world->create_entity();
  334. auto *renderable = original_entity->add_component<RenderableComponent>(
  335. "test.obj", "test.png");
  336. renderable->mesh_path = "models/building.obj";
  337. renderable->texture_path = "textures/building.png";
  338. renderable->visible = false;
  339. renderable->mesh = RenderableComponent::MeshKind::Quad;
  340. renderable->color = {1.0F, 0.5F, 0.25F};
  341. QJsonObject json = Serialization::serializeEntity(original_entity);
  342. auto *new_entity = world->create_entity();
  343. Serialization::deserializeEntity(new_entity, json);
  344. auto *deserialized = new_entity->get_component<RenderableComponent>();
  345. ASSERT_NE(deserialized, nullptr);
  346. EXPECT_EQ(deserialized->mesh_path, "models/building.obj");
  347. EXPECT_EQ(deserialized->texture_path, "textures/building.png");
  348. EXPECT_FALSE(deserialized->visible);
  349. EXPECT_EQ(deserialized->mesh, RenderableComponent::MeshKind::Quad);
  350. EXPECT_FLOAT_EQ(deserialized->color[0], 1.0F);
  351. EXPECT_FLOAT_EQ(deserialized->color[1], 0.5F);
  352. EXPECT_FLOAT_EQ(deserialized->color[2], 0.25F);
  353. }
  354. TEST_F(SerializationTest, AttackTargetComponentSerialization) {
  355. auto *entity = world->create_entity();
  356. auto *attack_target = entity->add_component<AttackTargetComponent>();
  357. attack_target->target_id = 42;
  358. attack_target->should_chase = true;
  359. QJsonObject json = Serialization::serializeEntity(entity);
  360. ASSERT_TRUE(json.contains("attack_target"));
  361. QJsonObject attack_target_obj = json["attack_target"].toObject();
  362. EXPECT_EQ(attack_target_obj["target_id"].toVariant().toULongLong(), 42ULL);
  363. EXPECT_TRUE(attack_target_obj["should_chase"].toBool());
  364. }
  365. TEST_F(SerializationTest, AttackTargetComponentRoundTrip) {
  366. auto *original_entity = world->create_entity();
  367. auto *attack_target = original_entity->add_component<AttackTargetComponent>();
  368. attack_target->target_id = 123;
  369. attack_target->should_chase = false;
  370. QJsonObject json = Serialization::serializeEntity(original_entity);
  371. auto *new_entity = world->create_entity();
  372. Serialization::deserializeEntity(new_entity, json);
  373. auto *deserialized = new_entity->get_component<AttackTargetComponent>();
  374. ASSERT_NE(deserialized, nullptr);
  375. EXPECT_EQ(deserialized->target_id, 123U);
  376. EXPECT_FALSE(deserialized->should_chase);
  377. }
  378. TEST_F(SerializationTest, BuildingComponentSerialization) {
  379. auto *entity = world->create_entity();
  380. entity->add_component<BuildingComponent>();
  381. QJsonObject json = Serialization::serializeEntity(entity);
  382. ASSERT_TRUE(json.contains("building"));
  383. EXPECT_TRUE(json["building"].toBool());
  384. }
  385. TEST_F(SerializationTest, BuildingComponentRoundTrip) {
  386. auto *original_entity = world->create_entity();
  387. original_entity->add_component<BuildingComponent>();
  388. QJsonObject json = Serialization::serializeEntity(original_entity);
  389. auto *new_entity = world->create_entity();
  390. Serialization::deserializeEntity(new_entity, json);
  391. auto *deserialized = new_entity->get_component<BuildingComponent>();
  392. ASSERT_NE(deserialized, nullptr);
  393. }
  394. TEST_F(SerializationTest, AIControlledComponentSerialization) {
  395. auto *entity = world->create_entity();
  396. entity->add_component<AIControlledComponent>();
  397. QJsonObject json = Serialization::serializeEntity(entity);
  398. ASSERT_TRUE(json.contains("aiControlled"));
  399. EXPECT_TRUE(json["aiControlled"].toBool());
  400. }
  401. TEST_F(SerializationTest, AIControlledComponentRoundTrip) {
  402. auto *original_entity = world->create_entity();
  403. original_entity->add_component<AIControlledComponent>();
  404. QJsonObject json = Serialization::serializeEntity(original_entity);
  405. auto *new_entity = world->create_entity();
  406. Serialization::deserializeEntity(new_entity, json);
  407. auto *deserialized = new_entity->get_component<AIControlledComponent>();
  408. ASSERT_NE(deserialized, nullptr);
  409. }
  410. TEST_F(SerializationTest, CaptureComponentSerialization) {
  411. auto *entity = world->create_entity();
  412. auto *capture = entity->add_component<CaptureComponent>();
  413. capture->capturing_player_id = 2;
  414. capture->capture_progress = 7.5F;
  415. capture->required_time = 15.0F;
  416. capture->is_being_captured = true;
  417. QJsonObject json = Serialization::serializeEntity(entity);
  418. ASSERT_TRUE(json.contains("capture"));
  419. QJsonObject capture_obj = json["capture"].toObject();
  420. EXPECT_EQ(capture_obj["capturing_player_id"].toInt(), 2);
  421. EXPECT_FLOAT_EQ(capture_obj["capture_progress"].toDouble(), 7.5);
  422. EXPECT_FLOAT_EQ(capture_obj["required_time"].toDouble(), 15.0);
  423. EXPECT_TRUE(capture_obj["is_being_captured"].toBool());
  424. }
  425. TEST_F(SerializationTest, CaptureComponentRoundTrip) {
  426. auto *original_entity = world->create_entity();
  427. auto *capture = original_entity->add_component<CaptureComponent>();
  428. capture->capturing_player_id = 3;
  429. capture->capture_progress = 10.0F;
  430. capture->required_time = 20.0F;
  431. capture->is_being_captured = false;
  432. QJsonObject json = Serialization::serializeEntity(original_entity);
  433. auto *new_entity = world->create_entity();
  434. Serialization::deserializeEntity(new_entity, json);
  435. auto *deserialized = new_entity->get_component<CaptureComponent>();
  436. ASSERT_NE(deserialized, nullptr);
  437. EXPECT_EQ(deserialized->capturing_player_id, 3);
  438. EXPECT_FLOAT_EQ(deserialized->capture_progress, 10.0F);
  439. EXPECT_FLOAT_EQ(deserialized->required_time, 20.0F);
  440. EXPECT_FALSE(deserialized->is_being_captured);
  441. }
  442. TEST_F(SerializationTest, CompleteEntityWithAllComponents) {
  443. auto *entity = world->create_entity();
  444. auto *transform = entity->add_component<TransformComponent>();
  445. transform->position.x = 50.0F;
  446. transform->position.y = 10.0F;
  447. transform->position.z = 30.0F;
  448. auto *renderable =
  449. entity->add_component<RenderableComponent>("mesh.obj", "tex.png");
  450. renderable->visible = true;
  451. auto *unit = entity->add_component<UnitComponent>();
  452. unit->health = 100;
  453. unit->max_health = 100;
  454. auto *movement = entity->add_component<MovementComponent>();
  455. movement->has_target = true;
  456. movement->target_x = 100.0F;
  457. auto *attack = entity->add_component<AttackComponent>();
  458. attack->damage = 25;
  459. auto *attack_target = entity->add_component<AttackTargetComponent>();
  460. attack_target->target_id = 99;
  461. entity->add_component<BuildingComponent>();
  462. auto *production = entity->add_component<ProductionComponent>();
  463. production->in_progress = true;
  464. entity->add_component<AIControlledComponent>();
  465. auto *capture = entity->add_component<CaptureComponent>();
  466. capture->is_being_captured = true;
  467. QJsonObject json = Serialization::serializeEntity(entity);
  468. EXPECT_TRUE(json.contains("transform"));
  469. EXPECT_TRUE(json.contains("renderable"));
  470. EXPECT_TRUE(json.contains("unit"));
  471. EXPECT_TRUE(json.contains("movement"));
  472. EXPECT_TRUE(json.contains("attack"));
  473. EXPECT_TRUE(json.contains("attack_target"));
  474. EXPECT_TRUE(json.contains("building"));
  475. EXPECT_TRUE(json.contains("production"));
  476. EXPECT_TRUE(json.contains("aiControlled"));
  477. EXPECT_TRUE(json.contains("capture"));
  478. auto *new_entity = world->create_entity();
  479. Serialization::deserializeEntity(new_entity, json);
  480. EXPECT_NE(new_entity->get_component<TransformComponent>(), nullptr);
  481. EXPECT_NE(new_entity->get_component<RenderableComponent>(), nullptr);
  482. EXPECT_NE(new_entity->get_component<UnitComponent>(), nullptr);
  483. EXPECT_NE(new_entity->get_component<MovementComponent>(), nullptr);
  484. EXPECT_NE(new_entity->get_component<AttackComponent>(), nullptr);
  485. EXPECT_NE(new_entity->get_component<AttackTargetComponent>(), nullptr);
  486. EXPECT_NE(new_entity->get_component<BuildingComponent>(), nullptr);
  487. EXPECT_NE(new_entity->get_component<ProductionComponent>(), nullptr);
  488. EXPECT_NE(new_entity->get_component<AIControlledComponent>(), nullptr);
  489. EXPECT_NE(new_entity->get_component<CaptureComponent>(), nullptr);
  490. }
  491. TEST_F(SerializationTest, EmptyWorldSerialization) {
  492. QJsonDocument doc = Serialization::serializeWorld(world.get());
  493. ASSERT_TRUE(doc.isObject());
  494. QJsonObject world_obj = doc.object();
  495. EXPECT_TRUE(world_obj.contains("entities"));
  496. QJsonArray entities = world_obj["entities"].toArray();
  497. EXPECT_EQ(entities.size(), 0);
  498. }