mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
Factorio 2.1.18 removed PollutionSettings::max_pollution_to_restore_trees, but readPollution still read it for every version, so every map setting after it was read 9 bytes late: enemy_attack_pollution_consumption_modifier came out as garbage, the enemy_evolution factors shifted by one field and enemy_expansion.enabled and both expansion distances came out null. Read the field only for strings older than 2.1.18. Add modified_v2_1_17 and modified_v2_1_18 fixtures generated with headless 2.1.17 and 2.1.18 from the modified 2.1 settings (base game only), unit tests asserting their full decoded output, and use the 2.1.18 string for the load-scenario integration test on 2.1.18 and later. Fixes #1131 Co-authored-by: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com> Co-authored-by: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com>
142 lines
4.4 KiB
JavaScript
142 lines
4.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import zlib from "node:zlib";
|
|
|
|
import * as lib from "@clusterio/lib";
|
|
|
|
import * as testStrings from "./test_strings.js";
|
|
import * as testSettings from "./test_settings.js";
|
|
|
|
|
|
// Simple linear congruential random number generator
|
|
class Random {
|
|
constructor(seed) {
|
|
this.prev = seed;
|
|
}
|
|
|
|
next() {
|
|
let curr = (1103515245 * this.prev + 12345) & 0x7fffffff;
|
|
this.prev = curr;
|
|
return curr >> 16;
|
|
}
|
|
}
|
|
|
|
describe("lib/factorio/exchange_string", function() {
|
|
describe("readMapExchangeString", function() {
|
|
it("should parse post v0.16 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.default), {
|
|
version: [1, 1, 33, 0],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.default_map_gen_settings,
|
|
map_settings: testSettings.default_map_settings,
|
|
checksum: 3169422966,
|
|
});
|
|
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified), {
|
|
version: [1, 1, 33, 0],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_map_gen_settings,
|
|
map_settings: testSettings.modified_map_settings,
|
|
checksum: 4092204126,
|
|
});
|
|
});
|
|
|
|
it("should parse post v2.0 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2), {
|
|
version: [2, 0, 47, 0],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_v2_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_map_settings,
|
|
checksum: 979461261,
|
|
});
|
|
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_space_age), {
|
|
version: [2, 0, 47, 0],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_space_age_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_map_settings,
|
|
checksum: 1746300027,
|
|
});
|
|
});
|
|
|
|
it("should parse post v2.1 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1), {
|
|
version: [2, 1, 9, 3],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_1_map_settings,
|
|
checksum: 3180296799,
|
|
});
|
|
});
|
|
|
|
it("should parse post v2.1.13 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1_13), {
|
|
version: [2, 1, 14, 1],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_1_13_map_settings,
|
|
checksum: 272054359,
|
|
});
|
|
});
|
|
|
|
it("should parse v2.1.17 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1_17), {
|
|
version: [2, 1, 17, 0],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_1_13_map_settings,
|
|
checksum: 1073352633,
|
|
});
|
|
});
|
|
|
|
it("should parse post v2.1.18 strings", function() {
|
|
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1_18), {
|
|
version: [2, 1, 18, 4],
|
|
unknown: 0,
|
|
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
|
|
map_settings: testSettings.modified_v2_1_18_map_settings,
|
|
checksum: 1437579271,
|
|
});
|
|
});
|
|
|
|
it("should handle malformed strings", function() {
|
|
assert.throws(
|
|
() => lib.readMapExchangeString("<<blah>>"),
|
|
new Error("Not a map exchange string")
|
|
);
|
|
|
|
assert.throws(
|
|
() => lib.readMapExchangeString(testStrings.default.slice(0, 100)),
|
|
new Error("Not a map exchange string")
|
|
);
|
|
|
|
assert.throws(
|
|
() => lib.readMapExchangeString(`>>>${Buffer.from("abk430ia404ah3b4").toString("base64")}<<<`),
|
|
new Error("Malformed map exchange string: zlib inflate failed")
|
|
);
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
let gen = new Random(i);
|
|
let size = gen.next() % 200 + 100;
|
|
let data = Buffer.alloc(size);
|
|
for (let j = 0; j < size; j++) {
|
|
data[j] = gen.next() % 256;
|
|
}
|
|
// eslint-disable-next-line node/no-sync
|
|
data = zlib.deflateSync(data);
|
|
assert.throws(
|
|
() => lib.readMapExchangeString(`>>>${data.toString("base64")}<<<`),
|
|
new Error("Malformed map exchange string: reached end before finishing parsing")
|
|
);
|
|
}
|
|
|
|
let pastEnd = Buffer.from(testStrings.default.replace(/><\n/g, ""), "base64");
|
|
// eslint-disable-next-line node/no-sync
|
|
pastEnd = zlib.deflateSync(Buffer.concat([zlib.inflateSync(pastEnd), Buffer.from("junk")]));
|
|
assert.throws(
|
|
() => lib.readMapExchangeString(`>>>${pastEnd.toString("base64")}<<<`),
|
|
new Error("Malformed map exchange string: data after end")
|
|
);
|
|
});
|
|
});
|
|
});
|