diff --git a/sample/SampleApplication/SampleApplication.csproj b/sample/SampleApplication/SampleApplication.csproj
index a40c100..c332fcf 100644
--- a/sample/SampleApplication/SampleApplication.csproj
+++ b/sample/SampleApplication/SampleApplication.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/PetroGlyph.Games.EawFoc/src/PG.StarWarsGame.Infrastructure.csproj b/src/PetroGlyph.Games.EawFoc/src/PG.StarWarsGame.Infrastructure.csproj
index fb3fc10..7097e61 100644
--- a/src/PetroGlyph.Games.EawFoc/src/PG.StarWarsGame.Infrastructure.csproj
+++ b/src/PetroGlyph.Games.EawFoc/src/PG.StarWarsGame.Infrastructure.csproj
@@ -22,10 +22,10 @@
true
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/PetroGlyph.Games.EawFoc/src/PetroglyphGameInfrastructure.cs b/src/PetroGlyph.Games.EawFoc/src/PetroglyphGameInfrastructure.cs
index 9222120..78d7078 100644
--- a/src/PetroGlyph.Games.EawFoc/src/PetroglyphGameInfrastructure.cs
+++ b/src/PetroGlyph.Games.EawFoc/src/PetroglyphGameInfrastructure.cs
@@ -28,7 +28,6 @@ public static void InitializeServices(IServiceCollection serviceCollection)
serviceCollection.AddSingleton(sp => new SteamGameHelpers(sp));
serviceCollection.AddSingleton(sp => new GameFactory(sp));
//serviceCollection.AddSingleton(sp => new ModFactory(sp));
- serviceCollection.AddSingleton(sp => new ModIdentifierBuilder(sp));
serviceCollection.AddSingleton(sp => new ModFinder(sp));
serviceCollection.AddSingleton(sp => new ModReferenceLocationResolver(sp));
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/DetectedModReference.cs b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/DetectedModReference.cs
deleted file mode 100644
index 7be0be4..0000000
--- a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/DetectedModReference.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.IO.Abstractions;
-using EawModinfo.Spec;
-
-namespace PG.StarWarsGame.Infrastructure.Services.Detection;
-
-///
-/// Represents a detected mod reference with the optional associated .
-///
-public sealed class DetectedModReference
-{
- ///
- /// Initializes a new instance of the with the specified mod reference and modinfo.
- ///
- /// The detected mod reference.
- /// The directory of the mod.
- /// The optional detected modinfo.
- /// is .
- public DetectedModReference(IModReference modReference, IDirectoryInfo directory, IModinfo? modInfo)
- {
- ModReference = modReference ?? throw new ArgumentNullException(nameof(modReference));
- ModInfo = modInfo;
- Directory = directory;
- }
-
- ///
- /// Gets the detected mod reference.
- ///
- public IModReference ModReference { get; }
-
- ///
- /// Gets the detected directory of the mod.
- ///
- /// The value can be , if the detected mod reference is a virtual mod.
- public IDirectoryInfo? Directory { get; }
-
- ///
- /// Gets the detected modinfo or if none was detected.
- ///
- public IModinfo? ModInfo { get; }
-}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModIdentifierBuilder.cs b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModIdentifierBuilder.cs
deleted file mode 100644
index 6acc291..0000000
--- a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModIdentifierBuilder.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.IO.Abstractions;
-using EawModinfo.Model;
-using EawModinfo.Spec;
-using PG.StarWarsGame.Infrastructure.Mods;
-
-namespace PG.StarWarsGame.Infrastructure.Services.Detection;
-
-internal interface IModIdentifierBuilder
-{
- string Build(IDirectoryInfo modDirectory, bool isWorkshop);
-
- string Build(IMod mod);
-
- ModReference Normalize(IModReference modReference);
-}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModReferenceFinder.cs b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModReferenceFinder.cs
index 7940ab4..36d5485 100644
--- a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModReferenceFinder.cs
+++ b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/IModReferenceFinder.cs
@@ -1,5 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using EawModinfo.Spec;
+using EawModinfo.Utilities;
using PG.StarWarsGame.Infrastructure.Games;
namespace PG.StarWarsGame.Infrastructure.Services.Detection;
@@ -10,9 +12,11 @@ namespace PG.StarWarsGame.Infrastructure.Services.Detection;
public interface IModFinder
{
///
- /// Searches for for a given game.
+ /// Searches for physically installed mods for the specified game.
///
/// The game to search mods for.
- /// A set of detected mod references.
- ISet FindMods(IGame game);
+ /// A collection of installed mods of .
+ /// is .
+ /// does not exist.
+ ICollection FindMods(IGame game);
}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModFinder.cs b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModFinder.cs
index 4e3972f..d70cb8a 100644
--- a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModFinder.cs
+++ b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModFinder.cs
@@ -3,8 +3,8 @@
using System.IO.Abstractions;
using System.Linq;
using EawModinfo.File;
-using EawModinfo.Model;
using EawModinfo.Spec;
+using EawModinfo.Utilities;
using Microsoft.Extensions.DependencyInjection;
using PG.StarWarsGame.Infrastructure.Games;
using PG.StarWarsGame.Infrastructure.Services.Steam;
@@ -14,19 +14,15 @@ namespace PG.StarWarsGame.Infrastructure.Services.Detection;
internal class ModFinder : IModFinder
{
private readonly ISteamGameHelpers _steamHelper;
- private readonly IModIdentifierBuilder _idBuilder;
private readonly IModGameTypeResolver _gameTypeResolver;
public ModFinder(IServiceProvider serviceProvider)
{
- if (serviceProvider == null)
- throw new ArgumentNullException(nameof(serviceProvider));
- _idBuilder = serviceProvider.GetRequiredService();
_steamHelper = serviceProvider.GetRequiredService();
_gameTypeResolver = serviceProvider.GetRequiredService();
}
- public ISet FindMods(IGame game)
+ public ICollection FindMods(IGame game)
{
if (game == null)
throw new ArgumentNullException(nameof(game));
@@ -34,57 +30,36 @@ public ISet FindMods(IGame game)
if (!game.Exists())
throw new GameException("The game does not exist");
- var mods = new HashSet();
- foreach (var modReference in GetNormalMods(game).Union(GetWorkshopsMods(game)))
- mods.Add(modReference);
- return mods;
+ return GetNormalMods(game).Union(GetWorkshopsMods(game)).ToList();
}
private IEnumerable GetNormalMods(IGame game)
{
- return GetAllModsFromPath(game.ModsLocation, false, game.Type);
+ return GetAllModsFromPath(game.ModsLocation, ModReferenceBuilder.ModLocationKind.GameModsDirectory, game.Type);
}
private IEnumerable GetWorkshopsMods(IGame game)
{
return game.Platform != GamePlatform.SteamGold
? []
- : GetAllModsFromPath(_steamHelper.GetWorkshopsLocation(game), true, game.Type);
+ : GetAllModsFromPath(_steamHelper.GetWorkshopsLocation(game), ModReferenceBuilder.ModLocationKind.SteamWorkshops, game.Type);
}
- private IEnumerable GetAllModsFromPath(IDirectoryInfo lookupDirectory, bool isWorkshopsPath, GameType requestedGameType)
+ private IEnumerable GetAllModsFromPath(IDirectoryInfo lookupDirectory, ModReferenceBuilder.ModLocationKind locationKind, GameType requestedGameType)
{
if (!lookupDirectory.Exists)
yield break;
- var type = isWorkshopsPath ? ModType.Workshops : ModType.Default;
-
foreach (var modDirectory in lookupDirectory.EnumerateDirectories())
{
- var modinfoFiles = ModinfoFileFinder.FindModinfoFiles(modDirectory);
-
- IModinfo? mainModinfo = null;
-
- // Since the concept of modinfo files is completely optional,
- // a malformed modinfo file should not cause a crash. The mod in question gets fond without a modinfo.
- modinfoFiles.MainModinfo?.TryGetModinfo(out mainModinfo);
-
- if (IsDefinitelyNotGameType(requestedGameType, modDirectory, type, mainModinfo))
- continue;
+ ModinfoFinderCollection modinfoFiles;
+ modinfoFiles = ModinfoFileFinder.FindModinfoFiles(modDirectory);
- var id = _idBuilder.Build(modDirectory, isWorkshopsPath);
- yield return new DetectedModReference(new ModReference(id, type), modDirectory, mainModinfo);
-
- foreach (var variantModinfoFile in modinfoFiles.Variants)
+ foreach (var modRef in ModReferenceBuilder.CreateIdentifiers(modinfoFiles, locationKind))
{
- if (!variantModinfoFile.TryGetModinfo(out var variantModinfo))
- continue;
-
- if (IsDefinitelyNotGameType(requestedGameType, modDirectory, type, variantModinfo))
+ if (IsDefinitelyNotGameType(requestedGameType, modDirectory, modRef.ModReference.Type, modRef.Modinfo))
continue;
-
- id = _idBuilder.Build(modDirectory, isWorkshopsPath);
- yield return new DetectedModReference(new ModReference(id, type), modDirectory, variantModinfo);
+ yield return modRef;
}
}
}
@@ -94,6 +69,6 @@ private bool IsDefinitelyNotGameType(GameType expected, IDirectoryInfo modDirect
// If the type resolver was unable to find the type, we have to assume that the current mod matches to the game.
// Otherwise, we'd produce false negatives. Only if the resolver was able to determine a result, we use that finding.
return _gameTypeResolver.TryGetGameType(modDirectory, modType, modinfo, out var variantGameType) &&
- variantGameType.Contains(expected);
+ !variantGameType.Contains(expected);
}
}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModIdentifierBuilder.cs b/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModIdentifierBuilder.cs
deleted file mode 100644
index d4560c4..0000000
--- a/src/PetroGlyph.Games.EawFoc/src/Services/Detection/Mods/ModIdentifierBuilder.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using System;
-using System.IO.Abstractions;
-using AnakinRaW.CommonUtilities.FileSystem.Normalization;
-using EawModinfo.Model;
-using EawModinfo.Spec;
-using Microsoft.Extensions.DependencyInjection;
-using PG.StarWarsGame.Infrastructure.Mods;
-using PG.StarWarsGame.Infrastructure.Services.Steam;
-
-namespace PG.StarWarsGame.Infrastructure.Services.Detection;
-
-internal class ModIdentifierBuilder : IModIdentifierBuilder
-{
- private readonly ISteamGameHelpers _steamGameHelper;
-
- private static readonly PathNormalizeOptions PathNormalizeOptions = new()
- {
- UnifyCase = UnifyCasingKind.UpperCase,
- TrailingDirectorySeparatorBehavior = TrailingDirectorySeparatorBehavior.Trim
- };
-
- ///
- /// Creates a new instance.
- ///
- /// The service provider.
- public ModIdentifierBuilder(IServiceProvider serviceProvider)
- {
- _steamGameHelper = serviceProvider.GetRequiredService();
- }
-
- public string Build(IDirectoryInfo modDirectory, bool isWorkshop)
- {
- return isWorkshop ? BuildWorkshopsModId(modDirectory) : BuildDefaultModId(modDirectory);
- }
-
- ///
- public string Build(IMod mod)
- {
- if (mod.Type == ModType.Default)
- {
- if (mod is not IPhysicalMod physicalMod)
- throw new InvalidOperationException();
- return BuildDefaultModId(physicalMod.Directory);
- }
-
- if (mod.Type == ModType.Workshops)
- {
- if (mod is not IPhysicalMod physicalMod)
- throw new InvalidOperationException();
- return BuildWorkshopsModId(physicalMod.Directory);
- }
-
- if (mod.Type == ModType.Virtual)
- {
- if (mod is not IVirtualMod virtualMod)
- throw new InvalidOperationException();
- return BuildVirtualModId(virtualMod);
- }
-
- throw new NotSupportedException($"Cannot create identifier for unsupported mod type {mod.Type}.");
- }
-
- private static string BuildDefaultModId(IDirectoryInfo modDir)
- {
- return BuildDefaultModId(modDir.FullName);
- }
-
- private static string BuildDefaultModId(string modDirPath)
- {
- // NB: We don't want to resolve the path, cause the string is user data which could be abused to traverse paths.
- // Though, this is not a complete fix. Consumers of a mod's Identifier property still must validate the data.
- return PathNormalizer.Normalize(modDirPath, PathNormalizeOptions);
- }
-
- private string BuildWorkshopsModId(IDirectoryInfo modDir)
- {
- if (!_steamGameHelper.ToSteamWorkshopsId(modDir.Name, out _))
- throw new InvalidOperationException($"{modDir} is not a valid Steam Workshop directory.");
- return modDir.Name;
- }
-
- private static string BuildVirtualModId(IVirtualMod mod)
- {
- if (mod.ModInfo is null)
- throw new NotSupportedException("Virtual mods without modinfo data are not supported.");
- return mod.ModInfo.ToJson();
- }
-
- public ModReference Normalize(IModReference modReference)
- {
- var id = modReference.Type switch
- {
- ModType.Default => BuildDefaultModId(modReference.Identifier),
- ModType.Workshops => modReference.Identifier,
- ModType.Virtual => modReference.Identifier,
- _ => throw new ArgumentOutOfRangeException()
- };
- return new ModReference(id, modReference.Type, modReference.VersionRange);
- }
-}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/src/Services/IModFactory.cs b/src/PetroGlyph.Games.EawFoc/src/Services/IModFactory.cs
index cb2164b..95ae35c 100644
--- a/src/PetroGlyph.Games.EawFoc/src/Services/IModFactory.cs
+++ b/src/PetroGlyph.Games.EawFoc/src/Services/IModFactory.cs
@@ -1,9 +1,9 @@
using System.Globalization;
using System.IO;
using EawModinfo.Spec;
+using EawModinfo.Utilities;
using PG.StarWarsGame.Infrastructure.Games;
using PG.StarWarsGame.Infrastructure.Mods;
-using PG.StarWarsGame.Infrastructure.Services.Detection;
namespace PG.StarWarsGame.Infrastructure.Services;
diff --git a/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/DirectoryGameDetectorTest.cs b/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/DirectoryGameDetectorTest.cs
index a173353..ea186ca 100644
--- a/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/DirectoryGameDetectorTest.cs
+++ b/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/DirectoryGameDetectorTest.cs
@@ -1,6 +1,5 @@
using System;
using System.IO.Abstractions;
-using Moq;
using PG.StarWarsGame.Infrastructure.Games;
using PG.StarWarsGame.Infrastructure.Services.Detection;
using PG.StarWarsGame.Infrastructure.Testing.Game.Installation;
@@ -28,10 +27,9 @@ protected override GameDetectorTestInfo SetupGame(GameIdentity game
[Fact]
public void InvalidArgs_Throws()
{
- var sp = new Mock();
Assert.Throws(() => new DirectoryGameDetector(null!, null!));
Assert.Throws(() => new DirectoryGameDetector(FileSystem.DirectoryInfo.New("Game"), null!));
- Assert.Throws(() => new DirectoryGameDetector(null!, sp.Object));
+ Assert.Throws(() => new DirectoryGameDetector(null!, ServiceProvider));
}
[Theory]
diff --git a/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/RegistryGameDetectorTest.cs b/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/RegistryGameDetectorTest.cs
index 2e9a821..d8728a7 100644
--- a/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/RegistryGameDetectorTest.cs
+++ b/src/PetroGlyph.Games.EawFoc/test/GameServices/Detection/RegistryGameDetectorTest.cs
@@ -107,7 +107,7 @@ public void Dispose_ShallDisposeRegistries(GameIdentity identity)
false, ServiceProvider);
detector.Dispose();
- Assert.Throws(() => info.DetectorSetupInfo.EawRegistry.CdKey);
- Assert.Throws(() => info.DetectorSetupInfo.FocRegistry.CdKey);
+ Assert.Throws(() => info.DetectorSetupInfo.EawRegistry!.CdKey);
+ Assert.Throws(() => info.DetectorSetupInfo.FocRegistry!.CdKey);
}
}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/test/ModServices/ModFinderTest.cs b/src/PetroGlyph.Games.EawFoc/test/ModServices/ModFinderTest.cs
index 703096f..32bb9ff 100644
--- a/src/PetroGlyph.Games.EawFoc/test/ModServices/ModFinderTest.cs
+++ b/src/PetroGlyph.Games.EawFoc/test/ModServices/ModFinderTest.cs
@@ -1,302 +1,277 @@
using System;
-using System.IO.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using EawModinfo.Model;
+using EawModinfo.Spec.Steam;
using Microsoft.Extensions.DependencyInjection;
-using Moq;
using PG.StarWarsGame.Infrastructure.Games;
using PG.StarWarsGame.Infrastructure.Services.Detection;
using PG.StarWarsGame.Infrastructure.Services.Steam;
+using PG.StarWarsGame.Infrastructure.Testing;
using PG.StarWarsGame.Infrastructure.Testing.Game.Installation;
-using Testably.Abstractions.Testing;
+using PG.StarWarsGame.Infrastructure.Testing.Mods;
+using PG.TestingUtilities;
using Xunit;
namespace PG.StarWarsGame.Infrastructure.Test.ModServices;
-public class ModFinderTest
+public class ModFinderTest : CommonTestBase
{
- private readonly IServiceProvider _serviceProvider;
- private readonly ModFinder _service;
- private readonly Mock _steamHelper;
- private readonly MockFileSystem _fileSystem;
- private readonly Mock _idBuilder;
- private readonly Mock _gameTypeResolver;
+ private readonly ModFinder _modFinder;
+ private readonly ISteamGameHelpers _steamGameHelpers;
public ModFinderTest()
{
- var sc = new ServiceCollection();
- _steamHelper = new Mock();
- _fileSystem = new MockFileSystem();
- _idBuilder = new Mock();
- _gameTypeResolver = new Mock();
- sc.AddSingleton(_ => _steamHelper.Object);
- sc.AddSingleton(_ => _fileSystem);
- sc.AddSingleton(_ => _idBuilder.Object);
- sc.AddSingleton(_ => _gameTypeResolver.Object);
-
- _serviceProvider = sc.BuildServiceProvider();
- _service = new ModFinder(_serviceProvider);
+ _modFinder = new ModFinder(ServiceProvider);
+ _steamGameHelpers = ServiceProvider.GetRequiredService();
}
[Fact]
- public void GameNotExists_Throws()
+ public void FindMods_NullArg_Throws()
{
- var game = new Mock();
- Assert.Throws(() => _service.FindMods(game.Object));
+ Assert.Throws(() => _modFinder.FindMods(null!));
}
- [Fact]
- public void TestNoMods_Normal()
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_GameNotExists_Throws(GameIdentity gameIdentity)
{
- var game = _fileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.Disk), _serviceProvider);
- var mods = _service.FindMods(game);
- Assert.Empty(mods);
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+ game.Directory.Delete(true);
+ Assert.Throws(() => _modFinder.FindMods(game));
}
- [Fact]
- public void TestNoMods_Normal_NoFolder()
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_NoModsDirectory_ShouldNotFindMods(GameIdentity gameIdentity)
{
- _fileSystem.Initialize().WithSubdirectory("Game");
- var game = new Mock();
- game.Setup(g => g.Exists()).Returns(true);
- game.Setup(g => g.Platform).Returns(GamePlatform.Disk);
- game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Game"));
- game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Game/Mods"));
- var mods = _service.FindMods(game.Object);
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+ game.ModsLocation.Delete(true);
+
+ if (game.Platform is GamePlatform.SteamGold)
+ {
+ var wsDir = _steamGameHelpers.GetWorkshopsLocation(game);
+ wsDir.Delete(true);
+ }
+
+ var mods = _modFinder.FindMods(game);
Assert.Empty(mods);
}
- [Fact]
- public void TestNoMods_Steam()
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_EmptyModsDirectory_ShouldNotFindMods(GameIdentity gameIdentity)
{
- _fileSystem.Initialize().WithSubdirectory("Lib/Game/Eaw/Mods");
- var game = new Mock();
- game.Setup(g => g.Exists()).Returns(true);
- game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- .Returns(_fileSystem.DirectoryInfo.New("wsDir"));
- var mods = _service.FindMods(game.Object);
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+ game.ModsLocation.Create();
+
+ if (game.Platform is GamePlatform.SteamGold)
+ {
+ var wsDir = _steamGameHelpers.GetWorkshopsLocation(game);
+ wsDir.Create();
+ }
+
+ var mods = _modFinder.FindMods(game);
Assert.Empty(mods);
}
- //[Fact]
- //public void TestOneMods_Normal()
- //{
- // _fileSystem.Initialize().WithSubdirectory("Game/Mods/ModA");
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.Disk);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Game"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Game/Mods"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), false))
- // .Returns("somePath");
-
- // var mods = _service.FindMods(game.Object);
- // var mod = Assert.Single(mods);
- // Assert.Equal("somePath", mod.Identifier);
- // Assert.Equal(ModType.Default, mod.Type);
- //}
-
- //[Fact]
- //public void TestNoModOfPlatform_Normal()
- //{
- // _fileSystem.Initialize().WithSubdirectory("Game/Mods/ModA");
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.Disk);
- // game.Setup(g => g.Type).Returns(GameType.Eaw);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Game"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Game/Mods"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), false))
- // .Returns("somePath");
-
- // var resolverResult = GameType.Foc;
- // _gameTypeResolver
- // .Setup(r => r.TryGetGameType(It.IsAny(), ModType.Default, true, out resolverResult))
- // .Returns(true);
-
- // var mods = _service.FindMods(game.Object);
- // Assert.Empty(mods);
- //}
-
- //[Fact]
- //public void TestModOfCorrectPlatform_Normal()
- //{
- // _fileSystem.Initialize().WithSubdirectory("Game/Mods/ModA");
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.Disk);
- // game.Setup(g => g.Type).Returns(GameType.Eaw);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Game"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Game/Mods"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), false))
- // .Returns("somePath");
-
- // var resolverResult = GameType.Eaw;
- // _gameTypeResolver
- // .Setup(r => r.TryGetGameType(It.IsAny(), ModType.Default, true, out resolverResult))
- // .Returns(true);
-
- // var mods = _service.FindMods(game.Object);
- // var mod = Assert.Single(mods);
- // Assert.Equal("somePath", mod.Identifier);
- // Assert.Equal(ModType.Default, mod.Type);
- //}
-
- //[Fact]
- //public void TestTwoMods_Normal()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Game/Mods/ModA")
- // .WithSubdirectory("Game/Mods/ModB");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.Disk);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Game"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Game/Mods"));
-
- // _idBuilder.SetupSequence(ib => ib.Build(It.IsAny(), false))
- // .Returns("somePath1")
- // .Returns("somePath2");
-
- // var mods = _service.FindMods(game.Object);
- // Assert.Equal(2, mods.Count);
- //}
-
- //[Fact]
- //public void TestOneDefaultMod_Steam()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Lib/Game/Eaw/Mods/ModA");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- // .Returns(_fileSystem.DirectoryInfo.New("path"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), false))
- // .Returns("builderPath");
-
- // var mods = _service.FindMods(game.Object);
- // var mod = Assert.Single(mods);
-
- // Assert.Equal("builderPath", mod.Identifier);
- // Assert.Equal(ModType.Default, mod.Type);
- //}
-
- //[Fact]
- //public void TestOneDefaultModOneWsMod_Steam()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Lib/Game/Eaw/Mods/ModA")
- // .WithSubdirectory("Lib/workshop/content/32470/12345678");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- // .Returns(_fileSystem.DirectoryInfo.New("Lib/workshop/content/32470/"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), false))
- // .Returns("defaultPath");
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), true))
- // .Returns("workshopPath");
-
- // var mods = _service.FindMods(game.Object);
- // Assert.Equal(2, mods.Count);
-
- // var wsMod = mods.First(m => m.Type == ModType.Workshops);
- // Assert.Equal("workshopPath", wsMod.Identifier);
-
- // var defaultMod = mods.First(m => m.Type == ModType.Default);
- // Assert.Equal("defaultPath", defaultMod.Identifier);
- //}
-
- //[Fact]
- //public void TestOneWsMod_Steam()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Lib/workshop/content/32470/12345678");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- // .Returns(_fileSystem.DirectoryInfo.New("Lib/workshop/content/32470/"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), true))
- // .Returns("workshopPath");
-
- // var mods = _service.FindMods(game.Object);
- // var mod = Assert.Single(mods);
- // Assert.Equal("workshopPath", mod.Identifier);
- // Assert.Equal(ModType.Workshops, mod.Type);
- //}
-
- //[Fact]
- //public void TestNoWsModMatchingType_Steam()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Lib/workshop/content/32470/12345678");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- // game.Setup(g => g.Type).Returns(GameType.Foc);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- // .Returns(_fileSystem.DirectoryInfo.New("Lib/workshop/content/32470/"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), true))
- // .Returns("workshopPath");
-
- // var resolverResult = GameType.Eaw;
- // _gameTypeResolver
- // .Setup(r => r.TryGetGameType(It.IsAny(), ModType.Workshops, true, out resolverResult))
- // .Returns(true);
-
- // var mods = _service.FindMods(game.Object);
- // Assert.Empty(mods);
- //}
-
- //[Fact]
- //public void TestNoWsMatchesType_Steam()
- //{
- // _fileSystem.Initialize()
- // .WithSubdirectory("Lib/workshop/content/32470/12345678");
-
- // var game = new Mock();
- // game.Setup(g => g.Exists()).Returns(true);
- // game.Setup(g => g.Platform).Returns(GamePlatform.SteamGold);
- // game.Setup(g => g.Type).Returns(GameType.Foc);
- // game.Setup(g => g.Directory).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // game.Setup(g => g.ModsLocation).Returns(_fileSystem.DirectoryInfo.New("Lib/Game/Eaw/Mods"));
- // _steamHelper.Setup(h => h.GetWorkshopsLocation(game.Object))
- // .Returns(_fileSystem.DirectoryInfo.New("Lib/workshop/content/32470/"));
-
- // _idBuilder.Setup(ib => ib.Build(It.IsAny(), true))
- // .Returns("workshopPath");
-
- // var resolverResult = GameType.Foc;
- // _gameTypeResolver
- // .Setup(r => r.TryGetGameType(It.IsAny(), ModType.Workshops, true, out resolverResult))
- // .Returns(true);
-
- // var mods = _service.FindMods(game.Object);
- // var mod = Assert.Single(mods);
- // Assert.Equal("workshopPath", mod.Identifier);
- // Assert.Equal(ModType.Workshops, mod.Type);
- //}
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_OneMod_WithoutModinfo(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+ var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider);
+
+ var installedMods = _modFinder.FindMods(game);
+
+ var foundMod = Assert.Single(installedMods);
+
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+ Assert.Equal(expectedMod.ModInfo, foundMod.Modinfo);
+
+ // Cannot assert on expectedMod.Identifier, cause this test framework builds the wrong identifiers.
+ Assert.Equal(expectedMod.Directory.Name, foundMod.ModReference.Identifier);
+ }
+
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_OneMod_WithInvalidModinfo(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+
+ var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider);
+ expectedMod.InstallInvalidModinfoFile();
+
+
+ var installedMods = _modFinder.FindMods(game);
+
+ var foundMod = Assert.Single(installedMods);
+
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+ Assert.Equal(expectedMod.ModInfo, foundMod.Modinfo);
+
+ // Cannot assert on expectedMod.Identifier, cause this test framework builds the wrong identifiers.
+ Assert.Equal(expectedMod.Directory.Name, foundMod.ModReference.Identifier);
+ }
+
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_OneMod_WithOneInvalidModinfoVariant(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+
+ var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider);
+ expectedMod.InstallModinfoFile(new ModinfoData("Variant1"), "variant1");
+ expectedMod.InstallInvalidModinfoFile("variant2");
+
+
+ var installedMods = _modFinder.FindMods(game);
+
+ var foundMod = Assert.Single(installedMods);
+
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+ Assert.Equal("Variant1", foundMod.Modinfo!.Name);
+
+ // Cannot assert on expectedMod.Identifier, cause this test framework builds the wrong identifiers.
+ Assert.Equal($"{expectedMod.Directory.Name}:Variant1", foundMod.ModReference.Identifier);
+ }
+
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_OneMod_WithMainModinfo(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+
+ var modinfoData = new ModinfoData("MyMod");
+ var expectedMod = game.InstallMod(GITestUtilities.GetRandomWorkshopFlag(game), modinfoData, ServiceProvider);
+ expectedMod.InstallModinfoFile(modinfoData);
+
+ var installedMods = _modFinder.FindMods(game);
+
+ var foundMod = Assert.Single(installedMods);
+
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+
+ // Cannot assert on expectedMod.Identifier, cause this test framework builds the wrong identifiers.
+ Assert.Equal(expectedMod.Directory.Name, foundMod.ModReference.Identifier);
+ }
+
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_WithOnlyManyVariantModinfos(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+
+ var info1 = new ModinfoData("MyName1");
+ var info2 = new ModinfoData("MyName2");
+ var expectedMod = game.InstallMod("DirName", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider);
+ expectedMod.InstallModinfoFile(info1, "variant1");
+ expectedMod.InstallModinfoFile(info2, "variant2");
+
+ var installedMods = _modFinder.FindMods(game);
+
+ Assert.Equal(2, installedMods.Count);
+
+ foreach (var foundMod in installedMods)
+ {
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+ }
+
+ Assert.Equivalent(new List{ "MyName1", "MyName2" }, installedMods.Select(x => x.Modinfo!.Name), true);
+ Assert.Equivalent(
+ new List { $"{expectedMod.Directory.Name}:MyName1", $"{expectedMod.Directory.Name}:MyName2" },
+ installedMods.Select(x => x.ModReference.Identifier), true);
+ }
+
+ [Theory]
+ [MemberData(nameof(RealGameIdentities))]
+ public void FindMods_WithMainAndManyVariantModinfos(GameIdentity gameIdentity)
+ {
+ var game = FileSystem.InstallGame(gameIdentity, ServiceProvider);
+
+ var main = new ModinfoData("Main");
+ var info1 = new ModinfoData("MyName1");
+ var info2 = new ModinfoData("MyName2");
+ var expectedMod = game.InstallMod("DirName", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider);
+ expectedMod.InstallModinfoFile(main);
+ expectedMod.InstallModinfoFile(info1, "variant1");
+ expectedMod.InstallModinfoFile(info2, "variant2");
+
+ var installedMods = _modFinder.FindMods(game);
+
+ Assert.Equal(3, installedMods.Count);
+
+ foreach (var foundMod in installedMods)
+ {
+ Assert.Equal(expectedMod.Directory.FullName, foundMod.Directory.FullName);
+ Assert.Equal(expectedMod.Type, foundMod.ModReference.Type);
+ }
+
+ Assert.Equivalent(new List { "Main", "MyName1", "MyName2" }, installedMods.Select(x => x.Modinfo!.Name),
+ true);
+
+ Assert.Equivalent(
+ new List { expectedMod.Directory.Name, $"{expectedMod.Directory.Name}:MyName1", $"{expectedMod.Directory.Name}:MyName2" },
+ installedMods.Select(x => x.ModReference.Identifier), true);
+ }
+
+ [Theory]
+ [InlineData(GameType.Eaw)]
+ [InlineData(GameType.Foc)]
+ public void FindMods_Steam_ShouldAddWorkshopsAndMods(GameType type)
+ {
+ var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider);
+
+ var steamMod = game.InstallMod("SteamMod", true, ServiceProvider);
+
+ var modinfo = new ModinfoData("Name");
+ var defaultMod = game.InstallMod(false, modinfo, ServiceProvider);
+ defaultMod.InstallModinfoFile(modinfo);
+
+
+ var installedMods = _modFinder.FindMods(game);
+
+ Assert.Equal(2, installedMods.Count);
+
+ Assert.Contains(installedMods,
+ x => x.ModReference.Type == steamMod.Type && steamMod.Directory.FullName.Equals(x.Directory.FullName) &&
+ x.Modinfo is null && x.ModReference.Identifier.Equals(steamMod.Directory.Name));
+
+ Assert.Contains(installedMods, x => x.ModReference.Type == defaultMod.Type &&
+ defaultMod.Directory.FullName.Equals(x.Directory.FullName)
+ && x.Modinfo is not null && x.Modinfo.Name.Equals(defaultMod.Name) &&
+ x.ModReference.Identifier.Equals(defaultMod.Directory.Name));
+ }
+
+ [Theory]
+ [InlineData(GameType.Eaw)]
+ [InlineData(GameType.Foc)]
+ public void FindMods_Steam_ShouldNotContainModOfWrongGame(GameType type)
+ {
+ var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider);
+
+ var oppositeGameType = type is GameType.Eaw ? GameType.Foc : GameType.Eaw;
+
+ var steamData = new SteamData(
+ new Random().Next(0, int.MaxValue).ToString(),
+ "path",
+ TestHelpers.GetRandomEnum(),
+ "Title",
+ [$"{oppositeGameType.ToString().ToUpper()}"]);
+ var modinfo = new ModinfoData("Name")
+ {
+ SteamData = steamData
+ };
+
+
+ var defaultMod = game.InstallMod(true, modinfo, ServiceProvider);
+ defaultMod.InstallModinfoFile(modinfo);
+
+ Assert.Empty(_modFinder.FindMods(game));
+ }
}
\ No newline at end of file
diff --git a/src/PetroGlyph.Games.EawFoc/test/ModServices/ModIdentifierBuilderTest.cs b/src/PetroGlyph.Games.EawFoc/test/ModServices/ModIdentifierBuilderTest.cs
deleted file mode 100644
index a79db5e..0000000
--- a/src/PetroGlyph.Games.EawFoc/test/ModServices/ModIdentifierBuilderTest.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-using EawModinfo.Model;
-using EawModinfo.Spec;
-using EawModinfo.Spec.Equality;
-using PG.StarWarsGame.Infrastructure.Games;
-using PG.StarWarsGame.Infrastructure.Mods;
-using PG.StarWarsGame.Infrastructure.Services.Detection;
-using PG.StarWarsGame.Infrastructure.Testing;
-using PG.StarWarsGame.Infrastructure.Testing.Game.Installation;
-using PG.StarWarsGame.Infrastructure.Testing.Mods;
-using Semver;
-using Xunit;
-
-namespace PG.StarWarsGame.Infrastructure.Test.ModServices;
-
-public class ModIdentifierBuilderTest : CommonTestBaseWithRandomGame
-{
- private readonly ModIdentifierBuilder _idBuilder;
-
- public ModIdentifierBuilderTest()
- {
- _idBuilder = new ModIdentifierBuilder(ServiceProvider);
- }
-
- [Fact]
- public void Build_DefaultMod()
- {
- var mod = Game.InstallMod("Mod", false, ServiceProvider);
-
- var expected = mod.Directory.FullName.TrimEnd(FileSystem.Path.DirectorySeparatorChar, FileSystem.Path.AltDirectorySeparatorChar);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- expected = expected.ToUpperInvariant();
-
- Assert.Equal(expected, _idBuilder.Build(mod));
- Assert.Equal(expected, _idBuilder.Build(mod.Directory, false));
- }
-
- [Fact]
- public void Build_SteamWorkshopMod()
- {
- var steamGame = FileSystem.InstallGame(
- new GameIdentity(TestingUtilities.TestHelpers.GetRandomEnum(), GamePlatform.SteamGold),
- ServiceProvider);
-
- var mod = steamGame.InstallMod("Mod", true, ServiceProvider);
-
- var expected = mod.Directory.Name;
- _ = ulong.Parse(expected); // Check this conversion does not throw
-
- Assert.Equal(expected, _idBuilder.Build(mod));
- Assert.Equal(expected, _idBuilder.Build(mod.Directory, true));
- }
-
- [Fact]
- public void Build_SteamWorkshopMod_InvalidPathCannotBeConvertedToSteamWSId_Throws()
- {
- var mod = Game.InstallMod("Mod", false, ServiceProvider);
- Assert.Throws(() => _idBuilder.Build(mod.Directory, true));
- }
-
- [Fact]
- public void Build_VirtualMod()
- {
- var dep = CreateAndAddMod("Dep");
-
- var modinfo = new ModinfoData("Name")
- {
- Dependencies = new DependencyList(new List
- {
- dep
- }, DependencyResolveLayout.FullResolved),
- Languages = [new LanguageInfo("de", LanguageSupportLevel.FullLocalized)]
- };
- var mod = new VirtualMod(Game, "VirtualModId", modinfo, ServiceProvider);
-
- var id = _idBuilder.Build(mod);
- var parsedModInfo = ModinfoData.Parse(id);
-
- Assert.Equal(modinfo, parsedModInfo);
- Assert.Equal(modinfo.Languages, parsedModInfo.Languages, LanguageInfoEqualityComparer.WithSupportLevel);
- }
-
- [Fact]
- public void TestNormalizeWorkshops()
- {
- var mRef = new ModReference("123456", ModType.Workshops, SemVersionRange.Parse("1.*"));
- var expected = new ModReference("123456", ModType.Workshops, SemVersionRange.Parse("1.*"));
- var normalizedRef = _idBuilder.Normalize(mRef);
-
- Assert.Equal(expected, normalizedRef, ModReferenceEqualityComparer.Default);
- Assert.Equal(SemVersionRange.Parse("1.*"), normalizedRef.VersionRange);
- }
-
- [Fact]
- public void Normalize_VirtualMod()
- {
- var modinfoString = @"{""name"":""Mod""}";
- var mRef = new ModReference(modinfoString, ModType.Virtual, SemVersionRange.Parse("1.*"));
- var expected = new ModReference(modinfoString, ModType.Virtual);
- var normalizedRef = _idBuilder.Normalize(mRef);
-
- Assert.Equal(expected, normalizedRef);
- Assert.Equal(SemVersionRange.Parse("1.*"), normalizedRef.VersionRange);
- }
-}
\ No newline at end of file
diff --git a/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs b/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs
new file mode 100644
index 0000000..819f7e0
--- /dev/null
+++ b/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using EawModinfo.File;
+using EawModinfo.Spec;
+using PG.StarWarsGame.Infrastructure.Mods;
+
+namespace PG.StarWarsGame.Infrastructure.Testing.Mods;
+
+public static partial class ModInstallations
+{
+ public static IModinfoFile InstallInvalidModinfoFile(this IPhysicalMod mod, string? variantSubFileName = null)
+ {
+ return InstallModinfoFile(mod, stream => { stream.WriteByte(0); }, variantSubFileName);
+ }
+
+ public static IModinfoFile InstallModinfoFile(
+ this IPhysicalMod mod,
+ IModinfo modinfo,
+ string? variantSubFileName = null)
+ {
+ return InstallModinfoFile(mod, modinfo.ToJson, variantSubFileName);
+ }
+
+ private static IModinfoFile InstallModinfoFile(
+ this IPhysicalMod mod,
+ Action writeAction,
+ string? variantSubFileName)
+ {
+ var dir = mod.Directory;
+ dir.Create();
+
+ var fs = dir.FileSystem;
+
+ var modinfoFilePath = fs.Path.Combine(dir.FullName,
+ variantSubFileName != null
+ ? $"{variantSubFileName}-modinfo.json"
+ : "modinfo.json");
+
+ using var fileStream = fs.FileStream.New(modinfoFilePath, FileMode.Create);
+ writeAction(fileStream);
+
+ var fileInfo = fs.FileInfo.New(modinfoFilePath);
+
+ if (variantSubFileName is null)
+ return new ModinfoVariantFile(fileInfo);
+ return new ModinfoVariantFile(fileInfo);
+ }
+
+}
\ No newline at end of file
diff --git a/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs b/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs
index 7f276d3..3b1ac5b 100644
--- a/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs
+++ b/src/Testing/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs
@@ -9,7 +9,7 @@
namespace PG.StarWarsGame.Infrastructure.Testing.Mods;
-public static class ModInstallations
+public static partial class ModInstallations
{
public static Mod InstallAndAddMod(this IGame game, string name, bool workshop, IServiceProvider serviceProvider)
{