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.
This commit is contained in:
Freagarach 2021-12-28 08:23:59 +00:00
parent 32fc381017
commit 2c33c28a09
7 changed files with 92 additions and 46 deletions

View File

@ -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;

View File

@ -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];
};

View File

@ -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];
};

View File

@ -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;
};

View File

@ -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);

View File

@ -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);

View File

@ -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);