Add support for recommended mod dependencies (#946)

This commit is contained in:
Cooldude2606 authored and GitHub committed 2026-07-18 21:57:50 +01:00
1 parent 5758cd94b6
commit 198ea76674
4 files changed
+119 -21

No files matched your search

+22 -6
View File
@@ -217,23 +217,29 @@ describe("lib/data/ModInfo", function() {
const dependency = new ModDependency("! my-mod");
assert.equal(dependency.isSatisfied(mods), false);
});
it("should pass for optional / hidden being missing", function() {
it("should pass for optional / hidden / recommended being missing", function() {
const dependencyOptional = new ModDependency("? not-present");
assert.equal(dependencyOptional.isSatisfied(mods), true);
const dependencyHidden = new ModDependency("(?) not-present");
assert.equal(dependencyHidden.isSatisfied(mods), true);
const dependencyRecommended = new ModDependency("+ not-present");
assert.equal(dependencyRecommended.isSatisfied(mods), true);
});
it("should pass for optional / hidden being present", function() {
it("should pass for optional / hidden / recommended being present", function() {
const dependencyOptional = new ModDependency("? my-mod");
assert.equal(dependencyOptional.isSatisfied(mods), true);
const dependencyHidden = new ModDependency("(?) my-mod");
assert.equal(dependencyHidden.isSatisfied(mods), true);
const dependencyRecommended = new ModDependency("+ my-mod");
assert.equal(dependencyRecommended.isSatisfied(mods), true);
});
it("should fail for optional / hidden being present but wrong version", function() {
it("should fail for optional / hidden / recommended being present but wrong version", function() {
const dependencyOptional = new ModDependency("? my-mod > 2.0.0");
assert.equal(dependencyOptional.isSatisfied(mods), false);
const dependencyHidden = new ModDependency("(?) my-mod > 2.0.0");
assert.equal(dependencyHidden.isSatisfied(mods), false);
const dependencyRecommended = new ModDependency("+ my-mod > 2.0.0");
assert.equal(dependencyRecommended.isSatisfied(mods), false);
});
it("should pass for unordered / required being present", function() {
const dependencyOptional = new ModDependency("~ my-mod");
@@ -258,19 +264,29 @@ describe("lib/data/ModInfo", function() {
it("should return true iff the type is incompatible", function() {
const dependencyIncompatible = new ModDependency("! my-mod");
assert.equal(dependencyIncompatible.incompatible, true);
for (const test of ["my-mod", "? my-mod", "(?) my-mod", "~ my-mod"]) {
for (const test of ["my-mod", "? my-mod", "(?) my-mod", "~ my-mod", "+ my-mod"]) {
const dependency = new ModDependency(test);
assert.equal(dependency.incompatible, false, test);
}
});
});
describe("recommended", function() {
it("should return true iff the type is recommended", function() {
const dependencyIncompatible = new ModDependency("+ my-mod");
assert.equal(dependencyIncompatible.recommended, true);
for (const test of ["my-mod", "? my-mod", "(?) my-mod", "~ my-mod", "! my-mod"]) {
const dependency = new ModDependency(test);
assert.equal(dependency.recommended, false, test);
}
});
});
describe("required", function() {
it("should return true iff the dependency is required", function() {
for (const test of ["my-mod", "~ my-mod"]) {
const dependency = new ModDependency(test);
assert.equal(dependency.required, true, test);
}
for (const test of ["! my-mod", "? my-mod", "(?) my-mod"]) {
for (const test of ["! my-mod", "? my-mod", "(?) my-mod", "+ my-mod"]) {
const dependency = new ModDependency(test);
assert.equal(dependency.required, false, test);
}
@@ -282,7 +298,7 @@ describe("lib/data/ModInfo", function() {
const dependency = new ModDependency(test);
assert.equal(dependency.optional, true, test);
}
for (const test of ["! my-mod", "my-mod", "~ my-mod"]) {
for (const test of ["! my-mod", "my-mod", "~ my-mod", "+ my-mod"]) {
const dependency = new ModDependency(test);
assert.equal(dependency.optional, false, test);
}
+62 -4
View File
@@ -187,14 +187,16 @@ describe("messages/mod", function() {
});
});
describe("handle", function() {
const factorioVersions = ["1.0", "1.1", "2.0"];
const factorioVersions = ["1.0", "1.1", "2.0", "2.1"];
it("resolves dependencies", async function() {
for (const factorioVersion of factorioVersions) {
setPortalModRelease("root", "1.0.0", factorioVersion, ["foo", "bar < 2.0.0", "? baz"]);
setPortalModRelease("root", "1.0.0", factorioVersion, ["foo", "bar < 2.0.0", "? baz", "+ qux"]);
setPortalModRelease("foo", "1.0.0", factorioVersion, ["foo-dep"]);
setPortalModRelease("foo-dep", "1.0.0", factorioVersion, []);
setPortalModRelease("bar", "1.0.0", factorioVersion, []);
setPortalModRelease("baz", "1.0.0", factorioVersion, []);
setPortalModRelease("qux", "1.0.0", factorioVersion, ["qux-dep"]);
setPortalModRelease("qux-dep", "1.0.0", factorioVersion, []);
setPortalModRelease("root-2", "1.0.0", factorioVersion, ["foo", "bar-2"]);
setPortalModRelease("bar-2", "1.0.0", factorioVersion, []);
@@ -213,7 +215,7 @@ describe("messages/mod", function() {
const depIds = new Set(result.dependencies.map(mod => mod.id));
assert.deepEqual(depIds, new Set([
"root_1.0.0", "foo_1.0.0", "foo-dep_1.0.0", "bar_1.0.0",
"root-2_1.0.0", "bar-2_1.0.0",
"root-2_1.0.0", "bar-2_1.0.0", "qux_1.0.0", "qux-dep_1.0.0",
]));
}
});
@@ -307,6 +309,24 @@ describe("messages/mod", function() {
assert.deepEqual(depIds, new Set(["root_1.0.0", "foo_1.0.0"]));
}
});
it("ignores missing optional dependencies", async function() {
for (const factorioVersion of factorioVersions) {
setPortalModRelease("root", "1.0.0", factorioVersion, ["? foo"]);
const result = await controlConnection.handleModDependencyResolveRequest(
new lib.ModDependencyResolveRequest([new ModDependency("root")], factorioVersion),
);
assert.deepEqual(result.errors, new Map([
["base", "notFound"],
]));
const depIds = new Set(result.dependencies.map(mod => mod.id));
assert.deepEqual(depIds, new Set([
"root_1.0.0",
]));
}
});
it("does not ignore optional dependencies when required by another", async function() {
for (const factorioVersion of factorioVersions) {
setPortalModRelease("root", "1.0.0", factorioVersion, ["foo", "? baz"]);
@@ -325,6 +345,44 @@ describe("messages/mod", function() {
assert.deepEqual(depIds, new Set(["root_1.0.0", "foo_1.0.0", "baz_1.0.0"]));
}
});
it("ignores missing recommended dependencies", async function() {
for (const factorioVersion of factorioVersions) {
setPortalModRelease("root", "1.0.0", factorioVersion, ["+ foo"]);
const result = await controlConnection.handleModDependencyResolveRequest(
new lib.ModDependencyResolveRequest([new ModDependency("root")], factorioVersion),
);
assert.deepEqual(result.errors, new Map([
["base", "notFound"],
]));
const depIds = new Set(result.dependencies.map(mod => mod.id));
assert.deepEqual(depIds, new Set([
"root_1.0.0",
]));
}
});
it("does not ignore recommended dependencies when required by another", async function() {
for (const factorioVersion of factorioVersions) {
setPortalModRelease("root", "1.0.0", factorioVersion, ["+ baz", "foo"]);
setPortalModRelease("foo", "1.0.0", factorioVersion, ["baz"]);
setPortalModRelease("baz", "1.0.0", factorioVersion, []);
const result = await controlConnection.handleModDependencyResolveRequest(
new lib.ModDependencyResolveRequest([new ModDependency("root")], factorioVersion),
);
assert.deepEqual(result.errors, new Map([
["base", "notFound"],
]));
const depIds = new Set(result.dependencies.map(mod => mod.id));
assert.deepEqual(depIds, new Set([
"root_1.0.0", "foo_1.0.0", "baz_1.0.0",
]));
}
});
it("prefers the locally installed version if matching", async function() {
controller.modStore.addMod(lib.ModInfo.fromJSON({ name: "foo", version: "1.0.0" }));
for (const factorioVersion of factorioVersions) {
@@ -426,7 +484,7 @@ describe("messages/mod", function() {
"pyalienlife", "pyalienlifegraphics", "pyalienlifegraphics2", "pyalienlifegraphics3",
"pycoalprocessing", "pycoalprocessinggraphics", "pyfusionenergy", "pyfusionenergygraphics",
"pypetroleumhandling", "pypetroleumhandlinggraphics", "pyrawores", "pyraworesgraphics",
"pyhightech", "pyhightechgraphics", "pyindustry", "pyindustrygraphics",
"pyhightech", "pyhightechgraphics", "pyindustry", "pyindustrygraphics", "enable-all-feature-flags",
]));
});
});