From 395925ad2b82e3c73dc3ecbb6b5533f46ec76ab8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 26 May 2017 00:33:32 -0400 Subject: [PATCH] fix errors handling dependencies if some mods have no manifest --- .../ModResolverTests.cs | 36 +++++++++++++++++++ .../Framework/ModLoading/ModResolver.cs | 6 ++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/StardewModdingAPI.Tests/ModResolverTests.cs b/src/StardewModdingAPI.Tests/ModResolverTests.cs index 46c1c0cf..23aeba64 100644 --- a/src/StardewModdingAPI.Tests/ModResolverTests.cs +++ b/src/StardewModdingAPI.Tests/ModResolverTests.cs @@ -245,6 +245,20 @@ namespace StardewModdingAPI.Tests Assert.AreSame(modC.Object, mods[2], "The load order unexpectedly changed with no dependencies."); } + [Test(Description = "Assert that processing dependencies skips mods that have already failed without calling any other properties.")] + public void ProcessDependencies_Skips_Failed() + { + // arrange + Mock mock = new Mock(MockBehavior.Strict); + mock.Setup(p => p.Status).Returns(ModMetadataStatus.Failed); + + // act + new ModResolver().ProcessDependencies(new[] { mock.Object }); + + // assert + mock.VerifyGet(p => p.Status, Times.Once, "The validation did not check the manifest status."); + } + [Test(Description = "Assert that simple dependencies are reordered correctly.")] public void ProcessDependencies_Reorders_SimpleDependencies() { @@ -342,6 +356,28 @@ namespace StardewModdingAPI.Tests modE.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny()), Times.Once, "Mod E was expected to fail since it's part of a dependency loop."); } + [Test(Description = "Assert that dependencies are sorted correctly even if some of the mods failed during metadata loading.")] + public void ProcessDependencies_WithSomeFailedMods_Succeeds() + { + // arrange + // A ◀── B ◀── C D (failed) + Mock modA = this.GetMetadataForDependencyTest("Mod A"); + Mock modB = this.GetMetadataForDependencyTest("Mod B", dependencies: new[] { "Mod A" }); + Mock modC = this.GetMetadataForDependencyTest("Mod C", dependencies: new[] { "Mod B" }, allowStatusChange: true); + Mock modD = new Mock(MockBehavior.Strict); + modD.Setup(p => p.Manifest).Returns(null); + modD.Setup(p => p.Status).Returns(ModMetadataStatus.Failed); + + // act + IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object, modD.Object }).ToArray(); + + // assert + Assert.AreEqual(4, mods.Length, 0, "Expected to get the same number of mods input."); + Assert.AreSame(modD.Object, mods[0], "The load order is incorrect: mod D should be first since it was already failed."); + Assert.AreSame(modA.Object, mods[1], "The load order is incorrect: mod A should be second since it's needed by mod B."); + Assert.AreSame(modB.Object, mods[2], "The load order is incorrect: mod B should be third since it needs mod A, and is needed by mod C."); + Assert.AreSame(modC.Object, mods[3], "The load order is incorrect: mod C should be fourth since it needs mod B, and is needed by mod D."); + } /********* ** Private methods diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index 21aebeb1..f5139ce5 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -141,7 +141,7 @@ namespace StardewModdingAPI.Framework.ModLoading states[mod] = ModDependencyStatus.Failed; sortedMods.Push(mod); } - + // sort mods foreach (IModMetadata mod in mods) this.ProcessDependencies(mods.ToArray(), mod, states, sortedMods, new List()); @@ -198,7 +198,7 @@ namespace StardewModdingAPI.Framework.ModLoading string[] missingModIDs = ( from dependency in mod.Manifest.Dependencies - where mods.All(m => m.Manifest.UniqueID != dependency.UniqueID) + where mods.All(m => m.Manifest?.UniqueID != dependency.UniqueID) orderby dependency.UniqueID select dependency.UniqueID ) @@ -219,7 +219,7 @@ namespace StardewModdingAPI.Framework.ModLoading IModMetadata[] modsToLoadFirst = ( from other in mods - where mod.Manifest.Dependencies.Any(required => required.UniqueID == other.Manifest.UniqueID) + where mod.Manifest.Dependencies.Any(required => required.UniqueID == other.Manifest?.UniqueID) select other ) .ToArray();