From ae6e25d1b966d18656e230fb2440235e33a24b93 Mon Sep 17 00:00:00 2001 From: Bastiaan <17990055+bbassie@users.noreply.github.com> Date: Thu, 8 Oct 2026 21:57:00 +0200 Subject: [PATCH] Add regression tests for #704 and #705 (#1060) Covers the icon_size default of 64 in the export icon loaders and the host recreating saves and script-output when an instance is assigned. Both tests fail when the original fix is reverted. Closes #710 Co-authored-by: Claude Opus 5.5 --- packages/host/src/export.ts | 6 ++- .../data/base/graphics/icons/test-icon.png | Bin 0 -> 206 bytes test/host/Host.test.js | 42 ++++++++++++++++++ test/host/export.js | 40 +++++++++++++---- 4 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 test/file/factorio/0.1.2/data/base/graphics/icons/test-icon.png diff --git a/packages/host/src/export.ts b/packages/host/src/export.ts index e8986af2..eeda2594 100644 --- a/packages/host/src/export.ts +++ b/packages/host/src/export.ts @@ -160,7 +160,7 @@ async function loadSimpleIcon( item: SimpleIconSpecification, size: number, iconCache: IconCache, -) { +): Promise { let icon = await loadIcon(server, modVersions, item.icon, item.icon_size ?? 64, 0, iconCache); if (icon) { let iconScale = size / (item.icon_size ?? 64); @@ -178,7 +178,7 @@ async function loadLayeredIcon( item: LayeredIconSpecification, size: number, iconCache: IconCache, -) { +): Promise { let baseLayerSize = (item.icons[0].icon_size || item.icon_size) ?? 64; let icon = new Jimp({ width: size, height: size }); @@ -590,3 +590,5 @@ export async function exportData(server: FactorioServer) { // For testing only export const _exportLocale = exportLocale; +export const _loadSimpleIcon = loadSimpleIcon; +export const _loadLayeredIcon = loadLayeredIcon; diff --git a/test/file/factorio/0.1.2/data/base/graphics/icons/test-icon.png b/test/file/factorio/0.1.2/data/base/graphics/icons/test-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b2f06cccc1810f3be8ee688a20407b7a133fd628 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^2|($9&iw7G06K< zeecwRz)9r=e{MWB=w0C!qP$A*YDbof=_08>I&pt7R538u=|BHz1au&Sr>mdKI;Vst E07RZjv;Y7A literal 0 HcmV?d00001 diff --git a/test/host/Host.test.js b/test/host/Host.test.js index 5a93a9de..bbfffc58 100644 --- a/test/host/Host.test.js +++ b/test/host/Host.test.js @@ -1,4 +1,5 @@ import assert from "node:assert/strict"; +import fs from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -236,6 +237,47 @@ describe("host/src/Host", function() { }); }); }); + describe(".handleInstanceAssignInternalRequest()", function() { + const instancesDir = path.join("temp", "test", "host_assign"); + let host; + beforeEach(async function() { + await fs.rm(instancesDir, { recursive: true, force: true }); + await fs.mkdir(instancesDir, { recursive: true }); + const hostConfig = new lib.HostConfig("host", { "host.instances_directory": instancesDir }); + const hostConnector = new HostConnector(hostConfig, []); + host = new Host(hostConnector, hostConfig, []); + host.send = () => {}; + }); + function assignRequest(id, name) { + const config = new lib.InstanceConfig("controller", { "instance.id": id, "instance.name": name }); + return new lib.InstanceAssignInternalRequest(id, config.toRemote("host")); + } + + it("creates the folders for a new instance", async function() { + await host.handleInstanceAssignInternalRequest(assignRequest(1, "new")); + const instancePath = path.join(instancesDir, "new"); + assert.equal(host.discoveredInstances.get(1).path, instancePath); + await fs.access(path.join(instancePath, "saves")); + await fs.access(path.join(instancePath, "script-output")); + }); + it("recreates missing folders for a discovered instance", async function() { + const instancePath = path.join(instancesDir, "existing"); + await fs.mkdir(instancePath); + const configPath = path.join(instancePath, "instance.json"); + host.discoveredInstances.set(2, { + path: instancePath, + config: new lib.InstanceConfig("host", { + ...Host.instanceConfigWarning, + "instance.id": 2, + "instance.name": "existing", + }, configPath), + }); + + await host.handleInstanceAssignInternalRequest(assignRequest(2, "existing")); + await fs.access(path.join(instancePath, "saves")); + await fs.access(path.join(instancePath, "script-output")); + }); + }); describe(".handleHostRestartRequest()", function() { let mockHost; beforeEach(function() { diff --git a/test/host/export.js b/test/host/export.js index a9131584..6c551b7c 100644 --- a/test/host/export.js +++ b/test/host/export.js @@ -2,18 +2,18 @@ import assert from "node:assert/strict"; import path from "node:path"; import { FactorioServer } from "@clusterio/host/dist/node/src/server.js"; -import { _exportLocale } from "@clusterio/host/dist/node/src/export.js"; +import { _exportLocale, _loadLayeredIcon, _loadSimpleIcon } from "@clusterio/host/dist/node/src/export.js"; describe("host/src/export", function() { - describe("exportLocale()", function() { - let testServer; - before(async function() { - let writePath = path.join("temp", "test", "server"); - testServer = new FactorioServer(path.join("test", "file", "factorio"), writePath, {}); - await testServer.init(); - }); + let testServer; + before(async function() { + let writePath = path.join("temp", "test", "server"); + testServer = new FactorioServer(path.join("test", "file", "factorio"), writePath, {}); + await testServer.init(); + }); + describe("exportLocale()", function() { it("returns a flattened mapping with locale definitions", async function() { let locale = await _exportLocale(testServer, new Map(), ["base"], "en"); assert.deepEqual(locale, new Map([ @@ -28,4 +28,28 @@ describe("host/src/export", function() { ])); }); }); + + // test-icon.png is a red 64px icon followed by a blue 32px mipmap + const red = 0xff0000ff; + describe("loadSimpleIcon()", function() { + it("defaults icon_size to 64", async function() { + const icon = await _loadSimpleIcon( + testServer, new Map(), { icon: "__base__/graphics/icons/test-icon.png" }, 32, new Map() + ); + assert.equal(icon.bitmap.width, 32); + assert.equal(icon.bitmap.height, 32); + assert.equal(icon.getPixelColor(31, 16), red); + }); + }); + describe("loadLayeredIcon()", function() { + it("defaults icon_size to 64", async function() { + const icon = await _loadLayeredIcon( + testServer, new Map(), { icons: [{ icon: "__base__/graphics/icons/test-icon.png" }] }, 32, new Map() + ); + assert.equal(icon.bitmap.width, 32); + assert.equal(icon.bitmap.height, 32); + assert.equal(icon.getPixelColor(0, 0), red); + assert.equal(icon.getPixelColor(31, 31), red); + }); + }); });