From 2c33c28a0924cfb8917824e9c59549e97647a8b1 Mon Sep 17 00:00:00 2001 From: Freagarach Date: Tue, 28 Dec 2021 08:23:59 +0000 Subject: [PATCH] Add the ability to do simple (de)serialisation cycle in the JS unit tests. (And change the PQ, Trainer and Researcher serialisation.) To catch e.g. typos. - Use the same structure in the ProductionQueue item (de)serialisation as in Trainer and Researcher. - Also iterate over the serialisable attributes on deserialize, as proposed by @elexis (on IRC), for its symmetry. Proposed by: @Stan Differential revision: D4388 This was SVN commit r26133. --- .../simulation/components/ProductionQueue.js | 83 ++++++++++--------- .../simulation/components/Researcher.js | 4 +- .../public/simulation/components/Trainer.js | 4 +- .../simulation/components/tests/setup.js | 29 +++++++ .../components/tests/test_ProductionQueue.js | 8 ++ .../components/tests/test_Researcher.js | 4 +- .../components/tests/test_Trainer.js | 6 +- 7 files changed, 92 insertions(+), 46 deletions(-) diff --git a/binaries/data/mods/public/simulation/components/ProductionQueue.js b/binaries/data/mods/public/simulation/components/ProductionQueue.js index 1ded67a66f..4f6c6d7834 100644 --- a/binaries/data/mods/public/simulation/components/ProductionQueue.js +++ b/binaries/data/mods/public/simulation/components/ProductionQueue.js @@ -9,14 +9,11 @@ ProductionQueue.prototype.MaxQueueSize = 16; /** * This object represents an item in the queue. - */ -ProductionQueue.prototype.Item = function() {}; - -/** + * * @param {number} producer - The entity ID of our producer. * @param {string} metadata - Optionally any metadata attached to us. */ -ProductionQueue.prototype.Item.prototype.Init = function(producer, metadata) +ProductionQueue.prototype.Item = function(producer, metadata) { this.producer = producer; this.metadata = metadata; @@ -192,30 +189,31 @@ ProductionQueue.prototype.Item.prototype.OriginalItem = function() return this.originalItem; }; +ProductionQueue.prototype.Item.prototype.SerializableAttributes = [ + "entity", + "id", + "metadata", + "originalItem", + "paused", + "producer", + "started", + "technology" +]; + ProductionQueue.prototype.Item.prototype.Serialize = function() { - return { - "id": this.id, - "metadata": this.metadata, - "paused": this.paused, - "producer": this.producer, - "entity": this.entity, - "technology": this.technology, - "started": this.started, - "originalItem": this.originalItem - }; + const result = {}; + for (const att of this.SerializableAttributes) + if (this.hasOwnProperty(att)) + result[att] = this[att]; + return result; }; ProductionQueue.prototype.Item.prototype.Deserialize = function(data) { - this.Init(data.producer, data.metadata); - - this.id = data.id; - this.paused = data.paused; - this.entity = data.entity; - this.technology = data.technology; - this.started = data.started; - this.originalItem = data.originalItem; + for (const att of this.SerializableAttributes) + if (att in data) + this[att] = data[att]; }; ProductionQueue.prototype.Init = function() @@ -224,29 +222,35 @@ ProductionQueue.prototype.Init = function() this.queue = []; }; +ProductionQueue.prototype.SerializableAttributes = [ + "autoqueuing", + "nextID", + "paused", + "timer" +]; + ProductionQueue.prototype.Serialize = function() { - const queue = []; - for (const item of this.queue) - queue.push(item.Serialize()); - - return { - "autoqueuing": this.autoqueuing, - "nextID": this.nextID, - "paused": this.paused, - "timer": this.timer, - "queue": queue + const result = { + "queue": [] }; + for (const item of this.queue) + result.queue.push(item.Serialize()); + + for (const att of this.SerializableAttributes) + if (this.hasOwnProperty(att)) + result[att] = this[att]; + + return result; }; ProductionQueue.prototype.Deserialize = function(data) { - this.Init(); + for (const att of this.SerializableAttributes) + if (att in data) + this[att] = data[att]; - this.autoqueuing = data.autoqueuing; - this.nextID = data.nextID; - this.paused = data.paused; - this.timer = data.timer; + this.queue = []; for (const item of data.queue) { @@ -328,8 +332,7 @@ ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata return false; } - const item = new this.Item(); - item.Init(this.entity, metadata); + const item = new this.Item(this.entity, metadata); if (!item.Queue(type, templateName, count)) return false; diff --git a/binaries/data/mods/public/simulation/components/Researcher.js b/binaries/data/mods/public/simulation/components/Researcher.js index 95897b1513..d1c9b9c2ab 100644 --- a/binaries/data/mods/public/simulation/components/Researcher.js +++ b/binaries/data/mods/public/simulation/components/Researcher.js @@ -175,8 +175,8 @@ Researcher.prototype.Item.prototype.Serialize = function(id) Researcher.prototype.Item.prototype.Deserialize = function(data) { - for (const att in data) - if (this.SerializableAttributes.includes(att)) + for (const att of this.SerializableAttributes) + if (att in data) this[att] = data[att]; }; diff --git a/binaries/data/mods/public/simulation/components/Trainer.js b/binaries/data/mods/public/simulation/components/Trainer.js index d008760492..f1bfac6e2d 100644 --- a/binaries/data/mods/public/simulation/components/Trainer.js +++ b/binaries/data/mods/public/simulation/components/Trainer.js @@ -401,8 +401,8 @@ Trainer.prototype.Item.prototype.Serialize = function(id) Trainer.prototype.Item.prototype.Deserialize = function(data) { - for (const att in data) - if (this.SerializableAttributes.includes(att)) + for (const att of this.SerializableAttributes) + if (att in data) this[att] = data[att]; }; diff --git a/binaries/data/mods/public/simulation/components/tests/setup.js b/binaries/data/mods/public/simulation/components/tests/setup.js index a03e26d962..36bf7741e1 100644 --- a/binaries/data/mods/public/simulation/components/tests/setup.js +++ b/binaries/data/mods/public/simulation/components/tests/setup.js @@ -100,6 +100,12 @@ global.ConstructComponent = function(ent, name, template) "configurable": false, "enumerable": false, "writable": false + }, + "_cmpName": { + "value": name, + "configurable": false, + "enumerable": false, + "writable": false } }); @@ -135,3 +141,26 @@ global.Spy = function(obj, func) return this; }; + +global.SerializationCycle = function(cmp) +{ + let data; + if (typeof cmp.Serialize === "function") + data = cmp.Serialize(); + else + { + data = {}; + for (const att of cmp) + if (cmp.hasOwnProperty(att)) + data[att] = cmp[att]; + } + + const newCmp = ConstructComponent(cmp.entity, cmp._cmpName, cmp.template); + if (typeof newCmp.Deserialize === "function") + newCmp.Deserialize(data); + else + for (const att in data) + newCmp[att] = data[att]; + + return newCmp; +}; diff --git a/binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js b/binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js index d12204f5df..cdb1ba449f 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js +++ b/binaries/data/mods/public/simulation/components/tests/test_ProductionQueue.js @@ -81,3 +81,11 @@ TS_ASSERT(cmpProdQueue.GetQueue()[1].paused); cmpProdQueue.ProgressTimeout(null, 0); TS_ASSERT_EQUALS(cmpProdQueue.GetQueue().length, 0); + + +// Simple deserialisation test. +cmpProdQueue.AddItem("some_template", "unit", 2); +const deserialisedCmp = SerializationCycle(cmpProdQueue); +TS_ASSERT_EQUALS(deserialisedCmp.GetQueue().length, 1); +deserialisedCmp.ProgressTimeout(null, 0); +TS_ASSERT_EQUALS(deserialisedCmp.GetQueue().length, 0); diff --git a/binaries/data/mods/public/simulation/components/tests/test_Researcher.js b/binaries/data/mods/public/simulation/components/tests/test_Researcher.js index 3f1bfa3370..1f5a9d0090 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_Researcher.js +++ b/binaries/data/mods/public/simulation/components/tests/test_Researcher.js @@ -40,7 +40,7 @@ AddMock(entityID, IID_Identity, { "GetCiv": () => "iber" }); -const cmpResearcher = ConstructComponent(entityID, "Researcher", { +let cmpResearcher = ConstructComponent(entityID, "Researcher", { "Technologies": { "_string": "gather_fishing_net " + "phase_town_{civ} " + "phase_city_{civ}" } @@ -147,6 +147,8 @@ TS_ASSERT_EQUALS(cmpResearcher.GetResearchingTechnology(id).progress, 0); TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 500), 500); TS_ASSERT_EQUALS(cmpResearcher.GetResearchingTechnology(id).progress, 0.5); +cmpResearcher = SerializationCycle(cmpResearcher); + spyTechManager = new Spy(techManager, "ResearchTechnology"); TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 1000), 500); TS_ASSERT_EQUALS(spyTechManager._called, 1); diff --git a/binaries/data/mods/public/simulation/components/tests/test_Trainer.js b/binaries/data/mods/public/simulation/components/tests/test_Trainer.js index e29b83bc81..22023a8f6d 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_Trainer.js +++ b/binaries/data/mods/public/simulation/components/tests/test_Trainer.js @@ -26,7 +26,7 @@ AddMock(SYSTEM_ENTITY, IID_TemplateManager, { "GetTemplate": name => ({}) }); -const cmpTrainer = ConstructComponent(entityID, "Trainer", { +let cmpTrainer = ConstructComponent(entityID, "Trainer", { "Entities": { "_string": "units/{civ}/cavalry_javelineer_b " + "units/{civ}/infantry_swordsman_b " + "units/{native}/support_female_citizen" } @@ -246,6 +246,8 @@ AddMock(entityID, IID_Footprint, { "PickSpawnPoint": () => ({ "x": 0, "y": 1, "z": 0 }) }); +cmpTrainer = SerializationCycle(cmpTrainer); + TS_ASSERT_EQUALS(cmpTrainer.Progress(id, 1000), 500); TS_ASSERT(!cmpTrainer.HasBatch(id)); TS_ASSERT(!cmpEntLimits.AllowedToTrain("some_limit", 5)); @@ -268,6 +270,8 @@ TS_ASSERT(cmpTrainer.HasBatch(id)); TS_ASSERT_EQUALS(cmpEntLimits.GetCounts().some_limit, 3); TS_ASSERT_EQUALS(cmpEntLimits.GetMatchCounts()["units/iber/infantry_swordsman_b"], 3); +cmpTrainer = SerializationCycle(cmpTrainer); + // Check that when the batch is removed the counts are subtracted again. cmpTrainer.StopBatch(id); TS_ASSERT_EQUALS(cmpEntLimits.GetCounts().some_limit, 1);