Files
factorio-clusterio/test/lib/data/ModPack.js
T
Hornwitser bfe119eaa3 Flatten lib namespace
Move all functions and classes currently available through lib/name and
libName to be under a single flat namespace in lib.  This make
reorganising the lib namespace much simpler as the location of symbols
can move without breaking the consumers of lib.

The multi-entrypoint design was already problematic for the web plugin
system which couldn't effectively use it due to how webpack's shared
module system is awkward to set up with multiple entrypoints per package.
2023-07-28 16:03:29 +02:00

267 lines
7.8 KiB
JavaScript

"use strict";
const assert = require("assert").strict;
const zlib = require("zlib");
const lib = require("@clusterio/lib");
const { ModPack } = lib;
describe("lib/data/ModPack", function() {
describe("class ModPack", function() {
it("should round trip serialize", function() {
const validate = lib.compile(ModPack.jsonSchema);
function check(pack) {
const json = JSON.parse(JSON.stringify(pack));
if (!validate(json)) {
throw validate.errors;
}
assert.deepEqual(ModPack.fromJSON(json), pack);
const packStringed = ModPack.fromModPackString(pack.toModPackString());
packStringed.id = pack.id;
packStringed.exportManifest = pack.exportManifest;
assert.deepEqual(packStringed, pack);
}
check(ModPack.fromJSON({}));
check(ModPack.fromJSON({ name: "MyPack" }));
check(ModPack.fromJSON({ description: "My Description" }));
check(ModPack.fromJSON({ factorio_version: "2.0" }));
check(ModPack.fromJSON({ mods: [
{ name: "subspace_storage", enabled: true, version: "1.99.8" },
{ name: "clusterio_lib", enabled: true, version: "0.1.2", sha1: "012345abcd" },
]}));
check(ModPack.fromJSON({ settings: {
"startup": {
"bool-setting": { "value": true },
},
"runtime-global": {
"number-setting": { "value": 123 },
},
"runtime-per-user": {
"string-setting": { "value": "a string" },
},
}}));
check(ModPack.fromJSON({ export_manifest: { assets: { setting: "settings.json" }}}));
check(ModPack.fromJSON({ deleted: true }));
check(ModPack.fromJSON({
name: "Super pack",
description: "Every option at once.",
factorio_version: "2.0",
mods: [
{ name: "subspace_storage", enabled: true, version: "1.99.8" },
{ name: "clusterio_lib", enabled: true, version: "0.1.2", sha1: "012345abcd" },
],
settings: {
"startup": {
"bool-setting": { "value": true },
},
"runtime-global": {
"number-setting": { "value": 123 },
},
"runtime-per-user": {
"string-setting": { "value": "a string" },
},
},
export_manifest: { assets: { setting: "settings.json" }},
deleted: true,
}));
});
it("should sort integer factorio versions lexicographically", function() {
let unsortedVersions = ["1.0", "1.1.0", "0.1", "3.0.0", "1.2", "0.3.1", "0.3.3", "2.1.1", "0.0.1"];
let sortedVersions = ["0.0.1", "0.1", "0.3.1", "0.3.3", "1.0", "1.1.0", "1.2", "2.1.1", "3.0.0"];
let factorioMods = unsortedVersions.map(v => ModPack.fromJSON({ factorio_version: v }));
factorioMods.sort((a, b) => a.integerFactorioVersion - b.integerFactorioVersion);
assert.deepEqual(factorioMods.map(mod => mod.factorioVersion), sortedVersions);
});
describe(".fillDefaultSettings()", function() {
const prototypes = {
"bool-setting": {
"bool": {
name: "bool",
type: "bool-setting",
setting_type: "startup",
default_value: true,
},
},
"double-setting": {
"number": {
name: "number",
type: "double-setting",
setting_type: "runtime-global",
default_value: 123,
},
},
"string-setting": {
"string": {
name: "string",
type: "string-setting",
setting_type: "runtime-per-user",
default_value: "a string",
},
},
};
const mockLogger = { warn: () => {} };
it("should fill in defaults for settings", function() {
const pack = ModPack.fromJSON({});
pack.fillDefaultSettings(prototypes, mockLogger);
assert.deepEqual(pack.toJSON().settings, {
"startup": {
"bool": { "value": true },
},
"runtime-global": {
"number": { "value": 123 },
},
"runtime-per-user": {
"string": { "value": "a string" },
},
});
});
it("should not overwrite existing values", function() {
const pack = ModPack.fromJSON({ settings: {
"startup": {
"bool": { "value": false },
},
"runtime-global": {
"number": { "value": 2 },
},
"runtime-per-user": {
"string": { "value": "spam" },
},
}});
pack.fillDefaultSettings(prototypes, mockLogger);
assert.deepEqual(pack.toJSON().settings, {
"startup": {
"bool": { "value": false },
},
"runtime-global": {
"number": { "value": 2 },
},
"runtime-per-user": {
"string": { "value": "spam" },
},
});
});
it("should ignore unknown setting_type and missing default_value", function() {
const pack = ModPack.fromJSON({});
pack.fillDefaultSettings({
"string-setting": {
"foo": {
name: "foo",
type: "string-setting",
setting_type: "magic-that-does-not-exist",
default_value: "a string",
},
"bar": {
name: "bar",
type: "string-setting",
setting_type: "startup",
},
},
}, mockLogger);
assert.deepEqual(pack.toJSON().settings, {
"startup": {},
"runtime-global": {},
"runtime-per-user": {},
});
});
});
describe(".fromModPackString()", function() {
it("should handle malformed strings", function() {
assert.throws(
() => ModPack.fromModPackString("AMalformedString"),
new Error("Malformed mod pack string: zlib inflate failed")
);
let badJsonMsg;
try {
JSON.parse("Not Json");
} catch (err) {
badJsonMsg = err.message;
}
assert.throws(
// eslint-disable-next-line node/no-sync
() => ModPack.fromModPackString(Buffer.from(zlib.deflateSync("Not Json")).toString("base64")),
new Error(`Malformed mod pack string: ${badJsonMsg}`)
);
assert.throws(
// eslint-disable-next-line node/no-sync
() => ModPack.fromModPackString(Buffer.from(zlib.deflateSync('{"i":1}')).toString("base64")),
new Error("Malformed mod pack string: Schema validation failed")
);
});
});
describe("toModSettingsDat()", function() {
it("should properly serialise settings", function() {
const pack = ModPack.fromJSON({ settings: {
"startup": {
"bool-setting": { "value": true },
},
"runtime-global": {
"number-setting": { "value": 123 },
},
"runtime-per-user": {
"string-setting": { "value": "a string" },
},
}});
function istr(str) {
return [
Uint8Array.from([0, str.length]),
Buffer.from(str),
];
}
/* eslint-disable indent */
assert.deepEqual(
pack.toModSettingsDat(),
Buffer.concat([
new Uint8Array(Uint16Array.from([1, 1, 0, 0]).buffer), // version
Uint8Array.from([0]), // reserved
Uint8Array.from([5, 0]), // dictionary
new Uint8Array(Uint32Array.from([3]).buffer), // items
...istr("startup"), // name
Uint8Array.from([5, 0]), // dictionary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("bool-setting"), // name
Uint8Array.from([5, 0]), // dictinary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("value"), // name
Uint8Array.from([1, 0, 1]), // boolean
...istr("runtime-global"), // name
Uint8Array.from([5, 0]), // dictionary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("number-setting"), // name
Uint8Array.from([5, 0]), // dictinary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("value"), // name
Uint8Array.from([2, 0]), // number
new Uint8Array(Float64Array.from([123]).buffer),
...istr("runtime-per-user"), // name
Uint8Array.from([5, 0]), // dictionary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("string-setting"), // name
Uint8Array.from([5, 0]), // dictinary
new Uint8Array(Uint32Array.from([1]).buffer), // items
...istr("value"), // name
Uint8Array.from([3, 0, 0, "a string".length]), // string
Buffer.from("a string"),
])
);
/* eslint-enable indent */
});
});
});
});