diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ecb52d5c..362dc9aa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,4 +26,8 @@ jobs: dotnet-version: '10.0.x' - name: Build & Test in Release Mode - run: dotnet test --configuration Release --logger "GitHubActions" \ No newline at end of file + run: dotnet test --configuration Release --report-github + # Ignore exit code 8 on Linux (zero tests are now allowed) + # TODO: Remove this when linux is supported + env: + TESTINGPLATFORM_EXITCODE_IGNORE: ${{ matrix.os == 'ubuntu-latest' && '8' || '' }} \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index b10fafc0..aec3b0e0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ Alamo Engine Tools and Contributors - Copyright © 2025 Alamo Engine Tools and contributors. All rights reserved. + Copyright © 2026 Alamo Engine Tools and contributors. All rights reserved. Alamo Engine Tools petroglyph, alamo, glyphx, foc, eaw https://github.com/AlamoEngine-Tools/PetroglyphGameInfrastructure @@ -32,8 +32,7 @@ 3.9.50 - - runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/LICENSE b/LICENSE index 10fdbec7..23fe8695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Alamo Engine Tools +Copyright (c) 2026 Alamo Engine Tools Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/PetroGlyphGameInfrastructure.slnx b/PetroGlyphGameInfrastructure.slnx index c29d09ef..d5941e25 100644 --- a/PetroGlyphGameInfrastructure.slnx +++ b/PetroGlyphGameInfrastructure.slnx @@ -6,11 +6,12 @@ - + + + - diff --git a/global.json b/global.json new file mode 100644 index 00000000..8f73781c --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} \ No newline at end of file diff --git a/sampleApp/SampleApplication.csproj b/sampleApp/SampleApplication.csproj index e8b2d631..032d5a8c 100644 --- a/sampleApp/SampleApplication.csproj +++ b/sampleApp/SampleApplication.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/AET.SteamAbstraction/AET.SteamAbstraction.csproj b/src/AET.SteamAbstraction/AET.SteamAbstraction.csproj index 35deee25..64387ab8 100644 --- a/src/AET.SteamAbstraction/AET.SteamAbstraction.csproj +++ b/src/AET.SteamAbstraction/AET.SteamAbstraction.csproj @@ -1,6 +1,6 @@ - + - netstandard2.0 + netstandard2.0;netstandard2.1 AET.SteamAbstraction @@ -21,16 +21,16 @@ true - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/AET.SteamAbstraction/Library/SteamLibrary.cs b/src/AET.SteamAbstraction/Library/SteamLibrary.cs index 8be9d434..dbcbdfa8 100644 --- a/src/AET.SteamAbstraction/Library/SteamLibrary.cs +++ b/src/AET.SteamAbstraction/Library/SteamLibrary.cs @@ -19,9 +19,12 @@ internal class SteamLibrary : ISteamLibrary TrailingDirectorySeparatorBehavior = TrailingDirectorySeparatorBehavior.Trim }; + private readonly string _normalizedLocation; private readonly ILogger? _logger; private readonly ConcurrentDictionary _locations = new(); + private protected readonly IFileSystem FileSystem; + private readonly Dictionary _locationsNames = new() { { KnownLibraryLocations.SteamApps, ["steamapps"] }, @@ -29,9 +32,6 @@ internal class SteamLibrary : ISteamLibrary { KnownLibraryLocations.Workshops, ["steamapps", "workshop"] } }; - private readonly string _normalizedLocation; - private readonly IFileSystem _fileSystem; - public IDirectoryInfo LibraryLocation { get; } public IDirectoryInfo SteamAppsLocation => GetKnownLibraryLocation(KnownLibraryLocations.SteamApps); @@ -46,9 +46,9 @@ public SteamLibrary(IDirectoryInfo libraryLocation, IServiceProvider serviceProv throw new ArgumentNullException(nameof(libraryLocation)); if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider)); - _fileSystem = serviceProvider.GetRequiredService(); + FileSystem = serviceProvider.GetRequiredService(); _logger = serviceProvider.GetService()?.CreateLogger(GetType()); - _normalizedLocation = PathNormalizer.Normalize(_fileSystem.Path.GetFullPath(libraryLocation.FullName), SteamLibraryPathNormalizeOptions); + _normalizedLocation = PathNormalizer.Normalize(FileSystem.Path.GetFullPath(libraryLocation.FullName), SteamLibraryPathNormalizeOptions); LibraryLocation = libraryLocation; } @@ -91,7 +91,7 @@ public bool Equals(ISteamLibrary? other) if (ReferenceEquals(this, other)) return true; - var normalizedOtherPath = PathNormalizer.Normalize(_fileSystem.Path.GetFullPath(other.LibraryLocation.FullName), SteamLibraryPathNormalizeOptions); + var normalizedOtherPath = PathNormalizer.Normalize(FileSystem.Path.GetFullPath(other.LibraryLocation.FullName), SteamLibraryPathNormalizeOptions); return _normalizedLocation.Equals(normalizedOtherPath); } diff --git a/src/AET.SteamAbstraction/Linux/LinuxSteamRegistry.cs b/src/AET.SteamAbstraction/Linux/LinuxSteamRegistry.cs index 2cf0585d..f02d947e 100644 --- a/src/AET.SteamAbstraction/Linux/LinuxSteamRegistry.cs +++ b/src/AET.SteamAbstraction/Linux/LinuxSteamRegistry.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using AET.SteamAbstraction.Registry; using AnakinRaW.CommonUtilities; +using AnakinRaW.CommonUtilities.Registry; namespace AET.SteamAbstraction; @@ -16,4 +17,9 @@ internal class LinuxSteamRegistry(IServiceProvider serviceProvider) : Disposable public IDirectoryInfo? InstallationDirectory { get; } public int? ProcessId { get; } + + public IRegistryKey? OpenSteamRegistryKey() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/AET.SteamAbstraction/Properties/AssemblyInfo.cs b/src/AET.SteamAbstraction/Properties/AssemblyInfo.cs index 372482c9..333fabca 100644 --- a/src/AET.SteamAbstraction/Properties/AssemblyInfo.cs +++ b/src/AET.SteamAbstraction/Properties/AssemblyInfo.cs @@ -1,7 +1,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("AET.SteamAbstraction.Test")] -[assembly: InternalsVisibleTo("AET.SteamAbstraction.TestingUtilities")] +[assembly: InternalsVisibleTo("AET.SteamAbstraction.Testing")] [assembly: InternalsVisibleTo("PG.StarWarsGame.Infrastructure.Clients.Steam.Test")] diff --git a/src/AET.SteamAbstraction/Registry/ISteamRegistry.cs b/src/AET.SteamAbstraction/Registry/ISteamRegistry.cs index b640d4ca..d03dba69 100644 --- a/src/AET.SteamAbstraction/Registry/ISteamRegistry.cs +++ b/src/AET.SteamAbstraction/Registry/ISteamRegistry.cs @@ -1,4 +1,5 @@ -using System; +using AnakinRaW.CommonUtilities.Registry; +using System; using System.IO.Abstractions; namespace AET.SteamAbstraction.Registry; @@ -22,4 +23,10 @@ internal interface ISteamRegistry : IDisposable /// The PID of the current Steam Process. 0 or if Steam is not running. /// int? ProcessId { get; } + + /// + /// Opens the Steam registry and returns a writeable key. + /// + /// The steam registry key. + IRegistryKey? OpenSteamRegistryKey(); } \ No newline at end of file diff --git a/src/AET.SteamAbstraction/Utilities/IProcessHelper.cs b/src/AET.SteamAbstraction/Utilities/IProcessHelper.cs index d5698aa0..74a95f1b 100644 --- a/src/AET.SteamAbstraction/Utilities/IProcessHelper.cs +++ b/src/AET.SteamAbstraction/Utilities/IProcessHelper.cs @@ -1,10 +1,33 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; namespace AET.SteamAbstraction.Utilities; +/// +/// Provides utility methods for managing and interacting with system processes. +/// internal interface IProcessHelper { + /// + /// Determines whether a process with the specified process identifier (PID) is currently running. + /// + /// The process identifier (PID) to check. + /// + /// if a process with the specified PID is running; otherwise, . + /// + /// + /// This method attempts to retrieve the process by its PID. If the process does not exist or cannot be accessed, + /// it returns . + /// bool IsProcessRunning(int pid); + /// + /// Starts a new process using the specified configuration. + /// + /// The object that specifies the configuration for the process to be started. + /// A object that represents the started process, or if the process could not be started. + /// Thrown if is . + /// Thrown if no file name is specified in . + /// Thrown if an error occurs when opening the associated file. Process? StartProcess(ProcessStartInfo startInfo); } \ No newline at end of file diff --git a/src/AET.SteamAbstraction/Windows/WindowsSteamRegistry.cs b/src/AET.SteamAbstraction/Windows/WindowsSteamRegistry.cs index 7f707d4b..3a4559e2 100644 --- a/src/AET.SteamAbstraction/Windows/WindowsSteamRegistry.cs +++ b/src/AET.SteamAbstraction/Windows/WindowsSteamRegistry.cs @@ -74,6 +74,12 @@ public IDirectoryInfo? InstallationDirectory } } + public IRegistryKey? OpenSteamRegistryKey() + { + ThrowIfDisposed(); + return _registryKey!.OpenSubKey(string.Empty, true); + } + protected override void DisposeResources() { _registryKey?.Dispose(); @@ -95,10 +101,4 @@ private void WriteToSubKey(string subKeyName, Action keyAction) if (subKey is not null) keyAction(subKey); } - - internal IRegistryKey GetSteamRegistryKey() - { - ThrowIfDisposed(); - return _registryKey!.OpenSubKey(string.Empty, true)!; - } } \ No newline at end of file diff --git a/src/PG.StarWarsGame.Infrastructure/PG.StarWarsGame.Infrastructure.csproj b/src/PG.StarWarsGame.Infrastructure/PG.StarWarsGame.Infrastructure.csproj index 08e22e06..b736e5ab 100644 --- a/src/PG.StarWarsGame.Infrastructure/PG.StarWarsGame.Infrastructure.csproj +++ b/src/PG.StarWarsGame.Infrastructure/PG.StarWarsGame.Infrastructure.csproj @@ -22,10 +22,16 @@ true - - - - + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,11 +40,5 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - \ No newline at end of file diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/CompositeGameDetector.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/CompositeGameDetector.cs index 0634c9b8..6ef268ab 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/CompositeGameDetector.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/CompositeGameDetector.cs @@ -29,7 +29,7 @@ public sealed class CompositeGameDetector : IGameDetector /// The sorted list of detectors which shall get used. /// The service provider. /// - /// When after a detector was used, it will get disposed if it implements . + /// If , a detector that implements gets disposed after usage. /// Default is /// public CompositeGameDetector(IList sortedDetectors, IServiceProvider serviceProvider, bool disposeDetectors = false) @@ -49,7 +49,10 @@ public CompositeGameDetector(IList sortedDetectors, IServiceProvi /// The game type to detect. /// Collection of the platforms to search for. /// Data which holds the game's location or error information. - /// + /// + /// All exceptions that occurred during an unsuccessful game detection. + /// The exception is not thrown when any detector returns an installed game result. + /// public GameDetectionResult Detect(GameType gameType, params ICollection platforms) { var errors = new List(); diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/GameDetectorBase.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/GameDetectorBase.cs index 8dafee05..3f6cced8 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/GameDetectorBase.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Games/GameDetectorBase.cs @@ -151,7 +151,6 @@ internal static bool DataAndMegaFilesXmlExists(IDirectoryInfo directory) /// /// The game type to detect. /// Information about a found game installation. - /// This method may throw arbitrary exceptions. protected abstract GameLocationData FindGameLocation(GameType gameType); private static bool MatchesOptionsPlatform(ICollection platforms, GamePlatform identifiedPlatform) diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/IModGameTypeResolver.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/IModGameTypeResolver.cs index f6502b16..bd966fc4 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/IModGameTypeResolver.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/IModGameTypeResolver.cs @@ -21,7 +21,7 @@ public interface IModGameTypeResolver /// When this method returns , the assured game types will be stored in this variable. /// when the game type could be determined; if there is no clear evidence of the actual game type. /// is . - public bool TryGetGameType(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes); + public bool TryGetGameType(DetectedModReference modInformation, out ImmutableFrugalList gameTypes); /// /// Tries to determine the from a specified modinfo data. @@ -32,7 +32,7 @@ public interface IModGameTypeResolver /// The modinfo data. /// When this method returns , the assured game types will be stored in this variable. /// when the game type could be determined; if there is no clear evidence of the actual game type. - public bool TryGetGameType(IModinfo? modinfo, out ReadOnlyFrugalList gameTypes); + public bool TryGetGameType(IModinfo? modinfo, out ImmutableFrugalList gameTypes); /// /// Determines whether the specified mod information are definitely not compatible to a game type. diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModFinder.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModFinder.cs index ba2cfbf0..3c159ef1 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModFinder.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModFinder.cs @@ -3,7 +3,6 @@ using System.IO.Abstractions; using System.Linq; using AET.Modinfo.File; -using AET.Modinfo.Spec; using AET.Modinfo.Utilities; using AnakinRaW.CommonUtilities.FileSystem; using Microsoft.Extensions.DependencyInjection; @@ -83,8 +82,7 @@ private IEnumerable GetModsFromDirectory( _logger?.LogTrace("Searching for mods at location '{Location}'", modDirectory.FullName); - ModinfoFinderCollection modinfoFiles; - modinfoFiles = ModinfoFileFinder.FindModinfoFiles(modDirectory); + var modinfoFiles = ModinfoFileFinder.FindModinfoFiles(modDirectory); foreach (var modRef in ModReferenceBuilder.CreateIdentifiers(modinfoFiles, locationKind)) { diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModGameTypeResolver.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModGameTypeResolver.cs index 5ace74a3..29a370a7 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModGameTypeResolver.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/ModGameTypeResolver.cs @@ -37,7 +37,7 @@ protected ModGameTypeResolver(IServiceProvider serviceProvider) } /// - public bool TryGetGameType(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes) + public bool TryGetGameType(DetectedModReference modInformation, out ImmutableFrugalList gameTypes) { if (modInformation == null) throw new ArgumentNullException(nameof(modInformation)); @@ -56,10 +56,10 @@ public bool TryGetGameType(DetectedModReference modInformation, out ReadOnlyFrug /// The information of the mod. /// When this method returns , the assured game types will be stored in this variable. /// when the game type could be determined; if there is no clear evidence of the actual game type. - protected internal abstract bool TryGetGameTypeCore(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes); + protected internal abstract bool TryGetGameTypeCore(DetectedModReference modInformation, out ImmutableFrugalList gameTypes); /// - public virtual bool TryGetGameType(IModinfo? modinfo, out ReadOnlyFrugalList gameTypes) + public virtual bool TryGetGameType(IModinfo? modinfo, out ImmutableFrugalList gameTypes) { return GetGameType(modinfo?.SteamData, out gameTypes); } @@ -82,14 +82,14 @@ public bool IsDefinitelyNotCompatibleToGame(IModinfo? modinfo, GameType expected return TryGetGameType(modinfo, out var gameTypes) && !gameTypes.Contains(expectedGameType); } - private bool GetGameType(ISteamData? steamData, out ReadOnlyFrugalList gameTypes) + private bool GetGameType(ISteamData? steamData, out ImmutableFrugalList gameTypes) { gameTypes = default; - Logger?.LogTrace($"Try getting game type from steam data '[{string.Join(",", steamData?.Tags ?? ["tags n/a"])}]'"); + Logger?.LogTrace("Try getting game type from steam data '[{Tags}]'", string.Join(",", steamData?.Tags ?? ["tags n/a"])); return steamData is not null && GetGameTypesFromTags(steamData.Tags, out gameTypes); } - internal static bool GetGameTypesFromTags(IEnumerable tags, out ReadOnlyFrugalList gameTypes) + internal static bool GetGameTypesFromTags(IEnumerable tags, out ImmutableFrugalList gameTypes) { var mutableGameTypes = new FrugalList(); @@ -104,7 +104,7 @@ internal static bool GetGameTypesFromTags(IEnumerable tags, out ReadOnly mutableGameTypes.Add(GameType.Foc); } - gameTypes = mutableGameTypes.AsReadOnly(); + gameTypes = mutableGameTypes.ToImmutableList(); return gameTypes.Count > 0; } } \ No newline at end of file diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OfflineModGameTypeResolver.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OfflineModGameTypeResolver.cs index cfb2fd01..abed607f 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OfflineModGameTypeResolver.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OfflineModGameTypeResolver.cs @@ -23,7 +23,7 @@ public sealed class OfflineModGameTypeResolver(IServiceProvider serviceProvider) /// - protected internal override bool TryGetGameTypeCore(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes) + protected internal override bool TryGetGameTypeCore(DetectedModReference modInformation, out ImmutableFrugalList gameTypes) { gameTypes = default; @@ -47,21 +47,21 @@ protected internal override bool TryGetGameTypeCore(DetectedModReference modInfo if (detector.Detect(GameType.Foc, GamePlatform.Undefined).Installed) { Logger?.LogTrace("{ModRef} is located in FoC's Mods directory.", modInformation.ModReference); - gameTypes = new ReadOnlyFrugalList(GameType.Foc); + gameTypes = ImmutableFrugalList.Single(GameType.Foc); return true; } if (detector.Detect(GameType.Eaw, GamePlatform.Undefined).Installed) { Logger?.LogTrace("{ModRef} is located in EaW's Mods directory.", modInformation.ModReference); - gameTypes = new ReadOnlyFrugalList(GameType.Eaw); + gameTypes = ImmutableFrugalList.Single(GameType.Eaw); return true; } return false; } - private bool HandleWorkshop(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes) + private bool HandleWorkshop(DetectedModReference modInformation, out ImmutableFrugalList gameTypes) { gameTypes = default; if (modInformation.ModReference.Type == ModType.Workshops) @@ -69,15 +69,14 @@ private bool HandleWorkshop(DetectedModReference modInformation, out ReadOnlyFru if (!_steamGameHelpers.ToSteamWorkshopsId(modInformation.Directory.Name, out var steamId)) return false; - // Modinfo is superior to cache, because this value can change faster, - // than new distribution of this library might release. - // so that the cache would then be invalid. + // Modinfo is superior to cache, because a modinfo file can change more frequently + // than new release of this library (and therefore the cache). if (TryGetGameType(modInformation.Modinfo, out gameTypes)) return true; if (_cache.ContainsMod(steamId)) { - gameTypes = new ReadOnlyFrugalList(_cache.GetGameTypes(steamId)); + gameTypes = ImmutableFrugalList.Create(_cache.GetGameTypes(steamId)); return true; } } diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OnlineModGameTypeResolver.cs b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OnlineModGameTypeResolver.cs index b0c6ffd2..4174d29e 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OnlineModGameTypeResolver.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Detection/Mods/OnlineModGameTypeResolver.cs @@ -5,6 +5,7 @@ using AET.Modinfo.Spec; using AET.Modinfo.Utilities; using AnakinRaW.CommonUtilities.Collections; +using HtmlAgilityPack; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PG.StarWarsGame.Infrastructure.Games; @@ -24,14 +25,14 @@ public sealed class OnlineModGameTypeResolver(IServiceProvider serviceProvider) private readonly ISteamWorkshopWebpageDownloader _steamWebpageDownloader = serviceProvider.GetRequiredService(); /// - protected internal override bool TryGetGameTypeCore(DetectedModReference modInformation, out ReadOnlyFrugalList gameTypes) + protected internal override bool TryGetGameTypeCore(DetectedModReference modInformation, out ImmutableFrugalList gameTypes) { if (_offlineResolver.TryGetGameTypeCore(modInformation, out gameTypes)) return true; return modInformation.ModReference.Type == ModType.Workshops && GetGameTypeFromSteamPage(modInformation.Directory.Name, out gameTypes); } - private bool GetGameTypeFromSteamPage(string steamIdValue, out ReadOnlyFrugalList gameTypes) + private bool GetGameTypeFromSteamPage(string steamIdValue, out ImmutableFrugalList gameTypes) { gameTypes = default; if (!_steamGameHelpers.ToSteamWorkshopsId(steamIdValue, out var steamId)) @@ -39,10 +40,19 @@ private bool GetGameTypeFromSteamPage(string steamIdValue, out ReadOnlyFrugalLis Logger?.LogTrace("Getting steam tags from Steam's webpage for mod '{SteamId}'", steamId); - var webPage = _steamWebpageDownloader.GetSteamWorkshopsPageHtmlAsync(steamId, CultureInfo.InvariantCulture) - .GetAwaiter().GetResult(); - if (webPage is null) + HtmlDocument webPage; + try + { + webPage = _steamWebpageDownloader.GetSteamWorkshopsPageHtmlAsync(steamId, CultureInfo.InvariantCulture) + .GetAwaiter().GetResult(); + if (webPage is null) + return false; + } + catch (Exception e) + { + Logger?.LogTrace(e, "Failed to get steam tags from Steam's webpage for mod '{SteamId}'", steamId); return false; + } var tagNodes = webPage.DocumentNode.SelectNodes("//div[@class='workshopTags']/a/text()"); if (tagNodes is null || tagNodes.Count == 0) diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Name/Mods/OnlineWorkshopNameResolver.cs b/src/PG.StarWarsGame.Infrastructure/Services/Name/Mods/OnlineWorkshopNameResolver.cs index 91514eba..bc3d7628 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Name/Mods/OnlineWorkshopNameResolver.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Name/Mods/OnlineWorkshopNameResolver.cs @@ -3,6 +3,7 @@ using System.Globalization; using AET.Modinfo.Spec; using AET.Modinfo.Utilities; +using HtmlAgilityPack; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PG.StarWarsGame.Infrastructure.Services.Steam; @@ -50,12 +51,21 @@ protected internal override string ResolveCore(DetectedModReference detectedMod, private string? GetNameFromOnline(ulong modId, CultureInfo culture) { - var modsWorkshopWebpage = _steamWebpageDownloader.GetSteamWorkshopsPageHtmlAsync(modId, culture) - .GetAwaiter().GetResult(); + HtmlDocument modsWorkshopWebpage; + try + { + modsWorkshopWebpage = _steamWebpageDownloader.GetSteamWorkshopsPageHtmlAsync(modId, culture) + .GetAwaiter().GetResult(); - if (modsWorkshopWebpage == null) + if (modsWorkshopWebpage == null) + { + Logger?.LogTrace("Unable to download website for Steam ID '{ModId}'.", modId); + return null; + } + } + catch (Exception e) { - Logger?.LogTrace("Unable to download website for Steam ID '{ModId}'.", modId); + Logger?.LogTrace(e, "Unable to download website for Steam ID '{ModId}'.", modId); return null; } diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Steam/ISteamWorkshopWebpageDownloader.cs b/src/PG.StarWarsGame.Infrastructure/Services/Steam/ISteamWorkshopWebpageDownloader.cs index e6612195..664d8c79 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Steam/ISteamWorkshopWebpageDownloader.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Steam/ISteamWorkshopWebpageDownloader.cs @@ -6,5 +6,5 @@ namespace PG.StarWarsGame.Infrastructure.Services.Steam; internal interface ISteamWorkshopWebpageDownloader { - Task GetSteamWorkshopsPageHtmlAsync(ulong workshopId, CultureInfo? culture); + Task GetSteamWorkshopsPageHtmlAsync(ulong workshopId, CultureInfo? culture); } \ No newline at end of file diff --git a/src/PG.StarWarsGame.Infrastructure/Services/Steam/SteamWorkshopWebpageDownloader.cs b/src/PG.StarWarsGame.Infrastructure/Services/Steam/SteamWorkshopWebpageDownloader.cs index eedeb552..2686742a 100644 --- a/src/PG.StarWarsGame.Infrastructure/Services/Steam/SteamWorkshopWebpageDownloader.cs +++ b/src/PG.StarWarsGame.Infrastructure/Services/Steam/SteamWorkshopWebpageDownloader.cs @@ -10,7 +10,7 @@ internal class SteamWorkshopWebpageDownloader : ISteamWorkshopWebpageDownloader { private const string SteamWorkshopsBaseUrl = "https://steamcommunity.com/sharedfiles/filedetails/?"; - public async Task GetSteamWorkshopsPageHtmlAsync(ulong workshopId, CultureInfo? culture) + public async Task GetSteamWorkshopsPageHtmlAsync(ulong workshopId, CultureInfo? culture) { var queryString = HttpUtility.ParseQueryString(string.Empty); queryString.Add("id", workshopId.ToString()); @@ -18,18 +18,11 @@ internal class SteamWorkshopWebpageDownloader : ISteamWorkshopWebpageDownloader if (culture != null && !Equals(culture, CultureInfo.InvariantCulture)) queryString.Add("l", culture.EnglishName.ToLower()); - try - { - var address = $"{SteamWorkshopsBaseUrl}{queryString}"; - using var client = new HttpClient(); - var reply = await client.GetStringAsync(address); - var htmlDocument = new HtmlDocument(); - htmlDocument.LoadHtml(reply); - return htmlDocument; - } - catch - { - return null; - } + var address = $"{SteamWorkshopsBaseUrl}{queryString}"; + using var client = new HttpClient(); + var reply = await client.GetStringAsync(address); + var htmlDocument = new HtmlDocument(); + htmlDocument.LoadHtml(reply); + return htmlDocument; } } \ No newline at end of file diff --git a/src/PG.StarWarsGame.Infrastructure/ThrowHelper.cs b/src/PG.StarWarsGame.Infrastructure/ThrowHelper.cs index 401eb717..348c3a75 100644 --- a/src/PG.StarWarsGame.Infrastructure/ThrowHelper.cs +++ b/src/PG.StarWarsGame.Infrastructure/ThrowHelper.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; +using PG.StarWarsGame.Infrastructure.Utilities.CompilerServices; namespace PG.StarWarsGame.Infrastructure; diff --git a/src/PG.StarWarsGame.Infrastructure/Utilities/CompilerServices/CallerArgumentExpressionAttribute.cs b/src/PG.StarWarsGame.Infrastructure/Utilities/CompilerServices/CallerArgumentExpressionAttribute.cs index 093da83f..91d5d562 100644 --- a/src/PG.StarWarsGame.Infrastructure/Utilities/CompilerServices/CallerArgumentExpressionAttribute.cs +++ b/src/PG.StarWarsGame.Infrastructure/Utilities/CompilerServices/CallerArgumentExpressionAttribute.cs @@ -1,6 +1,8 @@ -#if !NET +using System; + +#if !NET #pragma warning disable IDE0130 -namespace System.Runtime.CompilerServices; +namespace PG.StarWarsGame.Infrastructure.Utilities.CompilerServices; #pragma warning restore IDE0130 [AttributeUsage(AttributeTargets.Parameter)] diff --git a/src/PG.StarWarsGame.Infrastructure/Utilities/PlayableObjectExtensions.cs b/src/PG.StarWarsGame.Infrastructure/Utilities/PlayableObjectExtensions.cs index 1518573c..5d746392 100644 --- a/src/PG.StarWarsGame.Infrastructure/Utilities/PlayableObjectExtensions.cs +++ b/src/PG.StarWarsGame.Infrastructure/Utilities/PlayableObjectExtensions.cs @@ -87,7 +87,7 @@ public static IEnumerable DataFiles( subPath ??= string.Empty; var fs = playableObject.Directory.FileSystem; var searchLocation = fs.Path.Combine("Data", subPath); - return EnumerateFiles(playableObject, fileSearchPattern, searchLocation, searchRecursive); + return playableObject.EnumerateFiles(fileSearchPattern, searchLocation, searchRecursive); } /// diff --git a/test/AET.SteamAbstraction.Test/AET.SteamAbstraction.Test.csproj b/test/AET.SteamAbstraction.Test/AET.SteamAbstraction.Test.csproj index d3d787e4..57b5bd66 100644 --- a/test/AET.SteamAbstraction.Test/AET.SteamAbstraction.Test.csproj +++ b/test/AET.SteamAbstraction.Test/AET.SteamAbstraction.Test.csproj @@ -1,4 +1,4 @@ - + AET.SteamAbstraction.Test @@ -9,17 +9,15 @@ $(TargetFrameworks);net481 false true + Exe - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/AET.SteamAbstraction.Test/CompilerHelpers/Attributes.cs b/test/AET.SteamAbstraction.Test/CompilerHelpers/Attributes.cs new file mode 100644 index 00000000..e1dc9a46 --- /dev/null +++ b/test/AET.SteamAbstraction.Test/CompilerHelpers/Attributes.cs @@ -0,0 +1,45 @@ +#if !NET5_0_OR_GREATER +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +namespace System.Runtime.Versioning; + +/// +/// Base type for all platform-specific API attributes. +/// + +internal abstract class OSPlatformAttribute(string platformName) : Attribute +{ + public string PlatformName { get; } = platformName; +} + +/// +/// Records the platform that the project targeted. +/// +[AttributeUsage(AttributeTargets.Assembly)] +internal sealed class TargetPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); + +/// +/// Records the operating system (and minimum version) that supports an API. Multiple attributes can be +/// applied to indicate support on multiple operating systems. +/// +/// +/// Callers can apply a +/// or use guards to prevent calls to APIs on unsupported operating systems. +/// +/// A given platform should only be specified once. +/// +[AttributeUsage(AttributeTargets.Assembly | + AttributeTargets.Class | + AttributeTargets.Constructor | + AttributeTargets.Enum | + AttributeTargets.Event | + AttributeTargets.Field | + AttributeTargets.Interface | + AttributeTargets.Method | + AttributeTargets.Module | + AttributeTargets.Property | + AttributeTargets.Struct, + AllowMultiple = true, Inherited = false)] +internal sealed class SupportedOSPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); +// ReSharper restore InconsistentNaming +#endif \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Test/ProcessHelperTest.cs b/test/AET.SteamAbstraction.Test/ProcessHelperTest.cs index 9abf488e..82e6b7e4 100644 --- a/test/AET.SteamAbstraction.Test/ProcessHelperTest.cs +++ b/test/AET.SteamAbstraction.Test/ProcessHelperTest.cs @@ -2,20 +2,25 @@ using System.Diagnostics; using System.Runtime.InteropServices; using AET.SteamAbstraction.Utilities; +using AnakinRaW.CommonUtilities.Testing; using Microsoft.Extensions.DependencyInjection; using Xunit; namespace AET.SteamAbstraction.Test; -public class ProcessHelperTest +public class ProcessHelperTest : TestBaseWithServiceProvider { private readonly IProcessHelper _processHelper; public ProcessHelperTest() { - var sc = new ServiceCollection(); - SteamAbstractionLayer.InitializeServices(sc); - _processHelper = sc.BuildServiceProvider().GetRequiredService(); + _processHelper = ServiceProvider.GetRequiredService(); + } + + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + SteamAbstractionLayer.InitializeServices(serviceCollection); } [Fact] diff --git a/test/AET.SteamAbstraction.Test/SteamAppManifestTest.cs b/test/AET.SteamAbstraction.Test/SteamAppManifestTest.cs index e191113d..d3b61675 100644 --- a/test/AET.SteamAbstraction.Test/SteamAppManifestTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamAppManifestTest.cs @@ -2,25 +2,29 @@ using System.Collections.Generic; using System.IO.Abstractions; using AET.SteamAbstraction.Games; -using AET.SteamAbstraction.Testing.Installation; +using AET.SteamAbstraction.Testing.TestBases; +using AnakinRaW.CommonUtilities.Registry; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; namespace AET.SteamAbstraction.Test; -public class SteamAppManifestTest +public class SteamAppManifestTest : SteamTestBase { private readonly MockFileSystem _fileSystem = new(); - private readonly IServiceProvider _serviceProvider; public SteamAppManifestTest() { - var sc = new ServiceCollection(); - sc.AddSingleton(_fileSystem); - SteamAbstractionLayer.InitializeServices(sc); - _serviceProvider = sc.BuildServiceProvider(); + Steam.InstallSteamFilesOnly(); + } + + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_fileSystem); + serviceCollection.AddSingleton(new InMemoryRegistry()); } [Fact] @@ -29,7 +33,7 @@ public void Ctor_NullArgs_Throws() Assert.Throws(() => new SteamAppManifest(null!, _fileSystem.FileInfo.New("file.acf"), 0, "name", _fileSystem.DirectoryInfo.New("path"), SteamAppState.StateFullyInstalled, new HashSet())); - var lib = _fileSystem.InstallSteamLibrary("path", _serviceProvider, false); + var lib = Steam.InstallLibrary("path", false); Assert.Throws(() => new SteamAppManifest(lib, null!, 0, "name", _fileSystem.DirectoryInfo.New("path"), SteamAppState.StateFullyInstalled, new HashSet())); @@ -49,7 +53,7 @@ public void Ctor_NullArgs_Throws() [Fact] public void Ctor_SetsProperties() { - var lib = _fileSystem.InstallSteamLibrary("path", _serviceProvider, false); + var lib = Steam.InstallLibrary("path", false); var appManifest = new SteamAppManifest(lib, _fileSystem.FileInfo.New("file.acf"), 123, "name", _fileSystem.DirectoryInfo.New("path"), SteamAppState.StateFullyInstalled, new HashSet {987, 654}); @@ -66,8 +70,8 @@ public void Ctor_SetsProperties() [Fact] public void Equality() { - var lib = _fileSystem.InstallSteamLibrary("path", _serviceProvider, false); - var otherLib = _fileSystem.InstallSteamLibrary("other", _serviceProvider, false); + var lib = Steam.InstallLibrary("path", false); + var otherLib = Steam.InstallLibrary("other", false); const uint aId = 123; const uint bId = 456; @@ -78,7 +82,7 @@ public void Equality() var appB = new SteamAppManifest(lib, _fileSystem.FileInfo.New(_fileSystem.Path.GetRandomFileName()), aId, _fileSystem.Path.GetRandomFileName(), _fileSystem.DirectoryInfo.New(_fileSystem.Path.GetRandomFileName()), - TestHelpers.GetRandomEnum(), new HashSet()); + Random.Enum(), new HashSet()); var appOtherLib = new SteamAppManifest(otherLib, _fileSystem.FileInfo.New("file.acf"), aId, "name", _fileSystem.DirectoryInfo.New("path"), diff --git a/test/AET.SteamAbstraction.Test/SteamLibraryFinderTest.cs b/test/AET.SteamAbstraction.Test/SteamLibraryFinderTest.cs index 3dd8ba3c..b88662fa 100644 --- a/test/AET.SteamAbstraction.Test/SteamLibraryFinderTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamLibraryFinderTest.cs @@ -1,49 +1,41 @@ -using System; -using System.Collections.Generic; -using System.IO.Abstractions; +using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using AET.SteamAbstraction.Library; -using AET.SteamAbstraction.Registry; -using AET.SteamAbstraction.Testing.Installation; -using AnakinRaW.CommonUtilities.Registry; -using Microsoft.Extensions.DependencyInjection; -using PG.TestingUtilities; -using Testably.Abstractions.Testing; +using AET.SteamAbstraction.Testing.TestBases; +using AnakinRaW.CommonUtilities.Testing.Attributes; using Xunit; +#if NET5_0_OR_GREATER +using System.Runtime.Versioning; +#endif + namespace AET.SteamAbstraction.Test; -public class SteamLibraryFinderTest +#if NET5_0_OR_GREATER +[SupportedOSPlatform("windows")] +#endif +public class SteamLibraryFinderTest : InMemorySteamTestBase { private readonly SteamLibraryFinder _libraryFinder; - private readonly MockFileSystem _fileSystem = new(); - private readonly IServiceProvider _serviceProvider; public SteamLibraryFinderTest() { - var sc = new ServiceCollection(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - sc.AddSingleton(new InMemoryRegistry(InMemoryRegistryCreationFlags.Default)); - sc.AddSingleton(_fileSystem); - SteamAbstractionLayer.InitializeServices(sc); - _serviceProvider = sc.BuildServiceProvider(); - _libraryFinder = new SteamLibraryFinder(_serviceProvider); + _libraryFinder = new SteamLibraryFinder(ServiceProvider); + Steam.Install(); } - [Fact] + // TODO: Target all platforms + [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_SteamNotFound_ReturnsEmpty() { - Assert.Empty(_libraryFinder.FindLibraries(_fileSystem.DirectoryInfo.New("does not exist"))); + Assert.Empty(_libraryFinder.FindLibraries(FileSystem.DirectoryInfo.New("not steam"))); } // TODO: Target all platforms [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_NoLibrariesInstalled() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var libs = _libraryFinder.FindLibraries(Steam.Registry.InstallationDirectory!); Assert.Empty(libs); } @@ -51,11 +43,8 @@ public void FindLibraries_NoLibrariesInstalled() [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_DefaultLibraryInstalled() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var lib = _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: true); - - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var lib = Steam.InstallDefaultLibrary(addToConfig: true); + var libs = _libraryFinder.FindLibraries(Steam.Registry.InstallationDirectory!); Assert.Equal([lib], libs); } @@ -64,12 +53,8 @@ public void FindLibraries_DefaultLibraryInstalled() [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_DefaultLibraryInstalledButNotInConfig_NotFound() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: false); - - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); - + Steam.InstallDefaultLibrary(addToConfig: false); + var libs = _libraryFinder.FindLibraries(Steam.InstallationDirectory!); Assert.Empty(libs); } @@ -77,29 +62,26 @@ public void FindLibraries_DefaultLibraryInstalledButNotInConfig_NotFound() [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_DefaultLibraryAndExternalLibInstalled() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var defaultLib = _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: true); - var externalLib = _fileSystem.InstallSteamLibrary("externalLib", _serviceProvider); + var defaultLib = Steam.InstallDefaultLibrary(addToConfig: true); + var externalLib = Steam.InstallLibrary("externalLib"); - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var libs = _libraryFinder.FindLibraries(Steam.InstallationDirectory!); Assert.Equal( new List { defaultLib, externalLib }.OrderBy(x => x.LibraryLocation.FullName), libs.OrderBy(x => x.LibraryLocation.FullName)); } + // TODO: Target all platforms [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_Windows_DefaultLibraryAndExternalLibInstalled_ExternalDoesNotHaveSteamDll_Skip() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var defaultLib = _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: true); - var externalLib = _fileSystem.InstallSteamLibrary("externalLib", _serviceProvider); - - _fileSystem.File.Delete(_fileSystem.Path.Combine(externalLib.LibraryLocation.FullName, "steam.dll")); + var defaultLib = Steam.InstallDefaultLibrary(addToConfig: true); + var externalLib = Steam.InstallLibrary("externalLib"); + + FileSystem.File.Delete(FileSystem.Path.Combine(externalLib.LibraryLocation.FullName, "steam.dll")); - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var libs = _libraryFinder.FindLibraries(Steam.InstallationDirectory!); Assert.Equal([defaultLib], libs.OrderBy(x => x.LibraryLocation.FullName)); } @@ -108,14 +90,12 @@ public void FindLibraries_Windows_DefaultLibraryAndExternalLibInstalled_External [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_DefaultLibraryAndExternalLibInstalled_ExternalDoesNotHaveVdf_Skip() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var defaultLib = _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: true); - var externalLib = _fileSystem.InstallSteamLibrary("externalLib", _serviceProvider); + var defaultLib = Steam.InstallDefaultLibrary(addToConfig: true); + var externalLib = Steam.InstallLibrary("externalLib"); - _fileSystem.File.Delete(_fileSystem.Path.Combine(externalLib.LibraryLocation.FullName, "libraryfolder.vdf")); + FileSystem.File.Delete(FileSystem.Path.Combine(externalLib.LibraryLocation.FullName, "libraryfolder.vdf")); - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var libs = _libraryFinder.FindLibraries(Steam.InstallationDirectory!); Assert.Equal([defaultLib], libs.OrderBy(x => x.LibraryLocation.FullName)); } @@ -124,14 +104,12 @@ public void FindLibraries_DefaultLibraryAndExternalLibInstalled_ExternalDoesNotH [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void FindLibraries_DefaultLibraryAndExternalLibInstalled_ExternalFolderDoesNotExist() { - using var registry = _serviceProvider.GetRequiredService().CreateRegistry(); - _fileSystem.InstallSteam(registry); - var defaultLib = _fileSystem.InstallDefaultLibrary(_serviceProvider, addToConfig: true); - var externalLib = _fileSystem.InstallSteamLibrary("externalLib", _serviceProvider); + var defaultLib = Steam.InstallDefaultLibrary(addToConfig: true); + var externalLib = Steam.InstallLibrary("externalLib"); - _fileSystem.Directory.Delete(externalLib.LibraryLocation.FullName, true); + FileSystem.Directory.Delete(externalLib.LibraryLocation.FullName, true); - var libs = _libraryFinder.FindLibraries(registry.InstallationDirectory!); + var libs = _libraryFinder.FindLibraries(Steam.InstallationDirectory!); Assert.Equal([defaultLib], libs.OrderBy(x => x.LibraryLocation.FullName)); } diff --git a/test/AET.SteamAbstraction.Test/SteamLibraryTest.cs b/test/AET.SteamAbstraction.Test/SteamLibraryTest.cs index cf5e885a..3e39d97d 100644 --- a/test/AET.SteamAbstraction.Test/SteamLibraryTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamLibraryTest.cs @@ -1,35 +1,25 @@ using System; -using System.IO.Abstractions; using System.Linq; using System.Runtime.InteropServices; using AET.SteamAbstraction.Library; -using AET.SteamAbstraction.Testing.Installation; -using Microsoft.Extensions.DependencyInjection; -using Testably.Abstractions.Testing; +using AET.SteamAbstraction.Testing.TestBases; using Xunit; namespace AET.SteamAbstraction.Test; -public class SteamLibraryTest +public class SteamLibraryTest : InMemorySteamTestBase { - private readonly IServiceProvider _serviceProvider; - private readonly MockFileSystem _fileSystem = new(); - public SteamLibraryTest() { - var sc = new ServiceCollection(); - sc.AddSingleton(_ => _fileSystem); - SteamAbstractionLayer.InitializeServices(sc); - _serviceProvider = sc.BuildServiceProvider(); - - _fileSystem.InstallSteamFiles(); + Steam.InstallSteamFilesOnly(); } + [Fact] public void Ctor_NullArgs_Throws() { - Assert.Throws(() => new SteamLibrary(null!, _serviceProvider)); - Assert.Throws(() => new SteamLibrary(_fileSystem.DirectoryInfo.New("Library"), null!)); + Assert.Throws(() => new SteamLibrary(null!, ServiceProvider)); + Assert.Throws(() => new SteamLibrary(FileSystem.DirectoryInfo.New("Library"), null!)); } [Theory] @@ -39,8 +29,8 @@ public void Ctor_NullArgs_Throws() [InlineData("other", false, false)] public void TestEquality(string path, bool equalWindows, bool equalLinux) { - var lib = new SteamLibrary(_fileSystem.DirectoryInfo.New("Library"), _serviceProvider); - var other = new SteamLibrary(_fileSystem.DirectoryInfo.New(path), _serviceProvider); + var lib = new SteamLibrary(FileSystem.DirectoryInfo.New("Library"), ServiceProvider); + var other = new SteamLibrary(FileSystem.DirectoryInfo.New(path), ServiceProvider); var equal = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? equalWindows : equalLinux; @@ -51,7 +41,7 @@ public void TestEquality(string path, bool equalWindows, bool equalLinux) [Fact] public void TestEquality_NullAndSame() { - var lib = new SteamLibrary(_fileSystem.DirectoryInfo.New("Library"), _serviceProvider); + var lib = new SteamLibrary(FileSystem.DirectoryInfo.New("Library"), ServiceProvider); Assert.False(lib.Equals((object)null!)); Assert.False(lib.Equals(null)); @@ -63,12 +53,12 @@ public void TestEquality_NullAndSame() [Fact] public void Locations() { - var libDirBasePath = _fileSystem.DirectoryInfo.New("Library"); - var expectedSteamApps = _fileSystem.Path.Combine(libDirBasePath.FullName, "steamapps"); - var expectedCommon = _fileSystem.Path.Combine(expectedSteamApps, "common"); - var expectedWorkshop = _fileSystem.Path.Combine(expectedSteamApps, "workshop"); + var libDirBasePath = FileSystem.DirectoryInfo.New("Library"); + var expectedSteamApps = FileSystem.Path.Combine(libDirBasePath.FullName, "steamapps"); + var expectedCommon = FileSystem.Path.Combine(expectedSteamApps, "common"); + var expectedWorkshop = FileSystem.Path.Combine(expectedSteamApps, "workshop"); - var lib = new SteamLibrary(_fileSystem.DirectoryInfo.New("Library"), _serviceProvider); + var lib = new SteamLibrary(FileSystem.DirectoryInfo.New("Library"), ServiceProvider); Assert.Equal(expectedSteamApps, lib.SteamAppsLocation.FullName); Assert.Equal(expectedCommon, lib.CommonLocation.FullName); Assert.Equal(expectedWorkshop, lib.WorkshopsLocation.FullName); @@ -77,7 +67,7 @@ public void Locations() [Fact] public void GetApps_NoAppsInstalled_Empty() { - var library = _fileSystem.InstallSteamLibrary("Library", _serviceProvider); + var library = Steam.InstallLibrary("Library"); var apps = library.GetApps(); @@ -87,7 +77,7 @@ public void GetApps_NoAppsInstalled_Empty() [Fact] public void GetApps_NoSteamAppsDirectoryDoesNotExists_Empty() { - var library = _fileSystem.InstallSteamLibrary("Library", _serviceProvider); + var library = Steam.InstallLibrary("Library"); library.SteamAppsLocation.Delete(true); var apps = library.GetApps(); @@ -98,8 +88,8 @@ public void GetApps_NoSteamAppsDirectoryDoesNotExists_Empty() [Fact] public void GetApps_InvalidAcfFile_Skipped() { - var library = _fileSystem.InstallSteamLibrary("Library", _serviceProvider); - library.InstallCorruptApp(_fileSystem); + var library = Steam.InstallLibrary("Library"); + library.InstallCorruptApp(); var apps = library.GetApps(); @@ -109,9 +99,9 @@ public void GetApps_InvalidAcfFile_Skipped() [Fact] public void TestApps() { - var library = _fileSystem.InstallSteamLibrary("Library", _serviceProvider); + var library = Steam.InstallLibrary("Library"); - library.InstallCorruptApp(_fileSystem); + library.InstallCorruptApp(); library.InstallGame(123, "Game1", "manifest1.acf"); var expectedGame2 = library.InstallGame(456, "Game2"); library.InstallGame(123, "NotGame1", "manifest2.acf"); diff --git a/test/AET.SteamAbstraction.Test/SteamRegistryFactoryTest.cs b/test/AET.SteamAbstraction.Test/SteamRegistryFactoryTest.cs index 6a1738b6..6803f25f 100644 --- a/test/AET.SteamAbstraction.Test/SteamRegistryFactoryTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamRegistryFactoryTest.cs @@ -1,32 +1,28 @@ -using System; -using System.IO.Abstractions; -using System.Runtime.InteropServices; -using AET.SteamAbstraction.Registry; +using AET.SteamAbstraction.Registry; using AnakinRaW.CommonUtilities.Registry; using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO.Abstractions; +using System.Runtime.InteropServices; +using AnakinRaW.CommonUtilities.Testing; using Testably.Abstractions.Testing; using Xunit; namespace AET.SteamAbstraction.Test; -public class SteamRegistryFactoryTest +public class SteamRegistryFactoryTest : TestBaseWithServiceProvider { - private readonly IRegistry _registry = new InMemoryRegistry(); - private readonly MockFileSystem _fileSystem = new(); - private readonly IServiceProvider _serviceProvider; - - public SteamRegistryFactoryTest() + protected override void SetupServices(IServiceCollection serviceCollection) { - var sc = new ServiceCollection(); - sc.AddSingleton(_fileSystem); - sc.AddSingleton(_registry); - _serviceProvider = sc.BuildServiceProvider(); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new MockFileSystem()); + serviceCollection.AddSingleton(new InMemoryRegistry()); } [Fact] public void Test_CreateWrapper() { - var factory = new SteamRegistryFactory(_serviceProvider); + var factory = new SteamRegistryFactory(ServiceProvider); var registry = factory.CreateRegistry(); diff --git a/test/AET.SteamAbstraction.Test/SteamRegistryTestBase.cs b/test/AET.SteamAbstraction.Test/SteamRegistryTestBase.cs index 9777a1f7..ede7d671 100644 --- a/test/AET.SteamAbstraction.Test/SteamRegistryTestBase.cs +++ b/test/AET.SteamAbstraction.Test/SteamRegistryTestBase.cs @@ -1,40 +1,36 @@ -using System; +using AET.SteamAbstraction.Registry; +using AET.SteamAbstraction.Testing; +using AnakinRaW.CommonUtilities.Registry; +using Microsoft.Extensions.DependencyInjection; +using System; using System.IO.Abstractions; using System.Reflection; -using AET.SteamAbstraction.Registry; -using Microsoft.Extensions.DependencyInjection; +using System.Runtime.InteropServices; +using AnakinRaW.CommonUtilities.Testing; using Testably.Abstractions.Testing; using Xunit; namespace AET.SteamAbstraction.Test; -public abstract class SteamRegistryTestBase +public abstract class SteamRegistryTestBase : TestBaseWithServiceProvider { protected readonly MockFileSystem FileSystem = new(); + protected readonly IRegistry InternalRegistry = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike) + : new InMemoryRegistry(); - protected readonly string SteamInstallPath = "steamDir"; - protected readonly string SteamExePath = "steamDir/steam"; - - protected readonly IServiceProvider ServiceProvider; - - protected SteamRegistryTestBase() + protected override void SetupServices(IServiceCollection serviceCollection) { - var sc = new ServiceCollection(); - sc.AddSingleton(FileSystem); - SteamAbstractionLayer.InitializeServices(sc); - // ReSharper disable once VirtualMemberCallInConstructor - BuildServiceCollection(sc); - ServiceProvider = sc.BuildServiceProvider(); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(FileSystem); + serviceCollection.AddSingleton(InternalRegistry); + SteamAbstractionLayer.InitializeServices(serviceCollection); } private protected abstract ISteamRegistry CreateRegistry(bool steamExists = true); protected abstract void SetSteamPid(int pid); - protected virtual void BuildServiceCollection(IServiceCollection serviceCollection) - { - } - [Fact] public void TestInstallationProperties_SteamNotInstalled() { @@ -50,8 +46,8 @@ public void TestInstallationProperties_SteamInstalled() { var registry = CreateRegistry(); - Assert.Equal(FileSystem.FileInfo.New(SteamExePath).FullName, registry.ExecutableFile!.FullName); - Assert.Equal(FileSystem.DirectoryInfo.New(SteamInstallPath).FullName, registry.InstallationDirectory!.FullName); + Assert.Equal(FileSystem.FileInfo.New(TestingSteamConstants.SteamExePath).FullName, registry.ExecutableFile!.FullName); + Assert.Equal(FileSystem.DirectoryInfo.New(TestingSteamConstants.SteamInstallPath).FullName, registry.InstallationDirectory!.FullName); Assert.True(registry.ProcessId is null or 0); } @@ -60,8 +56,8 @@ public void TestInstallationProperties_SteamInstalledAndRunning() { var registry = CreateRegistry(); - Assert.Equal(FileSystem.FileInfo.New(SteamExePath).FullName, registry.ExecutableFile!.FullName); - Assert.Equal(FileSystem.DirectoryInfo.New(SteamInstallPath).FullName, registry.InstallationDirectory!.FullName); + Assert.Equal(FileSystem.FileInfo.New(TestingSteamConstants.SteamExePath).FullName, registry.ExecutableFile!.FullName); + Assert.Equal(FileSystem.DirectoryInfo.New(TestingSteamConstants.SteamInstallPath).FullName, registry.InstallationDirectory!.FullName); SetSteamPid(1234); diff --git a/test/AET.SteamAbstraction.Test/SteamVdfReaderTest.cs b/test/AET.SteamAbstraction.Test/SteamVdfReaderTest.cs index 6e3eb335..e741d6ab 100644 --- a/test/AET.SteamAbstraction.Test/SteamVdfReaderTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamVdfReaderTest.cs @@ -1,27 +1,21 @@ -using System; +using AET.SteamAbstraction.Games; +using AET.SteamAbstraction.Testing; +using AET.SteamAbstraction.Testing.TestBases; +using System; using System.Collections.Generic; using System.IO; -using System.IO.Abstractions; using System.Linq; -using AET.SteamAbstraction.Games; -using AET.SteamAbstraction.Testing.Installation; -using Microsoft.Extensions.DependencyInjection; using Testably.Abstractions.Testing; using Xunit; using VdfException = AET.SteamAbstraction.Vdf.VdfException; namespace AET.SteamAbstraction.Test; -public class SteamVdfReaderTest +public class SteamVdfReaderTest : InMemorySteamTestBase { - private readonly IServiceProvider _serviceProvider; - private readonly MockFileSystem _fileSystem = new(); - public SteamVdfReaderTest() { - var sc = new ServiceCollection(); - sc.AddSingleton(_ => _fileSystem); - _serviceProvider = sc.BuildServiceProvider(); + Steam.InstallSteamFilesOnly(); } #region ReadLibraryLocationsFromConfig @@ -29,8 +23,8 @@ public SteamVdfReaderTest() [Fact] public void ReadLibraryLocationsFromConfig_EmptyFile_Throws() { - _fileSystem.Initialize().WithFile("input.vdf"); - var input = _fileSystem.FileInfo.New("input.vdf"); + FileSystem.Initialize().WithFile("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); Assert.Throws(() => SteamVdfReader.ReadLibraryLocationsFromConfig(input).ToList()); } @@ -42,9 +36,9 @@ public void ReadLibraryLocationsFromConfig_InvalidRootNodeName_Throws() ""0"" ""/Lib"" } "; - _fileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); + FileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); - var input = _fileSystem.FileInfo.New("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); Assert.Throws(() => SteamVdfReader.ReadLibraryLocationsFromConfig(input).ToList()); } @@ -52,9 +46,9 @@ public void ReadLibraryLocationsFromConfig_InvalidRootNodeName_Throws() public void ReadLibraryLocationsFromConfig_InvalidRootNodeKind_Throws() { var data = @"""libraryfolders"" ""someData"""; - _fileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); + FileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); - var input = _fileSystem.FileInfo.New("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); Assert.Throws(() => SteamVdfReader.ReadLibraryLocationsFromConfig(input).ToList()); } @@ -82,16 +76,16 @@ public void ReadLibraryLocationsFromConfig() } "; - var expected1 = _fileSystem.DirectoryInfo.New("/Lib1").FullName; - var expected2 = _fileSystem.DirectoryInfo.New("/Lib2").FullName; - var expected3 = _fileSystem.DirectoryInfo.New("/Lib3").FullName; + var expected1 = FileSystem.DirectoryInfo.New("/Lib1").FullName; + var expected2 = FileSystem.DirectoryInfo.New("/Lib2").FullName; + var expected3 = FileSystem.DirectoryInfo.New("/Lib3").FullName; - var notExpected1 = _fileSystem.DirectoryInfo.New("/LibA").FullName; - var notExpected2 = _fileSystem.DirectoryInfo.New("/LabelA").FullName; + var notExpected1 = FileSystem.DirectoryInfo.New("/LibA").FullName; + var notExpected2 = FileSystem.DirectoryInfo.New("/LabelA").FullName; - _fileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); + FileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); - var input = _fileSystem.FileInfo.New("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); var locations = SteamVdfReader.ReadLibraryLocationsFromConfig(input).Select(l => l.FullName).ToList(); Assert.Contains(expected1, locations); @@ -109,9 +103,9 @@ public void ReadLibraryLocationsFromConfig_NoLibrariesFound_EmptyEnumerable() ""NaN"" ""/Lib"" } "; - _fileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); + FileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); - var input = _fileSystem.FileInfo.New("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); var libs = SteamVdfReader.ReadLibraryLocationsFromConfig(input); Assert.Empty(libs); } @@ -123,9 +117,9 @@ public void ReadLibraryLocationsFromConfig_EmptyContent_EmptyEnumerable() { } "; - _fileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); + FileSystem.Initialize().WithFile("input.vdf").Which(d => d.HasStringContent(data)); - var input = _fileSystem.FileInfo.New("input.vdf"); + var input = FileSystem.FileInfo.New("input.vdf"); var libs = SteamVdfReader.ReadLibraryLocationsFromConfig(input); Assert.Empty(libs); } @@ -137,15 +131,15 @@ public void ReadLibraryLocationsFromConfig_EmptyContent_EmptyEnumerable() [Fact] public void ReadManifest_NullArgs_Throws() { - var lib = _fileSystem.InstallSteamLibrary("steamLib", _serviceProvider, false); + var lib = Steam.InstallLibrary("steamLib", false); Assert.Throws(() => SteamVdfReader.ReadManifest(null!, lib)); - Assert.Throws(() => SteamVdfReader.ReadManifest(_fileSystem.FileInfo.New("path"), null!)); + Assert.Throws(() => SteamVdfReader.ReadManifest(FileSystem.FileInfo.New("path"), null!)); } [Fact] public void ReadManifest_CorrectManifest() { - var lib = _fileSystem.InstallSteamLibrary("steamLib", _serviceProvider, false); + var lib = Steam.InstallLibrary("steamLib", false); var expectedManifest = lib.InstallGame( 1230, @@ -295,19 +289,19 @@ public static IEnumerable GetInvalidAppManifestContent() [MemberData(nameof(GetInvalidAppManifestContent))] public void ReadManifest_InvalidAppManifest_Throws(string content) { - var lib = _fileSystem.InstallSteamLibrary("steamLib", _serviceProvider, false); + var lib = Steam.InstallLibrary("steamLib", false); - var manifestFile = _fileSystem.Path.Combine(lib.SteamAppsLocation.FullName, "manifest.acf"); - _fileSystem.File.WriteAllText(manifestFile, content); + var manifestFile = FileSystem.Path.Combine(lib.SteamAppsLocation.FullName, "manifest.acf"); + FileSystem.File.WriteAllText(manifestFile, content); - Assert.ThrowsAny(() => SteamVdfReader.ReadManifest(_fileSystem.FileInfo.New(manifestFile), lib)); + Assert.ThrowsAny(() => SteamVdfReader.ReadManifest(FileSystem.FileInfo.New(manifestFile), lib)); } [Fact] public void ReadManifest_ManifestNotPartOfLibrary_Throws() { - var lib = _fileSystem.InstallSteamLibrary("steamLib", _serviceProvider, false); - var otherLib = _fileSystem.InstallSteamLibrary("otherLib", _serviceProvider, false); + var lib = Steam.InstallLibrary("steamLib", false); + var otherLib = Steam.InstallLibrary("otherLib", false); var manifestFile = otherLib.InstallGame(1230, "MyGame").ManifestFile; @@ -327,7 +321,7 @@ public void ReadLoginUsers_NullFile_Throws() [Fact] public void ReadLoginUsers_FileNotExists_Throws() { - var e = Assert.ThrowsAny(() => SteamVdfReader.ReadLoginUsers(_fileSystem.FileInfo.New("NotExists.vdf"))); + var e = Assert.ThrowsAny(() => SteamVdfReader.ReadLoginUsers(FileSystem.FileInfo.New("NotExists.vdf"))); Assert.IsType(e.InnerException); } @@ -392,8 +386,8 @@ public static IEnumerable GetInvalidLoginUserContent() [MemberData(nameof(GetInvalidLoginUserContent))] public void ReadLoginUsers_FileWithInvalidContent(string content) { - _fileSystem.File.WriteAllText("loginusers.vdf", content); - var file = _fileSystem.FileInfo.New("loginusers.vdf"); + FileSystem.File.WriteAllText("loginusers.vdf", content); + var file = FileSystem.FileInfo.New("loginusers.vdf"); Assert.ThrowsAny(() => SteamVdfReader.ReadLoginUsers(file)); } @@ -427,8 +421,8 @@ public void ReadLoginUsers_FileWithNotParsableUserIdIsSkipped() ""Timestamp"" ""00000000"" } }"; - _fileSystem.File.WriteAllText("loginusers.vdf", content); - var file = _fileSystem.FileInfo.New("loginusers.vdf"); + FileSystem.File.WriteAllText("loginusers.vdf", content); + var file = FileSystem.FileInfo.New("loginusers.vdf"); var user = Assert.Single(SteamVdfReader.ReadLoginUsers(file).Users); Assert.Equal(18446744073709551615u, user.UserId); @@ -447,8 +441,8 @@ public void ReadLoginUsers_UseDefaults() } } "; - _fileSystem.File.WriteAllText("loginusers.vdf", content); - var file = _fileSystem.FileInfo.New("loginusers.vdf"); + FileSystem.File.WriteAllText("loginusers.vdf", content); + var file = FileSystem.FileInfo.New("loginusers.vdf"); var user = Assert.Single(SteamVdfReader.ReadLoginUsers(file).Users); Assert.Equal(123456789u, user.UserId); @@ -464,8 +458,8 @@ public void ReadLoginUsers_EmptyFile() { } "; - _fileSystem.File.WriteAllText("loginusers.vdf", content); - var file = _fileSystem.FileInfo.New("loginusers.vdf"); + FileSystem.File.WriteAllText("loginusers.vdf", content); + var file = FileSystem.FileInfo.New("loginusers.vdf"); Assert.Empty(SteamVdfReader.ReadLoginUsers(file).Users); } @@ -473,9 +467,7 @@ public void ReadLoginUsers_EmptyFile() [Fact] public void ReadLoginUsers() { - _fileSystem.InstallSteamFiles(); - - var expectedUsers = new List + var expectedUsers = new List { new(1, true, false), new(2, false, false), @@ -483,11 +475,14 @@ public void ReadLoginUsers() new(4, true, true), }; - var file = _fileSystem.WriteLoginUsers(expectedUsers); + var file = Steam.WriteLoginUsers(expectedUsers); var users = SteamVdfReader.ReadLoginUsers(file); - Assert.Equal(expectedUsers, users.Users.OrderBy(x => x.UserId).ToList(), new SteamUserLoginMetadataEqualityComparer()); + Assert.Equal( + expectedUsers.Select(x => new SteamUserLoginMetadata(x.UserId, x.MostRecent, x.UserWantsOffline)), + users.Users.OrderBy(x => x.UserId).ToList(), + new SteamUserLoginMetadataEqualityComparer()); } private class SteamUserLoginMetadataEqualityComparer : IEqualityComparer diff --git a/test/AET.SteamAbstraction.Test/SteamWrapperFactoryTest.cs b/test/AET.SteamAbstraction.Test/SteamWrapperFactoryTest.cs index 5d104d6f..4ca43ff6 100644 --- a/test/AET.SteamAbstraction.Test/SteamWrapperFactoryTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamWrapperFactoryTest.cs @@ -1,34 +1,27 @@ -using System; -using System.IO.Abstractions; +using System.IO.Abstractions; using AnakinRaW.CommonUtilities.Registry; +using AnakinRaW.CommonUtilities.Testing; +using AnakinRaW.CommonUtilities.Testing.Attributes; using Microsoft.Extensions.DependencyInjection; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; namespace AET.SteamAbstraction.Test; -public class SteamWrapperFactoryTest +public class SteamWrapperFactoryTest : TestBaseWithServiceProvider { - private readonly IServiceProvider _serviceProvider; - - public SteamWrapperFactoryTest() + protected override void SetupServices(IServiceCollection serviceCollection) { - var sc = new ServiceCollection(); - var registry = new InMemoryRegistry(); - var fs = new MockFileSystem(); - - sc.AddSingleton(fs); - sc.AddSingleton(registry); - SteamAbstractionLayer.InitializeServices(sc); - - _serviceProvider = sc.BuildServiceProvider(); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new MockFileSystem()); + serviceCollection.AddSingleton(new InMemoryRegistry()); + SteamAbstractionLayer.InitializeServices(serviceCollection); } [PlatformSpecificFact(TestPlatformIdentifier.Windows)] public void Test_CreateWrapper_Windows() { - var factory = new SteamWrapperFactory(_serviceProvider); + var factory = new SteamWrapperFactory(ServiceProvider); var wrapper = factory.CreateWrapper(); Assert.IsType(wrapper); } diff --git a/test/AET.SteamAbstraction.Test/SteamWrapperIntegrationTest.cs b/test/AET.SteamAbstraction.Test/SteamWrapperIntegrationTest.cs index ac91aa74..6a2ad8e7 100644 --- a/test/AET.SteamAbstraction.Test/SteamWrapperIntegrationTest.cs +++ b/test/AET.SteamAbstraction.Test/SteamWrapperIntegrationTest.cs @@ -3,27 +3,29 @@ using System.Threading.Tasks; using AnakinRaW.CommonUtilities.Registry; using AnakinRaW.CommonUtilities.Registry.Windows; +using AnakinRaW.CommonUtilities.Testing; using Microsoft.Extensions.DependencyInjection; using Testably.Abstractions; using Xunit; namespace AET.SteamAbstraction.Test; -public class SteamWrapperIntegrationTest +public class SteamWrapperIntegrationTest : TestBaseWithServiceProvider { private readonly ISteamWrapper _service; public SteamWrapperIntegrationTest() { - var sc = new ServiceCollection(); - // Use actual FS - sc.AddSingleton(new RealFileSystem()); - SteamAbstractionLayer.InitializeServices(sc); + _service = ServiceProvider.GetRequiredService().CreateWrapper(); + } + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new RealFileSystem()); + SteamAbstractionLayer.InitializeServices(serviceCollection); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - sc.AddSingleton(new WindowsRegistry()); - - _service = sc.BuildServiceProvider().GetRequiredService().CreateWrapper(); + serviceCollection.AddSingleton(new WindowsRegistry()); } //[Fact] diff --git a/test/AET.SteamAbstraction.Test/SteamWrapperTestBase.cs b/test/AET.SteamAbstraction.Test/SteamWrapperTestBase.cs index 68140391..606a410a 100644 --- a/test/AET.SteamAbstraction.Test/SteamWrapperTestBase.cs +++ b/test/AET.SteamAbstraction.Test/SteamWrapperTestBase.cs @@ -1,53 +1,51 @@ using System; using System.Collections.Generic; -using System.IO.Abstractions; using System.Linq; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using AET.SteamAbstraction.Library; -using AET.SteamAbstraction.Registry; using AET.SteamAbstraction.Testing; -using AET.SteamAbstraction.Testing.Installation; +using AET.SteamAbstraction.Testing.TestBases; using AET.SteamAbstraction.Utilities; using AnakinRaW.CommonUtilities; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; -using PG.TestingUtilities; -using Testably.Abstractions.Testing; using Xunit; namespace AET.SteamAbstraction.Test; -public abstract class SteamWrapperTestBase : IDisposable +[SupportedOSPlatform("windows")] +public abstract class SteamWrapperTestBase : InMemorySteamTestBase { private readonly ISteamWrapperFactory _wrapperFactory; - protected readonly MockFileSystem FileSystem = new(); - protected readonly IServiceProvider ServiceProvider; internal TestProcessHelper? ProcessHelper; protected SteamWrapperTestBase() { - var sc = new ServiceCollection(); - sc.AddSingleton(FileSystem); - SteamAbstractionLayer.InitializeServices(sc); - sc.AddSingleton(sp => + _wrapperFactory = ServiceProvider.GetRequiredService(); + } + + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(sp => { return ProcessHelper = new TestProcessHelper(sp); }); - // ReSharper disable once VirtualMemberCallInConstructor - BuildServiceCollection(sc); - ServiceProvider = sc.BuildServiceProvider(); - _wrapperFactory = ServiceProvider.GetRequiredService(); + serviceCollection.AddSingleton(sp => sp.GetRequiredService()); } - protected virtual void BuildServiceCollection(IServiceCollection serviceCollection) + public override void Dispose() { + base.Dispose(); + ProcessHelper?.KillCurrent(); } protected void InstallSteam() { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - FileSystem.InstallSteam(registry); + Steam.Install(); } private protected SteamWrapper CreateWrapper() @@ -69,7 +67,7 @@ public async Task TestInstalled() Assert.Throws(() => wrapper.IsGameInstalled(123, out _)); Assert.Throws(wrapper.StartSteam); - await Assert.ThrowsAsync(() => wrapper.WaitSteamRunningAndLoggedInAsync(TestHelpers.RandomBool(), CancellationToken.None)); + await Assert.ThrowsAsync(() => wrapper.WaitSteamRunningAndLoggedInAsync(Random.Bool(), CancellationToken.None)); // Install Steam InstallSteam(); @@ -97,7 +95,7 @@ public async Task TestDisposed() Assert.Throws(() => wrapper.UserWantsOfflineMode); Assert.Throws(wrapper.StartSteam); Assert.Throws(() => wrapper.IsGameInstalled(123, out _)); - await Assert.ThrowsAsync(() => wrapper.WaitSteamRunningAndLoggedInAsync(TestHelpers.RandomBool(), CancellationToken.None)); + await Assert.ThrowsAsync(() => wrapper.WaitSteamRunningAndLoggedInAsync(Random.Bool(), CancellationToken.None)); } [Fact] @@ -121,8 +119,7 @@ public void IsRunning_RegistryHasPidSetButProcessNotRunning() var wrapper = CreateWrapper(); var expectedPid = new Random().Next(0, int.MaxValue); - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetPid(expectedPid); + Steam.Registry.SetPid(expectedPid); Assert.False(wrapper.IsRunning); Assert.False(wrapper.IsUserLoggedIn); @@ -137,11 +134,11 @@ public void Libraries() Assert.Empty(wrapper.Libraries); - var expectedLib = FileSystem.InstallDefaultLibrary(ServiceProvider); + var expectedLib = Steam.InstallDefaultLibrary(); var lib = Assert.Single(wrapper.Libraries); Assert.Equal(expectedLib, lib); - var otherExpectedLib = FileSystem.InstallSteamLibrary("externalLib", ServiceProvider); + var otherExpectedLib = Steam.InstallLibrary("externalLib"); Assert.Equal( new List{ expectedLib, otherExpectedLib }.OrderBy(x => x.LibraryLocation.FullName), wrapper.Libraries.OrderBy(x => x.LibraryLocation.FullName)); @@ -159,7 +156,7 @@ public void IsGameInstalled() Assert.Null(game); - var lib = FileSystem.InstallDefaultLibrary(ServiceProvider); + var lib = Steam.InstallDefaultLibrary(); // One Lib with no games Assert.False(wrapper.IsGameInstalled(123, out game)); Assert.Null(game); @@ -174,8 +171,8 @@ public void IsGameInstalled() Assert.Null(otherGame); - var otherLib = FileSystem.InstallSteamLibrary("externalLib", ServiceProvider); - otherLib.InstallCorruptApp(FileSystem); + var otherLib = Steam.InstallLibrary("externalLib"); + otherLib.InstallCorruptApp(); var otherExpectedGame = otherLib.InstallGame(456, "OtherGame"); Assert.True(wrapper.IsGameInstalled(456, out otherGame)); Assert.NotNull(otherGame); @@ -211,27 +208,31 @@ public void UserWantsOfflineMode() InstallSteam(); var wrapper = CreateWrapper(); - FileSystem.DeleteLoginUsersFile(); + Steam.DeleteLoginUsersFile(); Assert.Null(wrapper.UserWantsOfflineMode); - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(ulong.MaxValue, false, false)); + Steam.WriteLoginUsers(new TestingSteamUserLoginMetadata(ulong.MaxValue, mostRecent: false, userWantsOffline: false)); Assert.False(wrapper.UserWantsOfflineMode); // Not most recent - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(ulong.MaxValue, false, true)); + Steam.WriteLoginUsers(new TestingSteamUserLoginMetadata(ulong.MaxValue, false, true)); Assert.False(wrapper.UserWantsOfflineMode); - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(ulong.MaxValue, true, true)); + Steam.WriteLoginUsers(new TestingSteamUserLoginMetadata(ulong.MaxValue, true, true)); Assert.True(wrapper.UserWantsOfflineMode); - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(ulong.MaxValue, false, true), new SteamUserLoginMetadata(456, true, true)); + Steam.WriteLoginUsers( + new TestingSteamUserLoginMetadata(ulong.MaxValue, false, true), + new TestingSteamUserLoginMetadata(456, true, true)); Assert.True(wrapper.UserWantsOfflineMode); // Not most recent - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(ulong.MaxValue, false, true), new SteamUserLoginMetadata(456, true, false)); + Steam.WriteLoginUsers( + new TestingSteamUserLoginMetadata(ulong.MaxValue, false, true), + new TestingSteamUserLoginMetadata(456, true, userWantsOffline: false)); Assert.False(wrapper.UserWantsOfflineMode); - FileSystem.WriteCorruptLoginUsers(); + Steam.WriteCorruptLoginUsers(); Assert.Null(wrapper.UserWantsOfflineMode); } @@ -266,7 +267,7 @@ public async Task WaitSteamRunningAndLoggedInAsync_SteamNotRunningAndShouldNotSt LoginUser(12345); - await Assert.ThrowsAsync(async () => await wrapper.WaitSteamRunningAndLoggedInAsync(false)); + await Assert.ThrowsAsync(async () => await wrapper.WaitSteamRunningAndLoggedInAsync(false, TestContext.Current.CancellationToken)); Assert.Equal(0u, wrapper.GetCurrentUserId()); } @@ -280,7 +281,7 @@ public async Task TestWaitSteamRunningAndLoggedInAsync_LoggedIn() FakeStartSteam(); LoginUser(12345); - await wrapper.WaitSteamRunningAndLoggedInAsync(false); + await wrapper.WaitSteamRunningAndLoggedInAsync(false, TestContext.Current.CancellationToken); Assert.Equal(12345u, wrapper.GetCurrentUserId()); } @@ -291,7 +292,7 @@ public async Task TestWaitSteamRunningAndLoggedInAsync_DelayedLogin() InstallSteam(); var wrapper = CreateWrapper(); - var waitTask = wrapper.WaitSteamRunningAndLoggedInAsync(true); + var waitTask = wrapper.WaitSteamRunningAndLoggedInAsync(true, TestContext.Current.CancellationToken); // Ensure that code had time to proceed to past running check. then wait a little more. await wrapper.WaitSteamRunningAsync(CancellationToken.None) @@ -361,39 +362,27 @@ public async Task WaitSteamRunningAndLoggedInAsync_UserDoesNotLoginBeforeCancell private void StopSteam() { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetPid(null); + Steam.Registry.SetPid(null); ProcessHelper!.SetRunningPid(null); } - private void FakeStartSteam(int pid) - { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetPid(pid); - ProcessHelper!.SetRunningPid(pid); - } - private void FakeStartSteam() { - FakeStartSteam(new Random().Next(100, 10000)); + Assert.NotNull(Steam); + Steam.FakeStart(new Random().Next(100, 10000)); } protected virtual void LogoutUser() { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetUserId(0); - FileSystem.WriteLoginUsers(null); + Assert.NotNull(Steam); + Steam.Registry.SetUserId(0); + Steam.WriteLoginUsers(null); } protected virtual void LoginUser(uint userId) { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetUserId(userId); - FileSystem.WriteLoginUsers(new SteamUserLoginMetadata(userId, true, false)); - } - - public void Dispose() - { - ProcessHelper?.KillCurrent(); + Assert.NotNull(Steam); + Steam.Registry.SetUserId(userId); + Steam.WriteLoginUsers(new TestingSteamUserLoginMetadata(userId, true, userWantsOffline: false)); } } \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Test/Windows/WindowsSteamRegistryTest.cs b/test/AET.SteamAbstraction.Test/Windows/WindowsSteamRegistryTest.cs index 5d2dd58f..e19e1423 100644 --- a/test/AET.SteamAbstraction.Test/Windows/WindowsSteamRegistryTest.cs +++ b/test/AET.SteamAbstraction.Test/Windows/WindowsSteamRegistryTest.cs @@ -1,21 +1,14 @@ #if Windows using AET.SteamAbstraction.Registry; +using AET.SteamAbstraction.Testing; using AnakinRaW.CommonUtilities.Registry; -using Microsoft.Extensions.DependencyInjection; using Xunit; namespace AET.SteamAbstraction.Test.Windows; public class WindowsSteamRegistryTest : SteamRegistryTestBase { - protected readonly IRegistry InternalRegistry = new InMemoryRegistry(); - - protected override void BuildServiceCollection(IServiceCollection serviceCollection) - { - serviceCollection.AddSingleton(InternalRegistry); - } - internal WindowsSteamRegistry CreateWindowsRegistry(bool steamExists = true) { var registry = new WindowsSteamRegistry(ServiceProvider); @@ -25,8 +18,8 @@ internal WindowsSteamRegistry CreateWindowsRegistry(bool steamExists = true) using var hkcu = InternalRegistry.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default); using var steamKey = hkcu.CreateSubKey("Software\\Valve\\Steam")!; - steamKey.SetValue("SteamExe", FileSystem.Path.GetFullPath(SteamExePath)); - steamKey.SetValue("SteamPath", FileSystem.Path.GetFullPath(SteamInstallPath)); + steamKey.SetValue("SteamExe", FileSystem.Path.GetFullPath(TestingSteamConstants.SteamExePath)); + steamKey.SetValue("SteamPath", FileSystem.Path.GetFullPath(TestingSteamConstants.SteamInstallPath)); } return registry; diff --git a/test/AET.SteamAbstraction.Test/Windows/WindowsSteamWrapperTest.cs b/test/AET.SteamAbstraction.Test/Windows/WindowsSteamWrapperTest.cs index f814648d..9986ba4c 100644 --- a/test/AET.SteamAbstraction.Test/Windows/WindowsSteamWrapperTest.cs +++ b/test/AET.SteamAbstraction.Test/Windows/WindowsSteamWrapperTest.cs @@ -1,21 +1,11 @@ #if Windows - using System; -using AnakinRaW.CommonUtilities.Registry; -using Microsoft.Extensions.DependencyInjection; using Xunit; namespace AET.SteamAbstraction.Test.Windows; public class WindowsSteamWrapperTest : SteamWrapperTestBase { - protected readonly IRegistry InternalRegistry = new InMemoryRegistry(); - - protected override void BuildServiceCollection(IServiceCollection serviceCollection) - { - serviceCollection.AddSingleton(InternalRegistry); - } - [Fact] public void TestInvalidArgs_Throws() { diff --git a/test/AET.SteamAbstraction.Testing/AET.SteamAbstraction.Testing.csproj b/test/AET.SteamAbstraction.Testing/AET.SteamAbstraction.Testing.csproj index 90660bc1..d5942647 100644 --- a/test/AET.SteamAbstraction.Testing/AET.SteamAbstraction.Testing.csproj +++ b/test/AET.SteamAbstraction.Testing/AET.SteamAbstraction.Testing.csproj @@ -1,51 +1,39 @@ - + - AET.SteamAbstraction.TestingUtilities + AET.SteamAbstraction.Testing + netstandard2.0;net10.0 + true + false - net10.0 - $(TargetFrameworks);net481 - false - false + AET.SteamAbstraction.Testing + Provides a testing layer that allowes to virtualize Steam, so that it does not need to be physically installed. + AlamoEngineTools.SteamAbstraction.Testing + alamo,petroglyph,glyphx + en + + true + true + true + + + true + snupkg + + - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - diff --git a/test/AET.SteamAbstraction.Testing/AssemblyInfo.cs b/test/AET.SteamAbstraction.Testing/AssemblyInfo.cs deleted file mode 100644 index 1957ee0b..00000000 --- a/test/AET.SteamAbstraction.Testing/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("AET.SteamAbstraction.Test")] -[assembly: InternalsVisibleTo("PG.StarWarsGame.Infrastructure.Clients.Steam.Test")] diff --git a/test/AET.SteamAbstraction.Testing/CompilerHelpers/Attributes.cs b/test/AET.SteamAbstraction.Testing/CompilerHelpers/Attributes.cs new file mode 100644 index 00000000..e1dc9a46 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/CompilerHelpers/Attributes.cs @@ -0,0 +1,45 @@ +#if !NET5_0_OR_GREATER +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +namespace System.Runtime.Versioning; + +/// +/// Base type for all platform-specific API attributes. +/// + +internal abstract class OSPlatformAttribute(string platformName) : Attribute +{ + public string PlatformName { get; } = platformName; +} + +/// +/// Records the platform that the project targeted. +/// +[AttributeUsage(AttributeTargets.Assembly)] +internal sealed class TargetPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); + +/// +/// Records the operating system (and minimum version) that supports an API. Multiple attributes can be +/// applied to indicate support on multiple operating systems. +/// +/// +/// Callers can apply a +/// or use guards to prevent calls to APIs on unsupported operating systems. +/// +/// A given platform should only be specified once. +/// +[AttributeUsage(AttributeTargets.Assembly | + AttributeTargets.Class | + AttributeTargets.Constructor | + AttributeTargets.Enum | + AttributeTargets.Event | + AttributeTargets.Field | + AttributeTargets.Interface | + AttributeTargets.Method | + AttributeTargets.Module | + AttributeTargets.Property | + AttributeTargets.Struct, + AllowMultiple = true, Inherited = false)] +internal sealed class SupportedOSPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); +// ReSharper restore InconsistentNaming +#endif \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/ISteamFakeProcess.cs b/test/AET.SteamAbstraction.Testing/ISteamFakeProcess.cs new file mode 100644 index 00000000..669b3183 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/ISteamFakeProcess.cs @@ -0,0 +1,15 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +namespace AET.SteamAbstraction.Testing; + +/// +/// Represents a fake Steam process for testing purposes. +/// +public interface ISteamFakeProcess +{ + /// + /// Terminates the associated process. + /// + void Kill(); +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/ITestingSteamInstallation.cs b/test/AET.SteamAbstraction.Testing/ITestingSteamInstallation.cs new file mode 100644 index 00000000..92f0d4a6 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/ITestingSteamInstallation.cs @@ -0,0 +1,76 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Runtime.Versioning; + +namespace AET.SteamAbstraction.Testing; + +/// +/// Represents a testing Steam installation that can be manipulated for testing purposes. +/// +public interface ITestingSteamInstallation : IDisposable +{ + /// + /// Gets the directory where the Steam is installed or if the test installation is not installed. + /// + IDirectoryInfo? InstallationDirectory { get; } + + /// + /// Gets the testing registry. + /// + ITestingSteamRegistry Registry { get; } + + /// + /// Installs the testing Steam installation to the file system and registry. + /// + [SupportedOSPlatform("windows")] + void Install(); + + /// + /// Installs the testing Steam installation to the file system only. + /// + void InstallSteamFilesOnly(); + + /// + /// Starts a simulated Steam process for the specified process ID. + /// + /// The process identifier (PID) of the process to simulate. + /// An instance representing the simulated Steam process. + [SupportedOSPlatform("windows")] + ISteamFakeProcess FakeStart(int pid); + + /// + /// Installs the default Steam game library. + /// + /// to add the installed library to the configuration; otherwise, . The default is . + /// An instance representing the newly installed game library. + ITestingSteamLibrary InstallDefaultLibrary(bool addToConfig = true); + + /// + /// Installs a new Steam game library at the specified path and returns the library. + /// + /// The path where the new Steam library will be installed. + /// to add the installed library to the configuration; otherwise, . The default is . + /// An instance representing the newly installed game library. + ITestingSteamLibrary InstallLibrary(string path, bool addToConfig = true); + + /// + /// Writes an invalid "loginusers.vdf". + /// + void WriteCorruptLoginUsers(); + + /// + /// Deletes the "loginusers.vdf" file. + /// + void DeleteLoginUsersFile(); + + /// + /// Writes the specified Steam user login information to a new "loginusers.vdf". + /// + /// A parameter array of collections containing the login metadata for each Steam user to write. + /// An representing the file containing the written login user data. + IFileInfo WriteLoginUsers(params IEnumerable? users); +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/ITestingSteamLibrary.cs b/test/AET.SteamAbstraction.Testing/ITestingSteamLibrary.cs new file mode 100644 index 00000000..1038c94c --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/ITestingSteamLibrary.cs @@ -0,0 +1,59 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.SteamAbstraction.Games; +using AET.SteamAbstraction.Library; +using System.Collections.Generic; + +namespace AET.SteamAbstraction.Testing; + +/// +/// Represents a testing Steam game library that can be manipulated for testing purposes. +/// +public interface ITestingSteamLibrary : ISteamLibrary +{ + /// + /// Installs a game with the specified game ID, name, and manifest file name, and returns the associated + /// Steam application manifest. + /// + /// The ID of the game to install. + /// The display name of the game to be installed. + /// The name of the manifest file to use for installation. + /// A object representing the installed game's manifest. + SteamAppManifest InstallGame(uint id, string gameName, string appManifestName); + + /// + /// Installs a game with the specified game ID, name, number of installed depots and app state, and returns the associated + /// Steam application manifest. + /// + /// The ID of the game to install. + /// The display name of the game to be installed. + /// The number of depots to be installed. + /// The state of the installed game. + /// A object representing the installed game's manifest. + SteamAppManifest InstallGame( + uint id, + string gameName, + uint numberDepots = 1, + SteamAppState appState = SteamAppState.StateFullyInstalled); + + /// + /// Installs a game with the specified game ID, name, a list of installed depots and app state, and returns the associated + /// Steam application manifest. + /// + /// The ID of the game to install. + /// The display name of the game to be installed. + /// A list of depots to be installed. + /// The state of the installed game. + /// A object representing the installed game's manifest. + SteamAppManifest InstallGame( + uint id, + string gameName, + IList depots, + SteamAppState appState = SteamAppState.StateFullyInstalled); + + /// + /// Creates an intentionally corrupted game manifest. + /// + void InstallCorruptApp(); +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/ITestingSteamRegistry.cs b/test/AET.SteamAbstraction.Testing/ITestingSteamRegistry.cs new file mode 100644 index 00000000..941a7440 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/ITestingSteamRegistry.cs @@ -0,0 +1,48 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.IO.Abstractions; +using System.Runtime.Versioning; + +namespace AET.SteamAbstraction.Testing; + +/// +/// Defines methods and properties for querying and manipulating a test Steam client's registry state. +/// +public interface ITestingSteamRegistry : IDisposable +{ + /// + /// Gets the executable of the Steam client. + /// + IFileInfo? ExecutableFile { get; } + + /// + /// Gets the installation directory of the Steam client + /// + IDirectoryInfo? InstallationDirectory { get; } + + /// + /// The PID of the current Steam Process. 0 or if Steam is not running. + /// + int? ProcessId { get; } + + /// + /// Registers a test installation of the Steam client to the registry. + /// + [SupportedOSPlatform("windows")] + void InstallSteam(); + + /// + /// Writes the specified process identifier as running Steam process to the registry. + /// + /// The process identifier to set. to indicate Steam is not running. + [SupportedOSPlatform("windows")] + void SetPid(int? pid); + + /// + /// Writes the identifier for the current user to the registry. + /// + /// The unique identifier to assign to the user. + void SetUserId(uint userId); +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Game.cs b/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Game.cs deleted file mode 100644 index 3e0fb259..00000000 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Game.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using System.IO.Abstractions; -using System.Text; -using AET.SteamAbstraction.Games; -using AET.SteamAbstraction.Library; -using Xunit; - -namespace AET.SteamAbstraction.Testing.Installation; - -internal static partial class SteamInstallation -{ - public static void InstallCorruptApp(this ISteamLibrary library, IFileSystem fileSystem) - { - var randomAcfName = fileSystem.Path.GetRandomFileName() + ".acf"; - library.SteamAppsLocation.Create(); - - fileSystem.File.WriteAllText(fileSystem.Path.Combine(library.SteamAppsLocation.FullName, randomAcfName), "\0"); - } - - public static SteamAppManifest InstallGame( - this ISteamLibrary library, - uint id, - string gameName, - string appManifestName) - { - return InstallGameCore(library, id, appManifestName, gameName, [id+1]); - } - - public static SteamAppManifest InstallGame( - this ISteamLibrary library, - uint id, - string gameName, - uint numberDepots = 1, - SteamAppState appState = SteamAppState.StateFullyInstalled) - { - var manifestFileName = $"appmanifest_{id}.acf"; - var depots = new List(); - for (uint i = 1; i < numberDepots + 1; i++) - depots.Add(i); - return InstallGameCore(library, id, manifestFileName, gameName, depots, appState); - } - - public static SteamAppManifest InstallGame( - this ISteamLibrary library, - uint id, - string gameName, - IList depots, - SteamAppState appState = SteamAppState.StateFullyInstalled) - { - var manifestFileName = $"appmanifest_{id}.acf"; - return InstallGameCore(library, id, manifestFileName, gameName, depots, appState); - } - - private static SteamAppManifest InstallGameCore( - this ISteamLibrary library, - uint id, - string appManifestName, - string gameName, - IList depots, - SteamAppState appState = SteamAppState.StateFullyInstalled) - { - var fs = library.SteamAppsLocation.FileSystem; - - - var depotSb = new StringBuilder(); - foreach (var depot in depots) - { - depotSb.Append($@" - ""{depot}"" - {{ - }} -"); - } - - var manifestContent = $@" -""AppState"" -{{ - ""appid"" ""{id}"" - ""name"" ""{gameName}"" - ""StateFlags"" ""{(int)appState}"" - ""installdir"" ""{gameName}"" - ""InstalledDepots"" - {{ - {depotSb} - }} - ""someProperty"" ""someValue"" -}} -"; - - var manifestFilePath = fs.Path.Combine(library.SteamAppsLocation.FullName, appManifestName); - fs.File.WriteAllText(manifestFilePath, manifestContent); - - Assert.True(fs.File.Exists(manifestFilePath)); - - var gamePath = fs.Path.Combine(library.CommonLocation.FullName, gameName); - var gameDir = fs.Directory.CreateDirectory(gamePath); - - return new SteamAppManifest(library, fs.FileInfo.New(manifestFilePath), id, gameName, gameDir, - SteamAppState.StateFullyInstalled, new HashSet()); - } -} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Linux.cs b/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Linux.cs deleted file mode 100644 index 2b42d713..00000000 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Linux.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.IO.Abstractions; - -namespace AET.SteamAbstraction.Testing.Installation; - -internal static partial class SteamInstallation -{ - private static void InstallLinuxRegistry(LinuxSteamRegistry registry, IFileSystem fs) - { - // TODO - } - - private static void SetPidLinuxRegistry(LinuxSteamRegistry linuxRegistry, int? pid) - { - // TODO - } -} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Windows.cs b/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Windows.cs deleted file mode 100644 index 90a80bd5..00000000 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.Windows.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO.Abstractions; - -namespace AET.SteamAbstraction.Testing.Installation; - -internal static partial class SteamInstallation -{ - private static void InstallWindowsRegistry(WindowsSteamRegistry registry, IFileSystem fs) - { - using var key = registry.GetSteamRegistryKey(); - - key.SetValue("SteamExe", fs.Path.GetFullPath(SteamExePath)); - key.SetValue("SteamPath", fs.Path.GetFullPath(SteamInstallPath)); - } - - private static void SetPidWindowsRegistry(WindowsSteamRegistry registry, int? pid) - { - if (pid is null) - return; - using var key = registry.GetSteamRegistryKey(); - using var activeProcessKey = key.CreateSubKey("ActiveProcess"); - - activeProcessKey!.SetValue("pid", pid); - } - - private static void SetUserIdWindowsRegistry(WindowsSteamRegistry registry, uint userId) - { - using var key = registry.GetSteamRegistryKey(); - using var activeProcessKey = key.CreateSubKey("ActiveProcess"); - - activeProcessKey!.SetValue("ActiveUser", userId); - } -} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.cs b/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.cs deleted file mode 100644 index bf7c600c..00000000 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Registry.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.IO.Abstractions; -using AET.SteamAbstraction.Registry; - -namespace AET.SteamAbstraction.Testing.Installation; - -internal static partial class SteamInstallation -{ - public static void InstallSteam(this ISteamRegistry registry, IFileSystem fs) - { - if (registry is WindowsSteamRegistry windowsRegistry) - InstallWindowsRegistry(windowsRegistry, fs); - else if (registry is LinuxSteamRegistry linuxRegistry) - InstallLinuxRegistry(linuxRegistry, fs); - } - - - public static void SetPid(this ISteamRegistry registry, int? pid) - { - if (registry is WindowsSteamRegistry windowsRegistry) - SetPidWindowsRegistry(windowsRegistry, pid); - else if (registry is LinuxSteamRegistry linuxRegistry) - SetPidLinuxRegistry(linuxRegistry, pid); - } - - public static void SetUserId(this ISteamRegistry registry, uint userId) - { - if (registry is WindowsSteamRegistry windowsRegistry) - SetUserIdWindowsRegistry(windowsRegistry, userId); - // Does not exist for Linux - } -} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.cs b/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.cs deleted file mode 100644 index 16c04a49..00000000 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Collections.Generic; -using System.IO.Abstractions; -using System.Text; -using AET.SteamAbstraction.Registry; - -namespace AET.SteamAbstraction.Testing.Installation; - -internal static partial class SteamInstallation -{ - // Ensure starts on path 'steam'. See GameInstallation.cs - private const string SteamInstallPath = "steam"; - private const string SteamExePath = "steam/steam.exe"; - - public static void InstallSteam(this IFileSystem fs, ISteamRegistry registry) - { - registry.InstallSteam(fs); - fs.InstallSteamFiles(); - } - - public static void InstallSteamFiles(this IFileSystem fs) - { - var configPath = fs.Path.GetFullPath(fs.Path.Combine(SteamInstallPath, "config")); - var exePath = fs.Path.GetFullPath(SteamExePath); - - fs.Directory.CreateDirectory(configPath); - using var _ = fs.File.Create(exePath); - } - - public static void DeleteLoginUsersFile(this IFileSystem fs) - { - var configPath = fs.Path.GetFullPath(fs.Path.Combine(SteamInstallPath, "config")); - var loginUsersPath = fs.Path.Combine(configPath, "loginusers.vdf"); - fs.File.Delete(loginUsersPath); - } - - public static void WriteCorruptLoginUsers(this IFileSystem fs) - { - var configPath = fs.Path.GetFullPath(fs.Path.Combine(SteamInstallPath, "config")); - var loginUsersPath = fs.Path.Combine(configPath, "loginusers.vdf"); - fs.File.WriteAllText(loginUsersPath, "\0"); - } - - public static IFileInfo WriteLoginUsers(this IFileSystem fs, params IEnumerable? users) - { - var configPath = fs.Path.GetFullPath(fs.Path.Combine(SteamInstallPath, "config")); - var loginUsersPath = fs.Path.Combine(configPath, "loginusers.vdf"); - - var content = $@" -""users"" -{{ - {SerializeUsers(users)} -}} -"; - fs.File.WriteAllText(loginUsersPath, content); - return fs.FileInfo.New(loginUsersPath); - } - - private static string SerializeUsers(IEnumerable? users) - { - var sb = new StringBuilder(); - - if (users is null) - return string.Empty; - - foreach (var metadata in users) - { - var content = $@" - ""{metadata.UserId}"" - {{ - ""AccountName"" ""someName"" - ""PersonaName"" ""some Name"" - ""RememberPassword"" ""1"" - ""WantsOfflineMode"" ""{BoolToNumber(metadata.UserWantsOffline)}"" - ""SkipOfflineModeWarning"" ""0"" - ""AllowAutoLogin"" ""1"" - ""MostRecent"" ""{BoolToNumber(metadata.MostRecent)}"" - ""Timestamp"" ""0000000000"" - }}"; - - sb.AppendLine(content); - - } - - return sb.ToString(); - } - - - private static int BoolToNumber(bool value) - { - return value ? 1 : 0; - } -} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/SteamFakeProcessImpl.cs b/test/AET.SteamAbstraction.Testing/SteamFakeProcessImpl.cs new file mode 100644 index 00000000..e2cd1256 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/SteamFakeProcessImpl.cs @@ -0,0 +1,25 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Runtime.Versioning; + +namespace AET.SteamAbstraction.Testing; + +[SupportedOSPlatform("windows")] +internal sealed class SteamFakeProcessImpl : ISteamFakeProcess +{ + private readonly TestProcessHelper _processHelper; + + public SteamFakeProcessImpl(IServiceProvider serviceProvider, int pid) + { + _processHelper = serviceProvider.GetRequiredService(); + _processHelper.SetRunningPid(pid); + } + + public void Kill() + { + _processHelper.KillCurrent(); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/SteamInstallationExtensions.cs b/test/AET.SteamAbstraction.Testing/SteamInstallationExtensions.cs new file mode 100644 index 00000000..45ef2cb1 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/SteamInstallationExtensions.cs @@ -0,0 +1,35 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; + +namespace AET.SteamAbstraction.Testing; + +/// +/// Provides factory methods for creating abstractions of Steam installations for testing purposes. +/// +/// +/// This class is intended for use in testing scenarios where mock or test implementations of Steam-related services are required. +/// +public static class SteamTesting +{ + /// + /// Creates a new instance of a Steam installation abstraction for testing using the specified service provider. + /// + /// The service provider used to resolve dependencies required by the testing Steam installation. + /// An instance of initialized with the provided service provider. + public static ITestingSteamInstallation Steam(IServiceProvider serviceProvider) + { + return new TestingSteamInstallationImpl(serviceProvider); + } + + /// + /// Creates a new instance of a Steam registry abstraction for testing using the specified service provider. + /// + /// The service provider used to resolve dependencies required by the testing Steam registry implementation. + /// An instance of initialized with the provided service provider. + public static ITestingSteamRegistry SteamRegistry(IServiceProvider serviceProvider) + { + return new TestingSteamRegistryImpl(serviceProvider); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestBases/InMemorySteamTestBase.cs b/test/AET.SteamAbstraction.Testing/TestBases/InMemorySteamTestBase.cs new file mode 100644 index 00000000..ca3960ec --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestBases/InMemorySteamTestBase.cs @@ -0,0 +1,32 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System.IO.Abstractions; +using System.Runtime.InteropServices; +using AnakinRaW.CommonUtilities.Registry; +using Microsoft.Extensions.DependencyInjection; +using Testably.Abstractions.Testing; + +namespace AET.SteamAbstraction.Testing.TestBases; + +/// +/// Provides a base class for Steam-related tests that work with in-memory file system and registry. +/// +public abstract class InMemorySteamTestBase : SteamTestBase +{ + /// + /// Gets the in-memory file system used for testing. + /// + protected readonly MockFileSystem FileSystem = new(); + + /// + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike) + : new InMemoryRegistry()); + + serviceCollection.AddSingleton(FileSystem); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestBases/SteamTestBase.cs b/test/AET.SteamAbstraction.Testing/TestBases/SteamTestBase.cs new file mode 100644 index 00000000..06e5e5fb --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestBases/SteamTestBase.cs @@ -0,0 +1,50 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using AnakinRaW.CommonUtilities.Testing; +using Microsoft.Extensions.DependencyInjection; + +namespace AET.SteamAbstraction.Testing.TestBases; + +/// +/// Provides a base class for integration tests that require access to a testing Steam installation and related +/// services. +/// +/// +/// Inheritors can use the protected instance to interact with a +/// test Steam environment. The class ensures that required Steam services are initialized and disposed +/// appropriately. +/// +public abstract class SteamTestBase : TestBaseWithServiceProvider, IDisposable +{ + /// + /// Gets the testing Steam installation instance for use in tests. + /// + protected readonly ITestingSteamInstallation Steam; + + /// + /// Initializes a new instance of the SteamTestBase class for use in derived test classes. + /// + /// + /// This protected constructor is intended to be called by subclasses to set up the Steam testing + /// environment. It initializes the Steam property using the provided service provider. + /// + protected SteamTestBase() + { + Steam = SteamTesting.Steam(ServiceProvider); + } + + /// + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + SteamAbstractionLayer.InitializeServices(serviceCollection); + } + + /// + public virtual void Dispose() + { + Steam.Dispose(); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestProcessHelper.cs b/test/AET.SteamAbstraction.Testing/TestProcessHelper.cs index 7773e9cf..1123462d 100644 --- a/test/AET.SteamAbstraction.Testing/TestProcessHelper.cs +++ b/test/AET.SteamAbstraction.Testing/TestProcessHelper.cs @@ -1,41 +1,88 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.SteamAbstraction.Utilities; +using Microsoft.Extensions.DependencyInjection; +using System; using System.Diagnostics; using System.IO.Abstractions; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading.Tasks; -using AET.SteamAbstraction.Registry; -using AET.SteamAbstraction.Testing.Installation; -using AET.SteamAbstraction.Utilities; -using Microsoft.Extensions.DependencyInjection; using Xunit; namespace AET.SteamAbstraction.Testing; -public class TestProcessHelper(IServiceProvider sp) : IProcessHelper +/// +/// Provides a test for managing and simulating process-related operations. +/// +public sealed class TestProcessHelper : IProcessHelper { - private readonly ISteamRegistryFactory _registryFactory = sp.GetRequiredService(); - private readonly IFileSystem _fileSystem = sp.GetRequiredService(); + private readonly IFileSystem _fileSystem; + private readonly ITestingSteamRegistry _registry; private int? _pid; + /// + /// Initializes a new instance of the class using the specified service provider. + /// + /// The service provider to use. + public TestProcessHelper(IServiceProvider serviceProvider) + { + _fileSystem = serviceProvider.GetRequiredService(); + _registry = SteamTesting.SteamRegistry(serviceProvider); + } + + + /// + /// Gets the actual process linked to this . + /// public Process? CurrentProcess { get; private set; } + /// + /// Gets or sets a value indicating whether the process start should be delayed when is called. + /// public bool DelayStart { get; set; } + /// + /// Sets the running process identifier. + /// + /// + /// This method can be used to simulate a running process with the specified PID without actually starting a real process using . + /// + /// The PID to use. Use to indicate no process is running. public void SetRunningPid(int? pid) { _pid = pid; } + /// + /// Checks whether the specified process identifier is the same as the process identifier linked to this . + /// + /// + /// The process identifier of this is either set by using or . + /// + /// + /// + /// if a process with the specified PID is running; otherwise, . + /// public bool IsProcessRunning(int pid) { return pid == _pid; } + /// + /// Starts a new process using the specified configuration. + /// + /// The object that specifies the configuration for the process to be started. + /// A object that represents the started process, or if the process could not be started. + /// Thrown if is . + /// Thrown if no file name is specified in . + /// Thrown if an error occurs when opening the associated file. + [SupportedOSPlatform("windows")] public Process StartProcess(ProcessStartInfo startInfo) { - var registry = _registryFactory.CreateRegistry(); - var expectedFileName = registry.ExecutableFile?.FullName; + var expectedFileName = _registry.ExecutableFile?.FullName; Assert.Equal(expectedFileName, _fileSystem.Path.GetFullPath(startInfo.FileName)); var processName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "cmd.exe" : "/bin/bash"; @@ -47,20 +94,24 @@ public Process StartProcess(ProcessStartInfo startInfo) var pid = p.Id; SetRunningPid(pid); - registry.SetPid(pid); + _registry.SetPid(pid); CurrentProcess = p; return p; } - internal void KillCurrent() + /// + /// Terminates the current process linked to this , if any and sets the PID to . + /// + [SupportedOSPlatform("windows")] + public void KillCurrent() { try { CurrentProcess?.Kill(); CurrentProcess = null; SetRunningPid(null); - _registryFactory.CreateRegistry().SetPid(null); + _registry.SetPid(null); } catch { diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamConstants.cs b/test/AET.SteamAbstraction.Testing/TestingSteamConstants.cs new file mode 100644 index 00000000..fc967ccd --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamConstants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +namespace AET.SteamAbstraction.Testing; + +/// +/// Provides constant values for Steam installation paths used in testing scenarios. +/// +public static class TestingSteamConstants +{ + // Ensure starts on path 'steam'. See GameInstallation.cs + /// + /// The root directory name for testing Steam installations. + /// + public const string SteamInstallPath = "steam"; + + /// + /// The path to the testing Steam executable. + /// + public const string SteamExePath = "steam/steam.exe"; +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Library.cs b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.Library.cs similarity index 54% rename from test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Library.cs rename to test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.Library.cs index d37253ba..847bf5ab 100644 --- a/test/AET.SteamAbstraction.Testing/Installation/SteamInstallation.Library.cs +++ b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.Library.cs @@ -1,51 +1,43 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; using System.Collections.Generic; using System.IO.Abstractions; using System.Linq; using System.Runtime.InteropServices; using System.Text; -using AET.SteamAbstraction.Library; using AnakinRaW.CommonUtilities.FileSystem; -using PG.TestingUtilities; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Xunit; -namespace AET.SteamAbstraction.Testing.Installation; +namespace AET.SteamAbstraction.Testing; -internal static partial class SteamInstallation +internal sealed partial class TestingSteamInstallationImpl { - public static ISteamLibrary InstallDefaultLibrary(this IFileSystem fs, IServiceProvider serviceProvider, bool addToConfig = true) + public ITestingSteamLibrary InstallDefaultLibrary(bool addToConfig = true) { - var steamPath = fs.Path.GetFullPath(SteamInstallPath); - return InstallSteamLibrary(fs, steamPath, true, serviceProvider, addToConfig); - + var steamPath = _fileSystem.Path.GetFullPath(TestingSteamConstants.SteamInstallPath); + return InstallSteamLibrary(steamPath, true, addToConfig); } - public static ISteamLibrary InstallSteamLibrary( - this IFileSystem fs, - string path, - IServiceProvider serviceProvider, - bool addToConfig = true) + public ITestingSteamLibrary InstallLibrary(string path, bool addToConfig = true) { - return InstallSteamLibrary(fs, path, false, serviceProvider, addToConfig); + return InstallSteamLibrary(path, false, addToConfig); } - private static ISteamLibrary InstallSteamLibrary( - this IFileSystem fs, - string path, - bool isDefault, - IServiceProvider serviceProvider, - bool addToConfig = true) + private ITestingSteamLibrary InstallSteamLibrary(string path, bool isDefault, bool addToConfig = true) { - var commonPath = fs.Path.Combine(path, "steamapps", "common"); - var workshopPath = fs.Path.Combine(path, "steamapps", "workshop"); + var commonPath = _fileSystem.Path.Combine(path, "steamapps", "common"); + var workshopPath = _fileSystem.Path.Combine(path, "steamapps", "workshop"); - fs.Directory.CreateDirectory(commonPath); - fs.Directory.CreateDirectory(workshopPath); + _fileSystem.Directory.CreateDirectory(commonPath); + _fileSystem.Directory.CreateDirectory(workshopPath); - var libDir = fs.DirectoryInfo.New(path); + var libDir = _fileSystem.DirectoryInfo.New(path); Assert.True(libDir.Exists); - var contentId = TestHelpers.RandomLong(); + var contentId = Random.Long(); var libraryVdf = $@"""libraryfolder"" {{ @@ -62,23 +54,23 @@ private static ISteamLibrary InstallSteamLibrary( libraryVdfSubPath = "steamapps"; } - fs.File.WriteAllText(fs.Path.Combine(libDir.FullName, libraryVdfSubPath, libraryVdfName), libraryVdf); + _fileSystem.File.WriteAllText(_fileSystem.Path.Combine(libDir.FullName, libraryVdfSubPath, libraryVdfName), libraryVdf); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - using var _ = fs.File.Create(fs.Path.Combine(libDir.FullName, "steam.dll")); + using var _ = _fileSystem.File.Create(_fileSystem.Path.Combine(libDir.FullName, "steam.dll")); } - var lib = new SteamLibrary(libDir, serviceProvider); + var lib = new TestingSteamLibrary(libDir, _serviceProvider); if (addToConfig) - AddToConfig(lib, fs); + AddToConfig(lib, _fileSystem); return lib; } - private static void AddToConfig(ISteamLibrary lib, IFileSystem fs) + private static void AddToConfig(TestingSteamLibrary lib, IFileSystem fs) { - var steamPath = fs.Path.GetFullPath(SteamInstallPath); + var steamPath = fs.Path.GetFullPath(TestingSteamConstants.SteamInstallPath); if (!fs.Directory.Exists(steamPath)) Assert.Fail("Steam not installed."); diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.User.cs b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.User.cs new file mode 100644 index 00000000..a2fdcdea --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.User.cs @@ -0,0 +1,77 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Linq; +using System.Text; + +namespace AET.SteamAbstraction.Testing; +internal sealed partial class TestingSteamInstallationImpl +{ + public void DeleteLoginUsersFile() + { + var configPath = + _fileSystem.Path.GetFullPath(_fileSystem.Path.Combine(TestingSteamConstants.SteamInstallPath, "config")); + var loginUsersPath = _fileSystem.Path.Combine(configPath, "loginusers.vdf"); + _fileSystem.File.Delete(loginUsersPath); + } + + public void WriteCorruptLoginUsers() + { + var configPath = + _fileSystem.Path.GetFullPath(_fileSystem.Path.Combine(TestingSteamConstants.SteamInstallPath, "config")); + var loginUsersPath = _fileSystem.Path.Combine(configPath, "loginusers.vdf"); + _fileSystem.File.WriteAllText(loginUsersPath, "\0"); + } + + public IFileInfo WriteLoginUsers(params IEnumerable? users) + { + var configPath = + _fileSystem.Path.GetFullPath(_fileSystem.Path.Combine(TestingSteamConstants.SteamInstallPath, "config")); + var loginUsersPath = _fileSystem.Path.Combine(configPath, "loginusers.vdf"); + + var content = $@" +""users"" +{{ + {SerializeUsers(users?.Select(x => new SteamUserLoginMetadata(x.UserId, x.MostRecent, x.UserWantsOffline)))} +}} +"; + _fileSystem.File.WriteAllText(loginUsersPath, content); + return _fileSystem.FileInfo.New(loginUsersPath); + } + + private static string SerializeUsers(IEnumerable? users) + { + var sb = new StringBuilder(); + + if (users is null) + return string.Empty; + + foreach (var metadata in users) + { + var content = $@" + ""{metadata.UserId}"" + {{ + ""AccountName"" ""someName"" + ""PersonaName"" ""some Name"" + ""RememberPassword"" ""1"" + ""WantsOfflineMode"" ""{BoolToNumber(metadata.UserWantsOffline)}"" + ""SkipOfflineModeWarning"" ""0"" + ""AllowAutoLogin"" ""1"" + ""MostRecent"" ""{BoolToNumber(metadata.MostRecent)}"" + ""Timestamp"" ""0000000000"" + }}"; + + sb.AppendLine(content); + } + + return sb.ToString(); + } + + + private static int BoolToNumber(bool value) + { + return value ? 1 : 0; + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.cs b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.cs new file mode 100644 index 00000000..d052c714 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamInstallationImpl.cs @@ -0,0 +1,47 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO.Abstractions; +using System.Runtime.Versioning; + +namespace AET.SteamAbstraction.Testing; + +internal sealed partial class TestingSteamInstallationImpl(IServiceProvider serviceProvider) : ITestingSteamInstallation +{ + private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); + private readonly IServiceProvider _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + + public IDirectoryInfo? InstallationDirectory => Registry.InstallationDirectory; + + public ITestingSteamRegistry Registry { get; } = SteamTesting.SteamRegistry(serviceProvider); + + [SupportedOSPlatform("windows")] + public void Install() + { + Registry.InstallSteam(); + InstallSteamFilesOnly(); + } + + public void InstallSteamFilesOnly() + { + var configPath = _fileSystem.Path.GetFullPath(_fileSystem.Path.Combine(TestingSteamConstants.SteamInstallPath, "config")); + var exePath = _fileSystem.Path.GetFullPath(TestingSteamConstants.SteamExePath); + + _fileSystem.Directory.CreateDirectory(configPath); + using var _ = _fileSystem.File.Create(exePath); + } + + [SupportedOSPlatform("windows")] + public ISteamFakeProcess FakeStart(int pid) + { + Registry.SetPid(pid); + return new SteamFakeProcessImpl(_serviceProvider, pid); + } + + public void Dispose() + { + Registry.Dispose(); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamLibrary.cs b/test/AET.SteamAbstraction.Testing/TestingSteamLibrary.cs new file mode 100644 index 00000000..b5443b18 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamLibrary.cs @@ -0,0 +1,102 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Text; +using AET.SteamAbstraction.Games; +using AET.SteamAbstraction.Library; +using Xunit; + +namespace AET.SteamAbstraction.Testing; + +internal sealed class TestingSteamLibrary(IDirectoryInfo libraryLocation, IServiceProvider serviceProvider) + : SteamLibrary(libraryLocation, serviceProvider), ITestingSteamLibrary +{ + public SteamAppManifest InstallGame(uint id, string gameName, string appManifestName) + { + return InstallGameCore(id, appManifestName, gameName, [id + 1]); + } + + public SteamAppManifest InstallGame( + uint id, + string gameName, + uint numberDepots = 1, + SteamAppState appState = SteamAppState.StateFullyInstalled) + { + var manifestFileName = $"appmanifest_{id}.acf"; + var depots = new List(); + for (uint i = 1; i < numberDepots + 1; i++) + depots.Add(i); + return InstallGameCore(id, manifestFileName, gameName, depots, appState); + } + + public SteamAppManifest InstallGame( + uint id, + string gameName, + IList depots, + SteamAppState appState = SteamAppState.StateFullyInstalled) + { + var manifestFileName = $"appmanifest_{id}.acf"; + return InstallGameCore(id, manifestFileName, gameName, depots, appState); + } + + public void InstallCorruptApp() + { + var randomAcfName = FileSystem.Path.GetRandomFileName() + ".acf"; + SteamAppsLocation.Create(); + + FileSystem.File.WriteAllText(FileSystem.Path.Combine(SteamAppsLocation.FullName, randomAcfName), "\0"); + } + + private SteamAppManifest InstallGameCore( + uint id, + string appManifestName, + string gameName, + IList depots, + SteamAppState appState = SteamAppState.StateFullyInstalled) + { + var depotSb = new StringBuilder(); + foreach (var depot in depots) + { + depotSb.Append($@" + ""{depot}"" + {{ + }} +"); + } + + var manifestContent = $@" +""AppState"" +{{ + ""appid"" ""{id}"" + ""name"" ""{gameName}"" + ""StateFlags"" ""{(int)appState}"" + ""installdir"" ""{gameName}"" + ""InstalledDepots"" + {{ + {depotSb} + }} + ""someProperty"" ""someValue"" +}} +"; + + var manifestFilePath = FileSystem.Path.Combine(SteamAppsLocation.FullName, appManifestName); + FileSystem.File.WriteAllText(manifestFilePath, manifestContent); + + Assert.True(FileSystem.File.Exists(manifestFilePath)); + + var gamePath = FileSystem.Path.Combine(CommonLocation.FullName, gameName); + var gameDir = FileSystem.Directory.CreateDirectory(gamePath); + + return new SteamAppManifest( + this, + FileSystem.FileInfo.New(manifestFilePath), + id, + gameName, + gameDir, + SteamAppState.StateFullyInstalled, + new HashSet()); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamRegistryImpl.cs b/test/AET.SteamAbstraction.Testing/TestingSteamRegistryImpl.cs new file mode 100644 index 00000000..8adfbf16 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamRegistryImpl.cs @@ -0,0 +1,87 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.IO.Abstractions; +using AET.SteamAbstraction.Registry; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace AET.SteamAbstraction.Testing; + +internal class TestingSteamRegistryImpl(IServiceProvider serviceProvider) : ITestingSteamRegistry +{ + private readonly ISteamRegistry _registry = serviceProvider.GetRequiredService().CreateRegistry(); + private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); + + public IFileInfo? ExecutableFile => _registry.ExecutableFile; + public IDirectoryInfo? InstallationDirectory => _registry.InstallationDirectory; + public int? ProcessId => _registry.ProcessId; + + public void InstallSteam() + { + if (_registry is WindowsSteamRegistry) + InstallWindowsRegistry(); + else if (_registry is LinuxSteamRegistry) + InstallLinuxRegistry(); + } + + + public void SetPid(int? pid) + { + if (_registry is WindowsSteamRegistry) + SetPidWindowsRegistry(pid); + else if (_registry is LinuxSteamRegistry) + SetPidLinuxRegistry(pid); + } + + public void SetUserId(uint userId) + { + if (_registry is WindowsSteamRegistry) + SetUserIdWindowsRegistry(userId); + // Does not exist for Linux + } + + private void InstallWindowsRegistry() + { + using var key = _registry.OpenSteamRegistryKey(); + Assert.NotNull(key); + key.SetValue("SteamExe", _fileSystem.Path.GetFullPath(TestingSteamConstants.SteamExePath)); + key.SetValue("SteamPath", _fileSystem.Path.GetFullPath(TestingSteamConstants.SteamInstallPath)); + } + + private void SetPidWindowsRegistry(int? pid) + { + if (pid is null) + return; + using var key = _registry.OpenSteamRegistryKey(); + Assert.NotNull(key); + using var activeProcessKey = key.CreateSubKey("ActiveProcess"); + + activeProcessKey!.SetValue("pid", pid); + } + + private void SetUserIdWindowsRegistry(uint userId) + { + using var key = _registry.OpenSteamRegistryKey(); + Assert.NotNull(key); + using var activeProcessKey = key.CreateSubKey("ActiveProcess"); + + activeProcessKey!.SetValue("ActiveUser", userId); + } + + private void InstallLinuxRegistry() + { + throw new NotImplementedException("Linux is currently not supported"); + } + + private void SetPidLinuxRegistry(int? pid) + { + throw new NotImplementedException("Linux is currently not supported"); + } + + public void Dispose() + { + _registry.Dispose(); + } +} \ No newline at end of file diff --git a/test/AET.SteamAbstraction.Testing/TestingSteamUserLoginMetadata.cs b/test/AET.SteamAbstraction.Testing/TestingSteamUserLoginMetadata.cs new file mode 100644 index 00000000..417a5ea3 --- /dev/null +++ b/test/AET.SteamAbstraction.Testing/TestingSteamUserLoginMetadata.cs @@ -0,0 +1,38 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +namespace AET.SteamAbstraction.Testing; + +/// +/// Represent metadata about a Steam user login. +/// +public sealed class TestingSteamUserLoginMetadata +{ + /// + /// Gets or sets the ID of the login user. + /// + public ulong UserId { get; init; } + + /// + /// Gets or sets a value indicating whether the user wants to use Steam in offline mode. + /// + public bool UserWantsOffline { get; init; } + + /// + /// Gets or sets a value indicating whether this login is the most recent one. + /// + public bool MostRecent { get; init; } + + /// + /// Initializes a new instance of the class. + /// + /// The user id. + /// The information whether this user represents the most recent login. + /// The information whether this user wants to stay offline. + public TestingSteamUserLoginMetadata(ulong userId, bool mostRecent = false, bool userWantsOffline = false) + { + UserId = userId; + MostRecent = mostRecent; + UserWantsOffline = userWantsOffline; + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/CompilerHelpers/Attributes.cs b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/CompilerHelpers/Attributes.cs new file mode 100644 index 00000000..e1dc9a46 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/CompilerHelpers/Attributes.cs @@ -0,0 +1,45 @@ +#if !NET5_0_OR_GREATER +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +namespace System.Runtime.Versioning; + +/// +/// Base type for all platform-specific API attributes. +/// + +internal abstract class OSPlatformAttribute(string platformName) : Attribute +{ + public string PlatformName { get; } = platformName; +} + +/// +/// Records the platform that the project targeted. +/// +[AttributeUsage(AttributeTargets.Assembly)] +internal sealed class TargetPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); + +/// +/// Records the operating system (and minimum version) that supports an API. Multiple attributes can be +/// applied to indicate support on multiple operating systems. +/// +/// +/// Callers can apply a +/// or use guards to prevent calls to APIs on unsupported operating systems. +/// +/// A given platform should only be specified once. +/// +[AttributeUsage(AttributeTargets.Assembly | + AttributeTargets.Class | + AttributeTargets.Constructor | + AttributeTargets.Enum | + AttributeTargets.Event | + AttributeTargets.Field | + AttributeTargets.Interface | + AttributeTargets.Method | + AttributeTargets.Module | + AttributeTargets.Property | + AttributeTargets.Struct, + AllowMultiple = true, Inherited = false)] +internal sealed class SupportedOSPlatformAttribute(string platformName) : OSPlatformAttribute(platformName); +// ReSharper restore InconsistentNaming +#endif \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/IGameClientFactoryTest.cs b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/IGameClientFactoryTest.cs index 5784774d..ff496fb3 100644 --- a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/IGameClientFactoryTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/IGameClientFactoryTest.cs @@ -4,30 +4,30 @@ using AnakinRaW.CommonUtilities.Registry; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; +using PG.StarWarsGame.Infrastructure.Testing; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; namespace PG.StarWarsGame.Infrastructure.Clients.Steam.Test; -public class IGameClientFactoryTest : CommonTestBase +public class IGameClientFactoryTest : GameInfrastructureTestBase { private readonly IRegistry _registry = new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike); - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(_registry); - SteamAbstractionLayer.InitializeServices(sc); - PetroglyphGameInfrastructure.InitializeServices(sc); - SteamPetroglyphStarWarsGameClients.InitializeServices(sc); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_registry); + SteamAbstractionLayer.InitializeServices(serviceCollection); + PetroglyphGameInfrastructure.InitializeServices(serviceCollection); + SteamPetroglyphStarWarsGameClients.InitializeServices(serviceCollection); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateClient_CreatesCorrectClientType(GameIdentity identity) { - var game = FileSystem.InstallGame(identity, ServiceProvider); + var game = GetOrCreateGameInstallation(identity).Game; var factory = ServiceProvider.GetRequiredService(); var client = factory.CreateClient(game); diff --git a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test.csproj b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test.csproj index 9a243dfd..a12919b3 100644 --- a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test.csproj +++ b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test.csproj @@ -1,4 +1,4 @@ - + PG.StarWarsGame.Infrastructure.Clients.Steam.Test @@ -9,18 +9,15 @@ $(TargetFrameworks);net481 false true + Exe - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameClientTest.cs b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameClientTest.cs index db607eb8..d00b01b1 100644 --- a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameClientTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameClientTest.cs @@ -1,11 +1,7 @@ #if Windows // TODO: Enable for linux -using System; -using System.Collections.Generic; using AET.SteamAbstraction; -using AET.SteamAbstraction.Registry; using AET.SteamAbstraction.Testing; -using AET.SteamAbstraction.Testing.Installation; using AET.SteamAbstraction.Utilities; using AnakinRaW.CommonUtilities.Registry; using Microsoft.Extensions.DependencyInjection; @@ -13,57 +9,68 @@ using PG.StarWarsGame.Infrastructure.Clients.Processes; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Test.Clients; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; +using PG.StarWarsGame.Infrastructure.Testing; +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Xunit; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; namespace PG.StarWarsGame.Infrastructure.Clients.Steam.Test; +[SupportedOSPlatform("windows")] public class SteamPetroglyphStarWarsGameClientTest : PetroglyphStarWarsGameClientTest { private readonly IRegistry _registry = new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike); - private readonly PetroglyphStarWarsGame _game; - private TestProcessHelper? _processHelper; + + private ISteamFakeProcess? _steamProcess; + private ITestingGameInstallation? _gameInstallation; protected override ICollection SupportedPlatforms { get; } = [GamePlatform.SteamGold]; - protected override void BeforePlay() + protected override ITestingGameInstallation GetOrCreateGameInstallation(IGameIdentity? identity = null) { - // Install Steam (regardless whether the identity is supported) - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - FileSystem.InstallSteam(registry); - FakeStartSteam(12345); - base.BeforePlay(); + if (_gameInstallation is not null) + return _gameInstallation; + var type = identity?.Type ?? Random.Enum(); + var steamIdentity = new GameIdentity(type, GamePlatform.SteamGold); + return _gameInstallation = GameInfrastructureTesting.Game(steamIdentity, ServiceProvider); } - public SteamPetroglyphStarWarsGameClientTest() + protected override void BeforePlay() { - _game = FileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.SteamGold), ServiceProvider); + // Install Steam (regardless whether the identity is supported) + var steam = SteamTesting.Steam(ServiceProvider); + steam.Install(); + _steamProcess = steam.FakeStart(12345); + base.BeforePlay(); } - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - sc.AddSingleton(_registry); - base.SetupServiceProvider(sc); - SteamAbstractionLayer.InitializeServices(sc); - SteamPetroglyphStarWarsGameClients.InitializeServices(sc); - - sc.AddSingleton(sp => - { - return _processHelper = new TestProcessHelper(sp); - }); + serviceCollection.AddSingleton(_registry); + base.SetupServices(serviceCollection); + SteamAbstractionLayer.InitializeServices(serviceCollection); + SteamPetroglyphStarWarsGameClients.InitializeServices(serviceCollection); + + serviceCollection.AddSingleton(sp => new TestProcessHelper(sp)); + serviceCollection.AddSingleton(sp => sp.GetRequiredService()); + } [Fact] public void Ctor_SteamClient_NullArgs_Throws() { Assert.Throws(() => new SteamPetroglyphStarWarsGameClient(null!, ServiceProvider)); - Assert.Throws(() => new SteamPetroglyphStarWarsGameClient(_game, null!)); + Assert.Throws(() => new SteamPetroglyphStarWarsGameClient(GetOrCreateGameInstallation().Game, null!)); } [Fact] public void SteamPetroglyphStarWarsGameClient_Lifecycle() { - var client = new SteamPetroglyphStarWarsGameClient(_game, ServiceProvider); + var client = new SteamPetroglyphStarWarsGameClient(GetOrCreateGameInstallation().Game, ServiceProvider); Assert.NotNull(client.SteamWrapper); client.Dispose(); @@ -72,50 +79,43 @@ public void SteamPetroglyphStarWarsGameClient_Lifecycle() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Ctor_NonSteamGameThrows(GameIdentity identity) { if (identity.Platform is GamePlatform.SteamGold) return; - var game = FileSystem.InstallGame(identity, ServiceProvider); - Assert.Throws(() => new SteamPetroglyphStarWarsGameClient(game, ServiceProvider)); + var otherGame = GameInfrastructureTesting.Game(identity, ServiceProvider).Game; + Assert.Throws(() => new SteamPetroglyphStarWarsGameClient(otherGame, ServiceProvider)); } [Fact] public void Play_SteamNotInstalled_Throws() { - var client = new SteamPetroglyphStarWarsGameClient(_game, ServiceProvider); + var game = GetOrCreateGameInstallation().Game; + var client = new SteamPetroglyphStarWarsGameClient(game, ServiceProvider); Assert.Throws(client.Play); - var expected = new GameProcessInfo(_game, GameBuildType.Release, ArgumentCollection.Empty); + var expected = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); - TestPlay(_game, expected, gameClient => gameClient.Play(), shallThrowGameStartException: true); + TestPlay(game, expected, gameClient => gameClient.Play(), shallThrowGameStartException: true); } [Fact] public void Play_SteamNotRunning_Throws() { // Install Steam (regardless whether the identity is supported) - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - FileSystem.InstallSteam(registry); + SteamTesting.Steam(ServiceProvider).Install(); - var expected = new GameProcessInfo(_game, GameBuildType.Release, ArgumentCollection.Empty); + var game = GetOrCreateGameInstallation().Game; + var expected = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); - TestPlay(_game, expected, gameClient => gameClient.Play(), shallThrowGameStartException: true); - } - - - private void FakeStartSteam(int pid) - { - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - registry.SetPid(pid); - _processHelper!.SetRunningPid(pid); + TestPlay(game, expected, gameClient => gameClient.Play(), shallThrowGameStartException: true); } public override void Dispose() { base.Dispose(); - _processHelper?.KillCurrent(); + _steamProcess?.Kill(); } } diff --git a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameDetectorTest.cs b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameDetectorTest.cs index f11848f5..3b4230e4 100644 --- a/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameDetectorTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Clients.Steam.Test/SteamPetroglyphStarWarsGameDetectorTest.cs @@ -2,24 +2,24 @@ using System; using System.Collections.Generic; +using System.Runtime.Versioning; using AET.SteamAbstraction; using AET.SteamAbstraction.Games; -using AET.SteamAbstraction.Registry; -using AET.SteamAbstraction.Testing.Installation; +using AET.SteamAbstraction.Testing; using AnakinRaW.CommonUtilities.Registry; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Game.Registry; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Clients.Steam.Test; -public class SteamPetroglyphStarWarsGameDetectorTest : GameDetectorTestBase +[SupportedOSPlatform("windows")] +public class SteamPetroglyphStarWarsGameDetectorTest : GameDetectorTestBase { private readonly IRegistry _registry = new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike); @@ -27,44 +27,43 @@ public class SteamPetroglyphStarWarsGameDetectorTest : GameDetectorTestBase SupportedPlatforms => [GamePlatform.SteamGold]; protected override bool CanDisableInitRequest => false; - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(_registry); - SteamAbstractionLayer.InitializeServices(sc); - PetroglyphGameInfrastructure.InitializeServices(sc); - SteamPetroglyphStarWarsGameClients.InitializeServices(sc); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_registry); + SteamAbstractionLayer.InitializeServices(serviceCollection); + SteamPetroglyphStarWarsGameClients.InitializeServices(serviceCollection); } - protected override IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization) + protected override IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization) { return new SteamPetroglyphStarWarsGameDetector(ServiceProvider); } - protected override GameDetectorTestInfo SetupGame(GameIdentity gameIdentity) + protected override GameDetectorTestInfo SetupGame(GameIdentity gameIdentity) { return SetupGame(gameIdentity, (game, otherGameType) => { - TestGameRegistrySetupData.Installed(game.Type, game.Directory).Create(ServiceProvider); - otherGameType.CreateNonExistingRegistry(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateInstalled(game); + GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(otherGameType); }); } - protected override GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity) + protected override GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity) { return SetupGame(gameIdentity, (game, otherGameType) => { - TestGameRegistrySetupData.Uninitialized(game.Type).Create(ServiceProvider); - otherGameType.CreateNonExistingRegistry(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(TestGameRegistrySetupData.Uninitialized(game.Type)); + GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(otherGameType); }); } - protected override void HandleInitialization(bool shallInitSuccessfully, GameDetectorTestInfo info) + protected override void HandleInitialization(bool shallInitSuccessfully, GameDetectorTestInfo info) { if (!shallInitSuccessfully) return; var registrySetupData = TestGameRegistrySetupData.Installed(info.GameType, info.GameDirectory!); - registrySetupData.Create(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(registrySetupData); } [Fact] @@ -81,7 +80,7 @@ public void Detect_SteamNotInstalled_ShouldReturnNotInstalled(GameType gameType) var gameId = new GameIdentity(gameType, GamePlatform.SteamGold); var expected = GameDetectionResult.NotInstalled(gameId.Type); - FileSystem.InstallGame(gameId, ServiceProvider); + GetOrCreateGameInstallation(gameId); var detector = new SteamPetroglyphStarWarsGameDetector(ServiceProvider); var result = detector.Detect(gameType, GamePlatform.SteamGold); @@ -97,7 +96,7 @@ public void Detect_SteamInstalledButGameNotRegisteredToSteam_ShouldReturnNotInst var gameId = new GameIdentity(gameType, GamePlatform.SteamGold); var expected = GameDetectionResult.NotInstalled(gameId.Type); - FileSystem.InstallGame(gameId, ServiceProvider); + GetOrCreateGameInstallation(gameId); var detector = new SteamPetroglyphStarWarsGameDetector(ServiceProvider); var result = detector.Detect(gameType, GamePlatform.SteamGold); @@ -115,8 +114,8 @@ public void Detect_SteamInstalledButGameNotFullyInstalled_ShouldReturnNotInstall var info = SetupGame(gameId, (game, otherGameType) => { - TestGameRegistrySetupData.Installed(game.Type, game.Directory).Create(ServiceProvider); - otherGameType.CreateNonExistingRegistry(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateInstalled(game); + GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(otherGameType); }, SteamAppState.StateUpdateRequired); var detector = CreateDetector(info, true); @@ -125,31 +124,30 @@ public void Detect_SteamInstalledButGameNotFullyInstalled_ShouldReturnNotInstall expected.AssertEqual(result); } - private GameDetectorTestInfo SetupGame( + private GameDetectorTestInfo SetupGame( GameIdentity gameIdentity, Action registrySetup, SteamAppState appState = SteamAppState.StateFullyInstalled) { // Install Steam (regardless whether the identity is supported) - var registry = ServiceProvider.GetRequiredService().CreateRegistry(); - FileSystem.InstallSteam(registry); + var steam = SteamTesting.Steam(ServiceProvider); + steam.Install(); if (gameIdentity.Platform != GamePlatform.SteamGold) - return new GameDetectorTestInfo(gameIdentity.Type, null, default); + return new GameDetectorTestInfo(gameIdentity.Type, null, null); // Install Game - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; // Register Game to Steam - var lib = FileSystem.InstallDefaultLibrary(ServiceProvider); + var lib = steam.InstallDefaultLibrary(); IList depots = gameIdentity.Type == GameType.Foc ? [32472] : []; lib.InstallGame(32470, "Star Wars Empire at War", depots, appState); // To Registry - var otherGameType = gameIdentity.Type == GameType.Eaw ? GameType.Foc : GameType.Eaw; - registrySetup(game, otherGameType); + registrySetup(game, gameIdentity.Type.Opposite()); - return new GameDetectorTestInfo(gameIdentity.Type, game.Directory, default); + return new GameDetectorTestInfo(gameIdentity.Type, game.Directory, null); } } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentCollectionTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentCollectionTest.cs index d4f651d3..9e73128c 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentCollectionTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentCollectionTest.cs @@ -13,7 +13,9 @@ public void TestEmpty() { var empty = ArgumentCollection.Empty; Assert.Empty(empty); +#pragma warning disable xUnit2013 Assert.Equal(0, empty.Count); +#pragma warning restore xUnit2013 } [Fact] @@ -24,7 +26,9 @@ public void TestImmutable() args.Add(new MapArgument("Map")); +#pragma warning disable xUnit2013 Assert.Equal(1, argList.Count); +#pragma warning restore xUnit2013 var a = Assert.Single(argList); var e = ((IEnumerable)argList).GetEnumerator(); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentValueSerializerTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentValueSerializerTest.cs index 00a07e7e..cc296db5 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentValueSerializerTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/ArgumentValueSerializerTest.cs @@ -1,7 +1,7 @@ using System; +using AnakinRaW.CommonUtilities.Testing.Attributes; using PG.StarWarsGame.Infrastructure.Clients.Arguments.CommandLine; using PG.StarWarsGame.Infrastructure.Clients.Arguments.GameArguments; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/FlagArgumentTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/FlagArgumentTest.cs index f78e7858..626b2265 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/FlagArgumentTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/FlagArgumentTest.cs @@ -1,6 +1,6 @@ using System; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Clients.Arguments; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Arguments; @@ -10,18 +10,18 @@ public class FlagArgumentTest [Fact] public void Ctor_InvalidArgs_Throws() { - Assert.Throws(() => new TestFlagArg(null!, TestHelpers.RandomBool(), TestHelpers.RandomBool())); - Assert.Throws(() => new TestFlagArg(string.Empty, TestHelpers.RandomBool(), TestHelpers.RandomBool())); + Assert.Throws(() => new TestFlagArg(null!, Random.Bool(), Random.Bool())); + Assert.Throws(() => new TestFlagArg(string.Empty, Random.Bool(), Random.Bool())); } [Fact] public void Ctor_SetProperty() { - var name = TestHelpers.GetRandom(GameArgumentNames.AllInternalSupportedArgumentNames); - var isDebug = TestHelpers.RandomBool(); - var value = TestHelpers.RandomBool(); + var name = Random.Item(GameArgumentNames.AllInternalSupportedArgumentNames); + var isDebug = Random.Bool(); + var value = Random.Bool(); - var a = new TestFlagArg(name, value, TestHelpers.RandomBool(), isDebug); + var a = new TestFlagArg(name, value, Random.Bool(), isDebug); Assert.Equal(name, a.Name); Assert.Equal(value, a.Value); Assert.Equal(value, ((GameArgument)a).Value); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTest.cs index c90e2e04..fdd98db2 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTest.cs @@ -1,5 +1,6 @@ -using PG.StarWarsGame.Infrastructure.Clients.Arguments; -using PG.TestingUtilities; +using System; +using AnakinRaW.CommonUtilities.Testing.Extensions; +using PG.StarWarsGame.Infrastructure.Clients.Arguments; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Arguments; @@ -52,7 +53,7 @@ public void IsValid_ArgumentNotValid(GameArgument arg, ArgumentValidityStatus ex } public class ValidatingTestArgument(bool isValueValid, string value) - : GameArgument(TestHelpers.GetRandom(GameArgumentNames.AllInternalSupportedArgumentNames), value) + : GameArgument(Random.Item(GameArgumentNames.AllInternalSupportedArgumentNames), value) { private protected override bool IsDataValid() { diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestBase.cs index 25458c52..3f896070 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestBase.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestBase.cs @@ -1,12 +1,13 @@ -using System.Collections.Generic; -using System.IO.Abstractions; -using System.Linq; -using System.Runtime.InteropServices; -using AET.Modinfo.Model; +using AET.Modinfo.Model; using AET.Modinfo.Spec; using PG.StarWarsGame.Infrastructure.Clients.Arguments; using PG.StarWarsGame.Infrastructure.Clients.Arguments.GameArguments; -using PG.TestingUtilities; +using System; +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Linq; +using System.Runtime.InteropServices; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Testably.Abstractions.Testing; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Arguments; @@ -198,22 +199,22 @@ public static IEnumerable GetValidArguments() yield return [new LanguageArgument(new LanguageInfo("en", LanguageSupportLevel.Default))]; yield return [new LanguageArgument(new LanguageInfo("de", LanguageSupportLevel.SFX))]; - yield return [new LocalPortArgument(TestHelpers.RandomUInt())]; - yield return [new MonitorArgument(TestHelpers.RandomUInt())]; - yield return [new ScreenWidthArgument(TestHelpers.RandomUInt())]; - yield return [new ScreenHeightArgument(TestHelpers.RandomUInt())]; - yield return [new FPSCapArgument(TestHelpers.RandomUInt())]; - yield return [new RandomSeedArgument(TestHelpers.RandomUInt())]; - yield return [new ProfileArgument(TestHelpers.RandomUInt())]; - yield return [new BCast2Argument(TestHelpers.RandomUInt())]; - yield return [new BCast3Argument(TestHelpers.RandomUInt())]; - yield return [new BCast4Argument(TestHelpers.RandomUInt())]; - yield return [new AILogStyleArgument(TestHelpers.GetRandomEnum())]; - yield return [new SyncLogFilterArgument(TestHelpers.RandomUShort())]; - yield return [new ConnectPortArgument(TestHelpers.RandomUInt())]; - foreach (var nonPathArg in GetNonPathKeyValueArgs(TestHelpers.GetRandom(GetValidStringValues))) + yield return [new LocalPortArgument(Random.UInt())]; + yield return [new MonitorArgument(Random.UInt())]; + yield return [new ScreenWidthArgument(Random.UInt())]; + yield return [new ScreenHeightArgument(Random.UInt())]; + yield return [new FPSCapArgument(Random.UInt())]; + yield return [new RandomSeedArgument(Random.UInt())]; + yield return [new ProfileArgument(Random.UInt())]; + yield return [new BCast2Argument(Random.UInt())]; + yield return [new BCast3Argument(Random.UInt())]; + yield return [new BCast4Argument(Random.UInt())]; + yield return [new AILogStyleArgument(Random.Enum())]; + yield return [new SyncLogFilterArgument(Random.UShort())]; + yield return [new ConnectPortArgument(Random.UInt())]; + foreach (var nonPathArg in GetNonPathKeyValueArgs(Random.Item(GetValidStringValues))) yield return [nonPathArg]; - foreach (var pathArg in GetPathKeyValueArgs(TestHelpers.GetRandom(GetValidStringValues), gameDir.FullName, fs)) + foreach (var pathArg in GetPathKeyValueArgs(Random.Item(GetValidStringValues), gameDir.FullName, fs)) yield return [pathArg]; // Mod @@ -225,8 +226,8 @@ public static IEnumerable GetValidArguments() yield return [ new ModArgumentList([ - new ModArgument(fs.DirectoryInfo.New(TestHelpers.GetRandom(GetValidStringValues)), gameDir, false), - new ModArgument(fs.DirectoryInfo.New(TestHelpers.GetRandom(GetValidStringValues)), gameDir, false), + new ModArgument(fs.DirectoryInfo.New(Random.Item(GetValidStringValues)), gameDir, false), + new ModArgument(fs.DirectoryInfo.New(Random.Item(GetValidStringValues)), gameDir, false), ]) ]; diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestClasses.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestClasses.cs index 10dbb8b4..4a3f0b81 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestClasses.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentTestClasses.cs @@ -1,6 +1,7 @@ using PG.StarWarsGame.Infrastructure.Clients.Arguments; using PG.StarWarsGame.Infrastructure.Clients.Arguments.CommandLine; -using PG.TestingUtilities; +using System; +using AnakinRaW.CommonUtilities.Testing.Extensions; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Arguments; @@ -12,7 +13,7 @@ public TestNamedArg(string name) : this(name, GameArgumentTestBase.ValidStringVa public static TestNamedArg FromValue(string value) { - var name = TestHelpers.GetRandom(GameArgumentNames.SupportedKeyValueArgumentNames); + var name = Random.Item(GameArgumentNames.SupportedKeyValueArgumentNames); return new TestNamedArg(name, value, false); } } @@ -21,7 +22,7 @@ public class TestFlagArg(string name, bool value, bool dashed = false, bool debu : FlagArgument(name, value, dashed, debug) { public TestFlagArg(bool value, bool dashed) : this( - TestHelpers.GetRandom(GameArgumentNames.SupportedFlagArgumentNames), value, dashed) + Random.Item(GameArgumentNames.SupportedFlagArgumentNames), value, dashed) { } @@ -31,7 +32,7 @@ public TestFlagArg(string name) : this(name, true) } public class LowerCaseNameArg() - : FlagArgument(TestHelpers.GetRandom(GameArgumentNames.AllInternalSupportedArgumentNames).ToLowerInvariant(), true); + : FlagArgument(Random.Item(GameArgumentNames.AllInternalSupportedArgumentNames).ToLowerInvariant(), true); [SerializeEnumValue] diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentsBuilderTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentsBuilderTest.cs index 1d800a96..d7e8a165 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentsBuilderTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/GameArgumentsBuilderTest.cs @@ -6,23 +6,39 @@ using PG.StarWarsGame.Infrastructure.Clients.Arguments.GameArguments; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Testably.Abstractions.Testing; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Arguments; -public class GameArgumentsBuilderTest : CommonTestBase +public sealed class GameArgumentsBuilderTest : GameInfrastructureTestBase { private readonly MockFileSystem _fileSystem = new(); private readonly GameArgumentsBuilder _builder = new(); private readonly IGame _game; + private readonly ITestingGameInstallation _gameInstallation; public GameArgumentsBuilderTest() { - _game = _fileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.SteamGold), ServiceProvider); + _gameInstallation = GetOrCreateGameInstallation(new GameIdentity(GameType.Foc, GamePlatform.SteamGold)); + _game = _gameInstallation.Game; + } + + private IPhysicalMod CreateMod(string name) + { + return _gameInstallation.InstallMod(name, false).Mod; + } + + private (IMod virtualMod, IPhysicalMod dep) CreateVirtualMod() + { + var dep = CreateMod("dep"); + var modinfo = new ModinfoData("VirtualMod") + { + Dependencies = new DependencyList([dep], DependencyResolveLayout.FullResolved) + }; + return (new VirtualMod(_game, modinfo.ToJson(), modinfo, ServiceProvider), dep); } [Fact] @@ -289,19 +305,4 @@ public void DisposedBuilder_Add_ThrowsObjectDisposedException() Assert.Throws(() => _builder.Remove(new WindowedArgument())); Assert.Throws(_builder.Build); } - - private IPhysicalMod CreateMod(string name) - { - return _game.InstallMod(name, false, ServiceProvider); - } - - private (IMod virtualMod, IPhysicalMod dep) CreateVirtualMod() - { - var dep = _game.InstallMod("dep", false, ServiceProvider); - var modinfo = new ModinfoData("VirtualMod") - { - Dependencies = new DependencyList([dep], DependencyResolveLayout.FullResolved) - }; - return (new VirtualMod(_game, modinfo.ToJson(), modinfo, ServiceProvider), dep); - } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/NamedArgumentTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/NamedArgumentTest.cs index 50a8ce29..1368ab0e 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/NamedArgumentTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Arguments/NamedArgumentTest.cs @@ -1,7 +1,7 @@ using System; using AnakinRaW.CommonUtilities.FileSystem.Normalization; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Clients.Arguments; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; @@ -21,8 +21,8 @@ public void Ctor_InvalidArgs_Throws() [Fact] public void Ctor_SetProperty() { - var name = TestHelpers.GetRandom(GameArgumentNames.AllInternalSupportedArgumentNames); - var isDebug = TestHelpers.RandomBool(); + var name = Random.Item(GameArgumentNames.AllInternalSupportedArgumentNames); + var isDebug = Random.Bool(); var a = new TestNamedArg(name, "value", isDebug); Assert.Equal(name, a.Name); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/GameClientFactoryTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/GameClientFactoryTest.cs index 1061f845..d08cae7a 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/GameClientFactoryTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/GameClientFactoryTest.cs @@ -6,12 +6,12 @@ namespace PG.StarWarsGame.Infrastructure.Test.Clients; -public class GameClientFactoryTest : CommonTestBase +public class GameClientFactoryTest : GameInfrastructureTestBase { - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - PetroglyphGameInfrastructure.InitializeServices(sc); + base.SetupServices(serviceCollection); + PetroglyphGameInfrastructure.InitializeServices(serviceCollection); } [Fact] @@ -25,7 +25,7 @@ public void CreateClient_NullArgs_Throws() public void CreateClient_CorrectTypeAndSetsProperty() { var factory = new GameClientFactory(ServiceProvider); - var game = CreateRandomGame(); + var game = GetOrCreateGameInstallation().Game; var client = factory.CreateClient(game); Assert.IsType(client); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/PetroglyphStarWarsGameClientTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/PetroglyphStarWarsGameClientTest.cs index 077a59f2..44697711 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/PetroglyphStarWarsGameClientTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/PetroglyphStarWarsGameClientTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Clients; using PG.StarWarsGame.Infrastructure.Clients.Arguments; @@ -11,58 +12,79 @@ using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Testing; using PG.StarWarsGame.Infrastructure.Testing.Clients; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients; -public class PetroglyphStarWarsGameClientTest : CommonTestBase, IDisposable +public class PetroglyphStarWarsGameClientTest : GameInfrastructureTestBase, IDisposable { private readonly IGameClientFactory _clientFactory; private readonly TestGameProcessLauncher _processLauncher = new(); + private ITestingGameInstallation? _gameInstallation; + protected virtual ICollection SupportedPlatforms => GITestUtilities.RealPlatforms; + public virtual void Dispose() + { + _processLauncher.Dispose(); + } + protected virtual void BeforePlay() { } + protected override ITestingGameInstallation GetOrCreateGameInstallation(IGameIdentity? identity = null) + { + if (_gameInstallation is not null) + return _gameInstallation; + + if (identity is not null) + { + if (!SupportedPlatforms.Contains(identity.Platform)) + throw new NotSupportedException($"The requested game platform '{identity.Platform}' is not supported by this client test"); + return _gameInstallation = GameInfrastructureTesting.Game(identity, ServiceProvider); + } + + var newIdentity = new GameIdentity(Random.Enum(), Random.Item(SupportedPlatforms)); + return _gameInstallation = GameInfrastructureTesting.Game(newIdentity, ServiceProvider); + } + public PetroglyphStarWarsGameClientTest() { _clientFactory = ServiceProvider.GetRequiredService(); } - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - PetroglyphGameInfrastructure.InitializeServices(sc); - sc.AddSingleton(_processLauncher); + base.SetupServices(serviceCollection); + PetroglyphGameInfrastructure.InitializeServices(serviceCollection); + TestGameProcessLauncher.RegisterAsService(serviceCollection, _processLauncher); } [Fact] public void Ctor_NullArgs_Throws() { Assert.Throws(() => new PetroglyphStarWarsGameClient(null!, ServiceProvider)); - var game = CreateRandomGame(); - Assert.Throws(() => new PetroglyphStarWarsGameClient(game, null!)); + Assert.Throws(() => new PetroglyphStarWarsGameClient(GetOrCreateGameInstallation().Game, null!)); } [Fact] public void Ctor_SetsGame() { - var game = CreateRandomGame(); + var game = GetOrCreateGameInstallation().Game; using var client = new PetroglyphStarWarsGameClient(game, ServiceProvider); Assert.Same(game, client.Game); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void IsDebugAvailable_NoDebugFilesAvailable(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - using var client = _clientFactory.CreateClient(game); + using var client = _clientFactory.CreateClient(GetOrCreateGameInstallation(gameIdentity).Game); Assert.False(client.IsDebugAvailable()); } @@ -71,16 +93,16 @@ public void IsDebugAvailable_NoDebugFilesAvailable(GameIdentity gameIdentity) [InlineData(GameType.Foc)] public void IsDebugAvailable_DebugFilesAvailable(GameType gameType) { - var game = FileSystem.InstallGame(new GameIdentity(gameType, GamePlatform.SteamGold), ServiceProvider); - game.InstallDebug(); - using var client = _clientFactory.CreateClient(game); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, GamePlatform.SteamGold)); + gameInstallation.InstallDebug(); + using var client = _clientFactory.CreateClient(gameInstallation.Game); Assert.True(client.IsDebugAvailable()); } [Fact] public void PlayDebug_NullArgs_Throws() { - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); + var game = GetOrCreateGameInstallation().Game; var client = _clientFactory.CreateClient(game); Assert.Throws(() => client.Play((IPhysicalMod)null!)); @@ -89,16 +111,17 @@ public void PlayDebug_NullArgs_Throws() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Play_CancelGameStart_Throws(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; if (gameIdentity.Platform == GamePlatform.SteamGold) - game.InstallDebug(); - var mod = game.InstallMod("MyMod", false, ServiceProvider); + gameInstallation.InstallDebug(); + var mod = gameInstallation.InstallMod("MyMod", false).Mod; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); @@ -123,16 +146,17 @@ void Cancel(GameStartingEventArgs args) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void PlayDebug_ProcessLauncherThrows(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; if (gameIdentity.Platform == GamePlatform.SteamGold) - game.InstallDebug(); - var mod = game.InstallMod("MyMod", false, ServiceProvider); + gameInstallation.InstallDebug(); + var mod = gameInstallation.InstallMod("MyMod", false).Mod; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); @@ -150,26 +174,26 @@ public void PlayDebug_ProcessLauncherThrows(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Play(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); TestPlay(game, expectedProcessInfo, client => client.Play()); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Play_Args(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var arg = new WindowedArgument(); @@ -178,14 +202,15 @@ public void Play_Args(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Play_Mod(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var mod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var mod = gameInstallation.InstallMod("MyMod").Mod; var expectedArguments = new ArgumentCollection([new ModArgumentList([ new ModArgument(mod.Directory, game.Directory, mod.Type == ModType.Workshops) @@ -199,8 +224,9 @@ public void Play_Mod(GameIdentity gameIdentity) [InlineData(GameType.Foc)] public void Debug_DebugIsAvailable(GameType gameType) { - var game = FileSystem.InstallGame(new GameIdentity(gameType, GamePlatform.SteamGold), ServiceProvider); - game.InstallDebug(); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, GamePlatform.SteamGold)); + gameInstallation.InstallDebug(); + var game = gameInstallation.Game; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Debug, ArgumentCollection.Empty); TestPlay( @@ -210,13 +236,13 @@ public void Debug_DebugIsAvailable(GameType gameType) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Debug_FallbackToRelease(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); TestPlay( @@ -226,13 +252,13 @@ public void Debug_FallbackToRelease(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Debug_DoNotFallbackToRelease_Throws(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); TestPlay( @@ -243,13 +269,13 @@ public void Debug_DoNotFallbackToRelease_Throws(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void PlayDebug_GameExecutablesNotAvailable_Throws(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var expectedProcessInfo = new GameProcessInfo(game, GameBuildType.Release, ArgumentCollection.Empty); @@ -269,13 +295,13 @@ public void PlayDebug_GameExecutablesNotAvailable_Throws(GameIdentity gameIdenti } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void PlayDebug_Derived_OnGameStarting_ThrowsCustom(GameIdentity gameIdentity) { if (!SupportedPlatforms.Contains(gameIdentity.Platform)) return; - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var derivedClient = new MyTestClient((_, type) => { @@ -337,18 +363,13 @@ protected void TestPlay( } } - private void AssertProcessStartInfo(GameProcessInfo expected, GameProcessInfo actual) + private static void AssertProcessStartInfo(GameProcessInfo expected, GameProcessInfo actual) { Assert.Equal(expected.Game, actual.Game); Assert.Equal(expected.BuildType, actual.BuildType); Assert.Equal(expected.Arguments, actual.Arguments); } - public virtual void Dispose() - { - _processLauncher.Dispose(); - } - private delegate void OnGameStartingDelegate(ArgumentCollection arguments, GameBuildType type); private class MyTestClient(OnGameStartingDelegate action, IGame game, IServiceProvider serviceProvider) diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessLauncherTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessLauncherTest.cs index 89423dc6..a9a58b66 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessLauncherTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessLauncherTest.cs @@ -1,48 +1,52 @@ -using System; -using System.Diagnostics; -using System.IO.Abstractions; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using PG.StarWarsGame.Infrastructure.Clients; +using PG.StarWarsGame.Infrastructure.Clients; using PG.StarWarsGame.Infrastructure.Clients.Arguments; using PG.StarWarsGame.Infrastructure.Clients.Arguments.GameArguments; using PG.StarWarsGame.Infrastructure.Clients.Processes; using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using System; +using System.Diagnostics; +using System.IO.Abstractions; +using System.Runtime.InteropServices; +using System.Threading.Tasks; using Testably.Abstractions; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Processes; -public class GameProcessLauncherTest : CommonTestBaseWithRandomGame, IDisposable +public class GameProcessLauncherTest : GameInfrastructureTestBaseWithRandomGame, IDisposable { private readonly GameProcessLauncher _launcher; private readonly IFileInfo _executable; - // We need to use the real FS here, cause Process.Start uses it too. - private readonly IFileSystem _realFileSystem = new RealFileSystem(); - private GameProcess? _gameProcess; public GameProcessLauncherTest() { _launcher = new GameProcessLauncher(ServiceProvider); - var tempDir = _realFileSystem.Path.Combine(_realFileSystem.Path.GetTempPath(), "GameProcessLauncherTest"); - _realFileSystem.Directory.CreateDirectory(tempDir); + var tempDir = FileSystem.Path.Combine(FileSystem.Path.GetTempPath(), "GameProcessLauncherTest"); + FileSystem.Directory.CreateDirectory(tempDir); var executableName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "TestExecutable.bat" : "TestExecutable.sh"; - _executable = _realFileSystem.FileInfo.New(_realFileSystem.Path.Combine(tempDir, executableName)); + _executable = FileSystem.FileInfo.New(FileSystem.Path.Combine(tempDir, executableName)); var scriptContent = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? "@echo off\nexit 0" + ? "@echo off\r\n" + + "timeout /t 5 /nobreak >nul\r\n" + + "exit 0" : "#!/bin/bash\nsleep 5\nexit 0"; - _realFileSystem.File.WriteAllText(_executable.FullName,scriptContent); + FileSystem.File.WriteAllText(_executable.FullName,scriptContent); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) Process.Start("chmod", $"+x {_executable.FullName}")!.WaitForExit(); } + protected override IFileSystem CreateFileSystem() + { + return new RealFileSystem(); + } + [Fact] public void StartGameProcess_ValidExecutable_Succeeds() { @@ -107,7 +111,7 @@ public async Task StartGameProcess_ValidExecutable_WaitForExitAsync() Assert.Equal(_executable.FullName, internalProcess.StartInfo.FileName); Assert.Empty(internalProcess.StartInfo.Arguments); - await process.WaitForExitAsync(); + await process.WaitForExitAsync(TestContext.Current.CancellationToken); Assert.Equal(GameProcessState.Closed, process.State); } @@ -135,9 +139,9 @@ public void Dispose() _gameProcess?.Process.Kill(); _gameProcess?.Dispose(); - var tempDir = _realFileSystem.Path.GetDirectoryName(_executable.FullName); - if (_realFileSystem.Directory.Exists(tempDir)) - _realFileSystem.Directory.Delete(tempDir, true); + var tempDir = FileSystem.Path.GetDirectoryName(_executable.FullName); + if (FileSystem.Directory.Exists(tempDir)) + FileSystem.Directory.Delete(tempDir, true); } catch { diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessTest.cs index 3acdd5e8..a0fa157f 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Processes/GameProcessTest.cs @@ -11,7 +11,7 @@ namespace PG.StarWarsGame.Infrastructure.Test.Clients.Processes; -public class GameProcessTest : CommonTestBaseWithRandomGame, IDisposable +public class GameProcessTest : GameInfrastructureTestBaseWithRandomGame, IDisposable { private Process _testProcess = null!; @@ -51,7 +51,8 @@ public async Task WaitForGameProcessExitAsync_CompletesOnProcessExit() Assert.Equal(GameProcessState.Running, gameProcess.State); - var exitTask = gameProcess.WaitForExitAsync(); + var exitTask = gameProcess.WaitForExitAsync(TestContext.Current.CancellationToken); + // ReSharper disable once MethodHasAsyncOverload process.StandardInput.WriteLine(); await exitTask; @@ -86,7 +87,7 @@ public async Task Exit_ClosesProcess() process.WaitForExit(); - await gameProcess.WaitForExitAsync(); + await gameProcess.WaitForExitAsync(TestContext.Current.CancellationToken); Assert.True(process.HasExited); Assert.Equal(GameProcessState.Closed, gameProcess.State); @@ -109,12 +110,12 @@ public async Task Exit_DoubleExitDoesNotThrow() { b.SignalAndWait(); gameProcess.Exit(); - }); + }, TestContext.Current.CancellationToken); var t2 = Task.Run(() => { b.SignalAndWait(); gameProcess.Exit(); - }); + }, TestContext.Current.CancellationToken); await Task.WhenAll(t1, t2); @@ -299,12 +300,12 @@ public async Task Dispose_CompletesWaitForExitAsyncSilently() var processInfo = new GameProcessInfo(Game, GameBuildType.Release, ArgumentCollection.Empty); var gameProcess = new GameProcess(process, processInfo); - var waitTask = gameProcess.WaitForExitAsync(); + var waitTask = gameProcess.WaitForExitAsync(TestContext.Current.CancellationToken); gameProcess.Dispose(); // WaitForExitAsync continues listening - var t = await Task.WhenAny(waitTask, Task.Delay(2000)); + var t = await Task.WhenAny(waitTask, Task.Delay(2000, TestContext.Current.CancellationToken)); Assert.NotSame(t, waitTask); } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Utilities/GameExecutableFileUtilitiesTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Utilities/GameExecutableFileUtilitiesTest.cs index ed8f70de..dd251ec4 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Clients/Utilities/GameExecutableFileUtilitiesTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Clients/Utilities/GameExecutableFileUtilitiesTest.cs @@ -4,13 +4,12 @@ using PG.StarWarsGame.Infrastructure.Clients.Utilities; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Clients.Utilities; -public class GameExecutableFileUtilitiesTest : CommonTestBase +public class GameExecutableFileUtilitiesTest : GameInfrastructureTestBase { public static IEnumerable GetGameExeNamesTestData() { @@ -38,17 +37,17 @@ public static IEnumerable GetGameExeNamesTestData() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void GetExecutableForGame_NullGame_ThrowsArgumentNullException(GameIdentity gameIdentity) { - FileSystem.InstallGame(gameIdentity, ServiceProvider); + GetOrCreateGameInstallation(gameIdentity); var buildTypes = new List { GameBuildType.Release, GameBuildType.Debug }; foreach (var buildType in buildTypes) Assert.Throws(() => GameExecutableFileUtilities.GetExecutableForGame(null!, buildType)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void GetExecutableForGame_GameExeFilesNotInstalled_ReturnsNull(GameIdentity gameIdentity) { var gameDir = FileSystem.DirectoryInfo.New("Game"); @@ -71,11 +70,11 @@ public void GetExecutableForGame_GameExeFilesNotInstalled_ReturnsNull(GameIdenti [MemberData(nameof(GetGameExeNamesTestData))] public void GetExecutableForGame_ReturnsFileHandle(GameIdentity gameIdentity, GameBuildType buildType, string expectedName) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); if (buildType == GameBuildType.Debug) - game.InstallDebug(); + gameInstallation.InstallDebug(); - var exeFile = GameExecutableFileUtilities.GetExecutableForGame(game, buildType); + var exeFile = GameExecutableFileUtilities.GetExecutableForGame(gameInstallation.Game, buildType); Assert.NotNull(exeFile); Assert.Equal(expectedName, exeFile.Name); } @@ -85,7 +84,7 @@ public void GetExecutableForGame_ReturnsFileHandle(GameIdentity gameIdentity, Ga [InlineData(GameType.Foc)] public void GetExecutableForGame_SteamHasReleaseButNotDebugFiles(GameType gameType) { - var game = FileSystem.InstallGame(new GameIdentity(gameType, GamePlatform.SteamGold), ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(gameType, GamePlatform.SteamGold)).Game; var releaseExe = GameExecutableFileUtilities.GetExecutableForGame(game, GameBuildType.Release); Assert.NotNull(releaseExe); @@ -95,13 +94,13 @@ public void GetExecutableForGame_SteamHasReleaseButNotDebugFiles(GameType gameTy } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void GetExecutableForGame_DebugFilesForOtherThanSteam_ShouldReturnNull(GameIdentity identity) { if (identity.Platform == GamePlatform.SteamGold) return; - var game = FileSystem.InstallGame(identity, ServiceProvider); + var game = GetOrCreateGameInstallation(identity).Game; using var _ = FileSystem.File.Create(FileSystem.Path.Combine(game.Directory.FullName, "StarWarsG.exe")); Assert.Null(GameExecutableFileUtilities.GetExecutableForGame(game, GameBuildType.Debug)); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameExceptionTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameExceptionTest.cs index 2cb2301c..34eeb87e 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameExceptionTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameExceptionTest.cs @@ -1,6 +1,6 @@ -using System; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Games; -using PG.TestingUtilities; +using System; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test; @@ -11,23 +11,23 @@ public static class GameExceptionTest public static void Ctor() { var exception = new GameException(); - ExceptionTest.AssertException(exception, validateMessage: false); + Assert.Exception(exception, validateMessage: false); } [Fact] public static void Ctor_String() { - var message = "game error"; + const string message = "game error"; var exception = new GameException(message); - ExceptionTest.AssertException(exception, message: message); + Assert.Exception(exception, message: message); } [Fact] public static void Ctor_String_Exception() { - var message = "game error"; + const string message = "game error"; var innerException = new Exception("Inner exception"); var exception = new GameException(message, innerException); - ExceptionTest.AssertException(exception, innerException: innerException, message: message); + Assert.Exception(exception, innerException, message); } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameIdentityTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameIdentityTest.cs index 7049a017..8450d716 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameIdentityTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameIdentityTest.cs @@ -1,5 +1,6 @@ using PG.StarWarsGame.Infrastructure.Games; -using PG.TestingUtilities; +using System; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test; @@ -9,8 +10,8 @@ public class GameIdentityTest [Fact] public void Ctor() { - var type = TestHelpers.GetRandomEnum(); - var platform = TestHelpers.GetRandomEnum(); + var type = Random.Enum(); + var platform = Random.Enum(); var id = new GameIdentity(type, platform); Assert.Equal(type, id.Type); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameLocalizationUtilitiesTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameLocalizationUtilitiesTest.cs index 0b70a84a..bb555d61 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameLocalizationUtilitiesTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameLocalizationUtilitiesTest.cs @@ -9,7 +9,7 @@ namespace PG.StarWarsGame.Infrastructure.Test; -public class GameLocalizationUtilitiesTest : CommonTestBaseWithRandomGame +public class GameLocalizationUtilitiesTest : GameInfrastructureTestBaseWithRandomGame { [Fact] public void ArgumentNull_Throws() diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CompositeDetectorTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CompositeDetectorTest.cs index 4a5651cf..c8edd60f 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CompositeDetectorTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CompositeDetectorTest.cs @@ -10,7 +10,7 @@ namespace PG.StarWarsGame.Infrastructure.Test.GameServices.Detection; -public class CompositeDetectorTest : CommonTestBase +public class CompositeDetectorTest : GameInfrastructureTestBase { [Fact] public void Ctor_InvalidThrows() @@ -22,7 +22,7 @@ public void Ctor_InvalidThrows() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_InstalledGame_MultipleDetectorsRunInSpecifiedSequence(GameIdentity identity) { var expectedResult = GameDetectionResult.FromInstalled(identity, FileSystem.DirectoryInfo.New("installed")); @@ -67,7 +67,7 @@ public void Detect_TryDetect_InstalledGame_MultipleDetectorsRunInSpecifiedSequen } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_InstalledGame_SecondDetectorDoesNotRunBecauseFirstFoundGame(GameIdentity identity) { var expectedResult = GameDetectionResult.FromInstalled(identity, FileSystem.DirectoryInfo.New("installed")); @@ -104,7 +104,7 @@ public void Detect_TryDetect_InstalledGame_SecondDetectorDoesNotRunBecauseFirstF } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_InstalledGame_ShallNotThrowIfInstalled(GameIdentity identity) { var expectedResult = GameDetectionResult.FromInstalled(identity, FileSystem.DirectoryInfo.New("installed")); @@ -123,7 +123,7 @@ public void Detect_TryDetect_InstalledGame_ShallNotThrowIfInstalled(GameIdentity } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_NotInstalledGame_ShallNotThrowEvenIfNotInstalled(GameIdentity identity) { var expectedResult = GameDetectionResult.NotInstalled(identity.Type); @@ -142,7 +142,7 @@ public void Detect_TryDetect_NotInstalledGame_ShallNotThrowEvenIfNotInstalled(Ga } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_NotInstalledGame_WhenAllDetectorsReturnNull(GameIdentity identity) { var expectedResult = GameDetectionResult.NotInstalled(identity.Type); @@ -161,7 +161,7 @@ public void Detect_TryDetect_NotInstalledGame_WhenAllDetectorsReturnNull(GameIde } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_ShallThrowAggregateException_TryDetect_ReturnsNotInstalledGame_WhenAllDetectorsThrow(GameIdentity identity) { var expectedResult = GameDetectionResult.NotInstalled(identity.Type); @@ -179,7 +179,7 @@ public void Detect_ShallThrowAggregateException_TryDetect_ReturnsNotInstalledGam } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_ShallPropagateRequireInitializationEvent(GameIdentity identity) { var expectedResult = GameDetectionResult.RequiresInitialization(identity.Type); @@ -234,7 +234,7 @@ public void Detect_TryDetect_ShallPropagateRequireInitializationEvent(GameIdenti //} [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_ShallDisposeDetectors(GameIdentity identity) { var expectedResult = GameDetectionResult.FromInstalled(identity, FileSystem.DirectoryInfo.New("installed")); @@ -255,11 +255,16 @@ public void Detect_ShallDisposeDetectors(GameIdentity identity) Assert.True(thirdDetector.IsDisposed); } - private class EmptyDetector : IGameDetector + private sealed class EmptyDetector : IGameDetector { public event EventHandler? InitializationRequested; public GameDetectionResult Detect(GameType gameType, ICollection platforms) => throw new NotImplementedException(); public bool TryDetect(GameType gameType, ICollection platforms, out GameDetectionResult result) => throw new NotImplementedException(); + + private void OnInitializationRequested(GameInitializeRequestEventArgs e) + { + InitializationRequested?.Invoke(this, e); + } } private delegate GameDetectionResult DetectDelegate(IGameDetector detector, GameType gameType, ICollection platforms); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CustomGameDetectorTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CustomGameDetectorTest.cs index 6499fbf3..940121c4 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CustomGameDetectorTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/CustomGameDetectorTest.cs @@ -1,46 +1,28 @@ -using System; -using System.IO.Abstractions; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using Testably.Abstractions.Testing; +using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using System; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices.Detection; -public class CustomGameDetectorTest +public class CustomGameDetectorTest : GameInfrastructureTestBase { - private readonly IServiceProvider _serviceProvider; - private readonly MockFileSystem _fileSystem = new(); - - public CustomGameDetectorTest() - { - var sc = new ServiceCollection(); - sc.AddSingleton(_fileSystem); - PetroglyphGameInfrastructure.InitializeServices(sc); - _serviceProvider = sc.BuildServiceProvider(); - } - [Theory] - [InlineData(GameType.Eaw)] - [InlineData(GameType.Foc)] - public void Detect_TryDetect_FindGameLocationThrowsException(GameType gameType) + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] + public void Detect_TryDetect_FindGameLocationThrowsException(GameIdentity identity) { - var expected = GameDetectionResult.NotInstalled(gameType); - foreach (var platform in GITestUtilities.RealPlatforms) - { - var gameInfo = _fileSystem.InstallGame(new GameIdentity(gameType, platform), _serviceProvider); - Assert.NotNull(gameInfo); + var expected = GameDetectionResult.NotInstalled(identity.Type); + var game = GetOrCreateGameInstallation(identity); + Assert.NotNull(game); - var detector = new CallbackGameDetectorBase(FindGameThrowsException, _serviceProvider, false); + var detector = new CallbackGameDetectorBase(FindGameThrowsException, ServiceProvider, false); - Assert.Throws(() => detector.Detect(gameType)); + Assert.Throws(() => detector.Detect(identity.Type)); - Assert.False(detector.TryDetect(gameType, [], out var result)); - expected.AssertEqual(result); - } + Assert.False(detector.TryDetect(identity.Type, [], out var result)); + expected.AssertEqual(result); } [Theory] @@ -49,7 +31,7 @@ public void Detect_TryDetect_FindGameLocationThrowsException(GameType gameType) public void Detect_TryDetect_FindGameLocationReturnsGameWhenItDoesNotExistsOnDisk(GameType gameType) { var expected = GameDetectionResult.NotInstalled(gameType); - var detector = new CallbackGameDetectorBase(ReturnsGame, _serviceProvider, false); + var detector = new CallbackGameDetectorBase(ReturnsGame, ServiceProvider, false); var result = detector.Detect(gameType); expected.AssertEqual(result); @@ -59,87 +41,83 @@ public void Detect_TryDetect_FindGameLocationReturnsGameWhenItDoesNotExistsOnDis } [Theory] - [InlineData(GameType.Eaw, true)] - [InlineData(GameType.Eaw, false)] - [InlineData(GameType.Foc, true)] - [InlineData(GameType.Foc, false)] - public void Detect_TryDetect_InitializationRequestedIsTriggeredWhenSupported_DoNotHandle(GameType gameType, bool supportInitialization) + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] + public void Detect_TryDetect_InitializationRequestedIsNotTriggeredWhenSupported_DoNotHandle(GameIdentity identity) { - var requiredInit = GameDetectionResult.RequiresInitialization(gameType); - foreach (var platform in GITestUtilities.RealPlatforms) - { - var gameInfo = _fileSystem.InstallGame(new GameIdentity(gameType, platform), _serviceProvider); - Assert.NotNull(gameInfo); - - var state = new DetectorState(); - var detector = new CallbackWithStateGameDetectorBase(state, HandleRequiredInitialization, _serviceProvider, supportInitialization); - - var eventRaised = false; - - detector.InitializationRequested += (_, e) => - { - state.Value = "some Value"; - eventRaised = true; - // Do not handle - e.Handled = false; - }; + var game = GetOrCreateGameInstallation(identity).Game; + Assert.NotNull(game); + Detect_TryDetect_InitializationRequestedIsTriggeredWhenSupported_DoNotHandle(game, false); + Detect_TryDetect_InitializationRequestedIsTriggeredWhenSupported_DoNotHandle(game, true); + } + + private void Detect_TryDetect_InitializationRequestedIsTriggeredWhenSupported_DoNotHandle(IGame game, bool supportInitialization) + { + var requiredInit = GameDetectionResult.RequiresInitialization(game.Type); - var result = detector.Detect(gameType, platform); - requiredInit.AssertEqual(result); - Assert.Equal(supportInitialization, eventRaised); + var state = new DetectorState(); + var detector = new CallbackWithStateGameDetectorBase(state, HandleRequiredInitialization, ServiceProvider, supportInitialization); - // Reset - eventRaised = false; - state.Value = null; + var eventRaised = false; - Assert.False(detector.TryDetect(gameType, [platform], out result)); - requiredInit.AssertEqual(result); - Assert.Equal(supportInitialization, eventRaised); - } + detector.InitializationRequested += (_, e) => + { + state.Value = "some Value"; + eventRaised = true; + // Do not handle + e.Handled = false; + }; + + var result = detector.Detect(game.Type, game.Platform); + requiredInit.AssertEqual(result); + Assert.Equal(supportInitialization, eventRaised); + + // Reset + eventRaised = false; + state.Value = null; + + Assert.False(detector.TryDetect(game.Type, [game.Platform], out result)); + requiredInit.AssertEqual(result); + Assert.Equal(supportInitialization, eventRaised); } [Theory] - [InlineData(GameType.Eaw)] - [InlineData(GameType.Foc)] - public void Detect_TryDetect_InitializationRequestedIsTriggeredAndHandled(GameType gameType) + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] + public void Detect_TryDetect_InitializationRequestedIsTriggeredAndHandled(GameIdentity identity) { - foreach (var platform in GITestUtilities.RealPlatforms) - { - var gameInfo = _fileSystem.InstallGame(new GameIdentity(gameType, platform), _serviceProvider); - Assert.NotNull(gameInfo); - - var installed = GameDetectionResult.FromInstalled(new GameIdentity(gameType, platform), gameInfo.Directory); - - var state = new DetectorState(); - var detector = new CallbackWithStateGameDetectorBase(state, HandleRequiredInitialization, _serviceProvider, true); - - var eventRaised = false; - - detector.InitializationRequested += (_, e) => - { - state.Value = gameInfo.Directory.FullName; - e.Handled = true; - eventRaised = true; - }; - var result = detector.Detect(gameType, platform); - installed.AssertEqual(result); - Assert.True(eventRaised); - - // Reset - eventRaised = false; - state.Value = null; - - Assert.True(detector.TryDetect(gameType, [platform], out result)); - installed.AssertEqual(result); - Assert.True(eventRaised); - } + var game = GetOrCreateGameInstallation(identity).Game; + Assert.NotNull(game); + + var installed = GameDetectionResult.FromInstalled(identity, game.Directory); + + var state = new DetectorState(); + var detector = new CallbackWithStateGameDetectorBase(state, HandleRequiredInitialization, ServiceProvider, true); + + var eventRaised = false; + + detector.InitializationRequested += (_, e) => + { + state.Value = game.Directory.FullName; + e.Handled = true; + eventRaised = true; + }; + var result = detector.Detect(identity.Type, identity.Platform); + installed.AssertEqual(result); + Assert.True(eventRaised); + + // Reset + eventRaised = false; + state.Value = null; + + Assert.True(detector.TryDetect(identity.Type, [identity.Platform], out result)); + installed.AssertEqual(result); + Assert.True(eventRaised); } private GameDetectorBase.GameLocationData HandleRequiredInitialization(GameType type, DetectorState state) { return state.Value is null ? GameDetectorBase.GameLocationData.RequiresInitialization - : new GameDetectorBase.GameLocationData(_fileSystem.DirectoryInfo.New(state.Value.ToString()!)); + : new GameDetectorBase.GameLocationData(FileSystem.DirectoryInfo.New(state.Value.ToString()!)); } private static GameDetectorBase.GameLocationData FindGameThrowsException(GameType arg) @@ -149,7 +127,7 @@ private static GameDetectorBase.GameLocationData FindGameThrowsException(GameTyp private GameDetectorBase.GameLocationData ReturnsGame(GameType arg) { - return new GameDetectorBase.GameLocationData(_fileSystem.DirectoryInfo.New($"games/{arg}")); + return new GameDetectorBase.GameLocationData(FileSystem.DirectoryInfo.New($"games/{arg}")); } public class CallbackGameDetectorBase( diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/DirectoryGameDetectorTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/DirectoryGameDetectorTest.cs index 3dac0eb0..784f36f5 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/DirectoryGameDetectorTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/DirectoryGameDetectorTest.cs @@ -4,29 +4,27 @@ using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices.Detection; -public class DirectoryGameDetectorTest : GameDetectorTestBase +public class DirectoryGameDetectorTest : GameDetectorTestBase { protected override bool SupportInitialization => false; protected override ICollection SupportedPlatforms => GITestUtilities.RealPlatforms; protected override bool CanDisableInitRequest => false; - protected override IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization) + protected override IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization) { return new DirectoryGameDetector(gameInfo.GameDirectory ?? FileSystem.DirectoryInfo.New("doesNotExist"), ServiceProvider); } - protected override GameDetectorTestInfo SetupGame(GameIdentity gameIdentity) + protected override GameDetectorTestInfo SetupGame(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - return new(gameIdentity.Type, game.Directory, default); + var game = GetOrCreateGameInstallation(gameIdentity).Game; + return new GameDetectorTestInfo(gameIdentity.Type, game.Directory, null); } [Fact] @@ -38,14 +36,14 @@ public void InvalidArgs_Throws() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GamesNotInstalled_DirectoryNotFound(GameIdentity identity) { TestNotInstalledWithCustomSetup(identity, _ => FileSystem.DirectoryInfo.New("doesNotExist")); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GamesNotInstalled_GameExeNotFound(GameIdentity identity) { FileSystem.Initialize().WithFile("Game/Data/megafiles.xml"); @@ -53,7 +51,7 @@ public void Detect_TryDetect_GamesNotInstalled_GameExeNotFound(GameIdentity iden } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GamesNotInstalled_GameDataWithMegaFilesNotFound(GameIdentity identity) { var exeName = identity.Type == GameType.Eaw @@ -68,12 +66,12 @@ public void Detect_TryDetect_GamesNotInstalled_GameDataWithMegaFilesNotFound(Gam } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GamesInstalled_WrongPathGiven(GameIdentity identity) { TestNotInstalledWithCustomSetup(identity, i => { - FileSystem.InstallGame(i, ServiceProvider); + if (i != null) GetOrCreateGameInstallation(i); return FileSystem.DirectoryInfo.New("other"); }); } @@ -84,15 +82,15 @@ private void TestNotInstalledWithCustomSetup(GameIdentity identity, Func new GameDetectorTestInfo(identity.Type, customSetup(identity), default), + _ => new GameDetectorTestInfo(identity.Type, customSetup(identity), null), _ => expected, null, queryPlatforms: []); } - protected override GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity) + protected override GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity) => throw new NotSupportedException(); - protected override void HandleInitialization(bool shallInitSuccessfully, GameDetectorTestInfo info) + protected override void HandleInitialization(bool shallInitSuccessfully, GameDetectorTestInfo info) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GameDetectionResultTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GameDetectionResultTest.cs index 75a19d23..f7f0e0b5 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GameDetectionResultTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GameDetectionResultTest.cs @@ -6,7 +6,7 @@ namespace PG.StarWarsGame.Infrastructure.Test.GameServices.Detection; -public class GameDetectionResultTest : CommonTestBase +public class GameDetectionResultTest : GameInfrastructureTestBase { [Fact] public void CreateInstance_Throws() diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GamePlatformIdentifierTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GamePlatformIdentifierTest.cs index 99489e01..e446e92e 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GamePlatformIdentifierTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/GamePlatformIdentifierTest.cs @@ -1,29 +1,22 @@ -using System; -using System.Collections.Generic; -using System.IO.Abstractions; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection.Platform; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; +using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using System; +using System.Collections.Generic; +using System.IO.Abstractions; using Testably.Abstractions.Testing; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices.Detection; -public class GamePlatformIdentifierTest +public class GamePlatformIdentifierTest : GameInfrastructureTestBase { - private readonly MockFileSystem _fileSystem = new(); private readonly GamePlatformIdentifier _platformIdentifier; - private readonly IServiceProvider _serviceProvider; public GamePlatformIdentifierTest() { - var sc = new ServiceCollection(); - sc.AddSingleton(_fileSystem); - PetroglyphGameInfrastructure.InitializeServices(sc); - _serviceProvider = sc.BuildServiceProvider(); - _platformIdentifier = new GamePlatformIdentifier(_serviceProvider); + _platformIdentifier = new GamePlatformIdentifier(ServiceProvider); } [Fact] @@ -36,20 +29,15 @@ public void NullArgs_ThrowsArgumentNullException() } [Theory] - [InlineData(GameType.Eaw)] - [InlineData(GameType.Foc)] - public void GetGamePlatform_WrongGameInstalledReturnsUndefined(GameType queryGameType) + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] + public void GetGamePlatform_WrongGameInstalledReturnsUndefined(GameIdentity identity) { - foreach (var platform in GITestUtilities.RealPlatforms) - { - var installType = queryGameType == GameType.Foc ? GameType.Eaw : GameType.Foc; - var game = _fileSystem.InstallGame(new GameIdentity(installType, platform), _serviceProvider); - var gameLocation = game.Directory; - - var actual = _platformIdentifier.GetGamePlatform(queryGameType, ref gameLocation); - Assert.True(GamePlatform.Undefined == actual, $"Expected value to be Undefined for platform {platform}"); - Assert.Equal(game.Directory.FullName, gameLocation.FullName); - } + var game = GetOrCreateGameInstallation(new GameIdentity(identity.Type.Opposite(), identity.Platform)).Game; + var gameLocation = game.Directory; + + var actual = _platformIdentifier.GetGamePlatform(identity.Type, ref gameLocation); + Assert.True(GamePlatform.Undefined == actual, $"Expected value to be Undefined for platform {identity.Platform}"); + Assert.Equal(game.Directory.FullName, gameLocation.FullName); } @@ -58,7 +46,7 @@ public void GetGamePlatform_WrongGameInstalledReturnsUndefined(GameType queryGam [InlineData(GameType.Foc)] public void GetGamePlatform_NoGameInstalledReturnsUndefined(GameType queryGameType) { - var gameLocation = _fileSystem.DirectoryInfo.New("noGameDir"); + var gameLocation = FileSystem.DirectoryInfo.New("noGameDir"); var locRef = gameLocation; var actual = _platformIdentifier.GetGamePlatform(queryGameType, ref locRef); Assert.Equal(GamePlatform.Undefined, actual); @@ -68,9 +56,9 @@ public void GetGamePlatform_NoGameInstalledReturnsUndefined(GameType queryGameTy [Fact] public void GetGamePlatform_FocOriginWithSanitization() { - _fileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.Origin), _serviceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(GameType.Foc, GamePlatform.Origin)); - var locRef = _fileSystem.GetWrongOriginFocRegistryLocation(); + var locRef = gameInstallation.GetWrongOriginFocRegistryLocation(); var locStore = locRef; var actual = _platformIdentifier.GetGamePlatform(GameType.Foc, ref locRef); @@ -94,9 +82,9 @@ public void GetGamePlatform_CannotGetPlatform_GameExeNotFound_Eaw(string subPath private void GetGamePlatform_CannotGetPlatform_GameExeNotFound(GameType gameType, string gamePath) { - _fileSystem.Initialize().WithFile(_fileSystem.Path.Combine(gamePath, "Data", "megafiles.xml")); + FileSystem.Initialize().WithFile(FileSystem.Path.Combine(gamePath, "Data", "megafiles.xml")); - var loc = _fileSystem.DirectoryInfo.New(gamePath); + var loc = FileSystem.DirectoryInfo.New(gamePath); var actual = _platformIdentifier.GetGamePlatform(gameType, ref loc); Assert.Equal(GamePlatform.Undefined, actual); @@ -119,14 +107,14 @@ public void GetGamePlatform_CannotGetPlatform_DataAndMegafilesXmlNotFound_Eaw(st private void GetGamePlatform_CannotGetPlatform_DataAndMegafilesXmlNotFound(GameType gameType, string gamePath) { - _fileSystem.Initialize().WithFile(_fileSystem.Path.Combine(gamePath, PetroglyphStarWarsGameConstants.ForcesOfCorruptionExeFileName)); - var loc = _fileSystem.DirectoryInfo.New(_fileSystem.Path.Combine(gamePath)); + FileSystem.Initialize().WithFile(FileSystem.Path.Combine(gamePath, PetroglyphStarWarsGameConstants.ForcesOfCorruptionExeFileName)); + var loc = FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(gamePath)); var actual = _platformIdentifier.GetGamePlatform(gameType, ref loc); Assert.Equal(GamePlatform.Undefined, actual); Assert.Equal(loc, loc); - _fileSystem.Directory.CreateDirectory(_fileSystem.Path.Combine(gamePath, "Data")); + FileSystem.Directory.CreateDirectory(FileSystem.Path.Combine(gamePath, "Data")); actual = _platformIdentifier.GetGamePlatform(gameType, ref loc); Assert.Equal(GamePlatform.Undefined, actual); Assert.Equal(loc, loc); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/RegistryGameDetectorTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/RegistryGameDetectorTest.cs index 1bb63d10..040d85b9 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/RegistryGameDetectorTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/Detection/RegistryGameDetectorTest.cs @@ -6,8 +6,8 @@ using PG.StarWarsGame.Infrastructure.Games.Registry; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Game.Registry; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; @@ -27,46 +27,39 @@ public class RegistryGameDetectorTest : GameDetectorTestBase true; protected override ICollection SupportedPlatforms => GITestUtilities.RealPlatforms; - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(_registry); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_registry); } protected override IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization) { var eawRegistry = gameInfo.DetectorSetupInfo?.EawRegistry - ?? GameType.Eaw.CreateNonExistingRegistry(ServiceProvider); + ?? GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(GameType.Eaw); var focRegistry = gameInfo.DetectorSetupInfo?.FocRegistry - ?? GameType.Foc.CreateNonExistingRegistry(ServiceProvider); + ?? GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(GameType.Foc); return new RegistryGameDetector(eawRegistry, focRegistry, shallHandleInitialization, ServiceProvider); } - private IGame InstallGame(GameIdentity gameIdentity) - { - return FileSystem.InstallGame(gameIdentity, ServiceProvider); - } - protected override GameDetectorTestInfo SetupGame(GameIdentity gameIdentity) { - var game = InstallGame(gameIdentity); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var registryContainer = SetupRegistry(game.Type, TestGameRegistrySetupData.Installed(game.Type, game.Directory)); return new GameDetectorTestInfo(game.Type, game.Directory, registryContainer); } protected override GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity) { - var game = InstallGame(gameIdentity); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var registryContainer = SetupRegistry(game.Type, TestGameRegistrySetupData.Uninitialized(gameIdentity.Type)); return new GameDetectorTestInfo(game.Type, game.Directory, registryContainer); } private GameRegistryContainer SetupRegistry(GameType gameType, TestGameRegistrySetupData registrySetup) { - var otherGameType = gameType == GameType.Eaw ? GameType.Foc : GameType.Eaw; - - var gameRegistry = registrySetup.Create(ServiceProvider); - var defaultRegistry = otherGameType.CreateNonExistingRegistry(ServiceProvider); + var gameRegistry = GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(registrySetup); + var defaultRegistry = GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(gameType.Opposite()); IGameRegistry eawRegistry; IGameRegistry focRegistry; @@ -90,14 +83,14 @@ protected override void HandleInitialization(bool shallInitSuccessfully, GameDet if (!shallInitSuccessfully) return; var registrySetupData = TestGameRegistrySetupData.Installed(info.GameType, info.GameDirectory!); - registrySetupData.Create(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(registrySetupData); } [Fact] public void TestInvalidArgs_Throws() { - var eawRegistry = GameType.Eaw.CreateNonExistingRegistry(ServiceProvider); - var focRegistry = GameType.Foc.CreateNonExistingRegistry(ServiceProvider); + var eawRegistry = GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(GameType.Eaw); + var focRegistry = GameInfrastructureTesting.Registry(ServiceProvider).CreateNonExistingRegistry(GameType.Foc); Assert.Throws(() => new RegistryGameDetector(null!, focRegistry, false, ServiceProvider)); Assert.Throws(() => new RegistryGameDetector(eawRegistry, null!, false, ServiceProvider)); Assert.Throws(() => new RegistryGameDetector(eawRegistry, focRegistry, false, null!)); @@ -106,7 +99,7 @@ public void TestInvalidArgs_Throws() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Dispose_ShallDisposeRegistries(GameIdentity identity) { var info = SetupGame(identity); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/EnglishGameNameResolverTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/EnglishGameNameResolverTest.cs index 534c0a83..12cad4cc 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/EnglishGameNameResolverTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/EnglishGameNameResolverTest.cs @@ -3,12 +3,13 @@ using System.Globalization; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Name; +using PG.StarWarsGame.Infrastructure.Testing; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices; -public class EnglishGameNameResolverTest : CommonTestBase +public class EnglishGameNameResolverTest : GameInfrastructureTestBase { public static IEnumerable GetCultures() { @@ -25,7 +26,7 @@ public static IEnumerable GetCultures() public void ResolveName_IgnoreCulture(CultureInfo culture) { var resolver = new EnglishGameNameResolver(); - var id = CreateRandomGameIdentity(); + var id = GITestUtilities.GetRandomGameIdentity(); resolver.ResolveName(id, culture); var name = resolver.ResolveName(id, CultureInfo.CurrentCulture); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/GameFactoryTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/GameFactoryTest.cs index f2c90a0f..ccbb0946 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/GameFactoryTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/GameFactoryTest.cs @@ -1,20 +1,19 @@ using System; using System.Collections.Generic; using System.Globalization; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Services.Name; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices; -public class GameFactoryTest : CommonTestBase +public class GameFactoryTest : GameInfrastructureTestBase { private readonly GameFactory _factory; private readonly IGameNameResolver _nameResolver; @@ -36,23 +35,23 @@ public void CreateGame_NullArg_Throws() { Assert.Throws(() => _factory.CreateGame(null!, CultureInfo.CurrentCulture)); Assert.Throws(() => _factory.CreateGame( - GameDetectionResult.NotInstalled(TestHelpers.GetRandomEnum()), + GameDetectionResult.NotInstalled(Random.Enum()), null!)); Assert.Throws(() => _factory.CreateGame( null!, FileSystem.DirectoryInfo.New("path"), - TestHelpers.RandomBool(), + Random.Bool(), CultureInfo.CurrentCulture)); Assert.Throws(() => _factory.CreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), null!, - TestHelpers.RandomBool(), + Random.Bool(), CultureInfo.CurrentCulture)); Assert.Throws(() => _factory.CreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("path"), - TestHelpers.RandomBool(), + Random.Bool(), null!)); } @@ -61,23 +60,23 @@ public void TryCreateGame_NullArg_Throws() { Assert.Throws(() => _factory.TryCreateGame(null!, CultureInfo.CurrentCulture, out _)); Assert.Throws(() => _factory.TryCreateGame( - GameDetectionResult.NotInstalled(TestHelpers.GetRandomEnum()), + GameDetectionResult.NotInstalled(Random.Enum()), null!, out _)); Assert.Throws(() => _factory.TryCreateGame( null!, FileSystem.DirectoryInfo.New("path"), - TestHelpers.RandomBool(), + Random.Bool(), CultureInfo.CurrentCulture, out _)); Assert.Throws(() => _factory.TryCreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), null!, - TestHelpers.RandomBool(), + Random.Bool(), CultureInfo.CurrentCulture, out _)); Assert.Throws(() => _factory.TryCreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("path"), - TestHelpers.RandomBool(), + Random.Bool(), null!, out _)); } @@ -85,20 +84,20 @@ public void TryCreateGame_NullArg_Throws() public void CreateGame_NoGameInstalled_Throws() { Assert.Throws(() => - _factory.CreateGame(GameDetectionResult.NotInstalled(TestHelpers.GetRandomEnum()), + _factory.CreateGame(GameDetectionResult.NotInstalled(Random.Enum()), CultureInfo.CurrentCulture)); Assert.Throws(() => - _factory.CreateGame(GameDetectionResult.RequiresInitialization(TestHelpers.GetRandomEnum()), + _factory.CreateGame(GameDetectionResult.RequiresInitialization(Random.Enum()), CultureInfo.CurrentCulture)); } [Fact] public void TryCreateGame_NoGameInstalled_Throws() { - Assert.False(_factory.TryCreateGame(GameDetectionResult.NotInstalled(TestHelpers.GetRandomEnum()), + Assert.False(_factory.TryCreateGame(GameDetectionResult.NotInstalled(Random.Enum()), CultureInfo.CurrentCulture, out _)); Assert.False(_factory.TryCreateGame( - GameDetectionResult.RequiresInitialization(TestHelpers.GetRandomEnum()), + GameDetectionResult.RequiresInitialization(Random.Enum()), CultureInfo.CurrentCulture, out _)); } @@ -107,12 +106,12 @@ public void CreateGame_GameNotExists_Throws() { Assert.Throws(() => _factory.CreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("gamePath"), true, CultureInfo.CurrentCulture)); Assert.False(_factory.TryCreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("gamePath"), true, CultureInfo.CurrentCulture, @@ -123,12 +122,12 @@ public void CreateGame_GameNotExists_Throws() Assert.Throws(() => _factory.CreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("gamePath"), true, CultureInfo.CurrentCulture)); Assert.False(_factory.TryCreateGame( - CreateRandomGameIdentity(), + GITestUtilities.GetRandomGameIdentity(), FileSystem.DirectoryInfo.New("gamePath"), true, CultureInfo.CurrentCulture, @@ -146,11 +145,10 @@ public void CreateGame_GameNotExists_Throws() [InlineData(GamePlatform.SteamGold, false)] public void CreateGame_WrongGameIdentityInstalled_WrongPlatform_Throws(GamePlatform platform, bool checkExists) { - var actualGameType = TestHelpers.GetRandomEnum(); + var actualGameType = Random.Enum(); // Use Disk so that we can check against more specific platforms - var installedGame = - FileSystem.InstallGame(new GameIdentity(actualGameType, GamePlatform.Disk), ServiceProvider); + var installedGame = GetOrCreateGameInstallation(new GameIdentity(actualGameType, GamePlatform.Disk)).Game; var createIdentity = new GameIdentity(actualGameType, platform); @@ -170,11 +168,10 @@ public static IEnumerable GetWrongGameTypeTestData() [MemberData(nameof(GetWrongGameTypeTestData))] public void CreateGame_WrongGameIdentityInstalled_WrongType_Throws(GamePlatform platform, bool checkExists) { - var actualGameType = TestHelpers.GetRandomEnum(); + var actualGameType = Random.Enum(); // Use Disk so that we can check against more specific platforms - var installedGame = FileSystem.InstallGame( - new GameIdentity(actualGameType, platform), ServiceProvider); + var installedGame = GetOrCreateGameInstallation(new GameIdentity(actualGameType, platform)).Game; var createGameType = actualGameType == GameType.Eaw ? GameType.Foc : GameType.Eaw; var createIdentity = new GameIdentity(createGameType, platform); @@ -185,17 +182,17 @@ public void CreateGame_WrongGameIdentityInstalled_WrongType_Throws(GamePlatform [Fact] public void CreateGame_UnidentifiedPlatform_Throws() { - var installedGame = CreateRandomGame(); + var game = GetOrCreateGameInstallation().Game; Assert.Throws(() => _factory.CreateGame( - new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.Undefined), - installedGame.Directory, - TestHelpers.RandomBool(), + new GameIdentity(Random.Enum(), GamePlatform.Undefined), + game.Directory, + Random.Bool(), CultureInfo.CurrentCulture)); Assert.False(_factory.TryCreateGame( - new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.Undefined), - installedGame.Directory, - TestHelpers.RandomBool(), + new GameIdentity(Random.Enum(), GamePlatform.Undefined), + game.Directory, + Random.Bool(), CultureInfo.CurrentCulture, out _)); } @@ -239,10 +236,10 @@ private void AssertGame(IGame game, IGameIdentity expectedIdentity, string expec } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateGame_FromIdentity_GameCreated(GameIdentity gameIdentity) { - var installedGame = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var installedGame = GetOrCreateGameInstallation(gameIdentity).Game; var expectedName = _nameResolver.ResolveName(gameIdentity, CultureInfo.CurrentCulture); @@ -257,10 +254,10 @@ public void CreateGame_FromIdentity_GameCreated(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateGame_FromDetectionResult_GameCreated(GameIdentity gameIdentity) { - var installedGame = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var installedGame = GetOrCreateGameInstallation(gameIdentity).Game; var detector = new DirectoryGameDetector(installedGame.Directory, ServiceProvider); var detectionResult = detector.Detect(gameIdentity.Type, gameIdentity.Platform); @@ -276,7 +273,7 @@ public void CreateGame_FromDetectionResult_GameCreated(GameIdentity gameIdentity AssertGame(tryGame, gameIdentity, installedGame.Directory.FullName, expectedName); } - public class GameFactoryWithNullNameResolver : CommonTestBaseWithRandomGame + public class GameFactoryWithNullNameResolver : GameInfrastructureTestBaseWithRandomGame { private readonly GameFactory _factory; @@ -285,10 +282,10 @@ public GameFactoryWithNullNameResolver() _factory = new GameFactory(ServiceProvider); } - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(new NullGameNameResolver()); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new NullGameNameResolver()); } [Fact] @@ -306,7 +303,7 @@ public void CreateGame_NameResolverReturnNull_Throws() } } - public class GameFactoryWithCustomNameResolver : CommonTestBaseWithRandomGame + public class GameFactoryWithCustomNameResolver : GameInfrastructureTestBaseWithRandomGame { private readonly GameFactory _factory; @@ -315,10 +312,10 @@ public GameFactoryWithCustomNameResolver() _factory = new GameFactory(ServiceProvider); } - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(new CultureAwareGameNameResolver()); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new CultureAwareGameNameResolver()); } public static IEnumerable GetCultures() diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamGameHelpersTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamGameHelpersTest.cs index 9c55fe62..901a6407 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamGameHelpersTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamGameHelpersTest.cs @@ -1,42 +1,40 @@ using System; using AnakinRaW.CommonUtilities.FileSystem.Normalization; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Steam; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.GameServices; -public class SteamGameHelpersTest : CommonTestBase +public class SteamGameHelpersTest : GameInfrastructureTestBase { - private readonly SteamGameHelpers _service; + private readonly SteamGameHelpers _steamGameHelpers; public SteamGameHelpersTest() { - _service = new SteamGameHelpers(ServiceProvider); + _steamGameHelpers = new SteamGameHelpers(ServiceProvider); } [Fact] public void GetWorkshopsLocation_NullArgs_Throws() { - Assert.Throws(() => _service.GetWorkshopsLocation(null!)); - Assert.Throws(() => _service.TryGetWorkshopsLocation(null!, out _)); + Assert.Throws(() => _steamGameHelpers.GetWorkshopsLocation(null!)); + Assert.Throws(() => _steamGameHelpers.TryGetWorkshopsLocation(null!, out _)); } [Fact] public void GetWorkshopsLocation_Success() { - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), - ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), GamePlatform.SteamGold)).Game; - var wsDir = _service.GetWorkshopsLocation(game); + var wsDir = _steamGameHelpers.GetWorkshopsLocation(game); var expectedEnd = PathNormalizer.Normalize("/workshop/content/32470", PathNormalizeOptions.UnifySeparators); Assert.EndsWith(expectedEnd, wsDir.FullName); - Assert.True(_service.TryGetWorkshopsLocation(game, out var directoryInfo)); + Assert.True(_steamGameHelpers.TryGetWorkshopsLocation(game, out var directoryInfo)); Assert.EndsWith(expectedEnd, directoryInfo.FullName); } @@ -46,11 +44,11 @@ public void GetWorkshopsLocation_CannotFindWorkshopPath() var gameDir = FileSystem.DirectoryInfo.New("SteamFakeFame"); gameDir.Create(); var game = new PetroglyphStarWarsGame( - new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), gameDir, "Game", + new GameIdentity(Random.Enum(), GamePlatform.SteamGold), gameDir, "Game", ServiceProvider); - Assert.Throws(() => _service.GetWorkshopsLocation(game)); - Assert.False(_service.TryGetWorkshopsLocation(game, out _)); + Assert.Throws(() => _steamGameHelpers.GetWorkshopsLocation(game)); + Assert.False(_steamGameHelpers.TryGetWorkshopsLocation(game, out _)); } [Theory] @@ -60,10 +58,9 @@ public void GetWorkshopsLocation_CannotFindWorkshopPath() [InlineData(GamePlatform.Origin)] public void GetWorkshopsLocation_FailNoSteam(GamePlatform platform) { - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), platform), - ServiceProvider); - Assert.Throws(() => _service.GetWorkshopsLocation(game)); - Assert.False(_service.TryGetWorkshopsLocation(game, out _)); + var game = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), platform)).Game; + Assert.Throws(() => _steamGameHelpers.GetWorkshopsLocation(game)); + Assert.False(_steamGameHelpers.TryGetWorkshopsLocation(game, out _)); } [Fact] @@ -73,7 +70,7 @@ public void ToSteamWorkshopsId() new Random().NextBytes(buf); var steamId = (ulong)BitConverter.ToInt64(buf, 0); - Assert.True(_service.ToSteamWorkshopsId(steamId.ToString(), out var result)); + Assert.True(_steamGameHelpers.ToSteamWorkshopsId(steamId.ToString(), out var result)); Assert.Equal(steamId, result); Assert.True(SteamGameHelpers.IstValidSteamWorkshopsDir(steamId.ToString(), out result)); @@ -96,7 +93,7 @@ public void ToSteamWorkshopsId() [InlineData("1 ")] public void ToSteamWorkshopsId_InvalidFormats(string input) { - Assert.False(_service.ToSteamWorkshopsId(input, out _)); + Assert.False(_steamGameHelpers.ToSteamWorkshopsId(input, out _)); Assert.False(SteamGameHelpers.IstValidSteamWorkshopsDir(input, out _)); Assert.False(SteamGameHelpers.IstValidSteamWorkshopsDir(input)); } @@ -104,8 +101,8 @@ public void ToSteamWorkshopsId_InvalidFormats(string input) [Fact] public void ToSteamWorkshopsId_InvalidArgs_Throws() { - Assert.Throws(() => _service.ToSteamWorkshopsId(null!, out _)); - Assert.Throws(() => _service.ToSteamWorkshopsId(string.Empty, out _)); + Assert.Throws(() => _steamGameHelpers.ToSteamWorkshopsId(null!, out _)); + Assert.Throws(() => _steamGameHelpers.ToSteamWorkshopsId(string.Empty, out _)); Assert.Throws(() => SteamGameHelpers.IstValidSteamWorkshopsDir(null!, out _)); Assert.Throws(() => SteamGameHelpers.IstValidSteamWorkshopsDir(string.Empty, out _)); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamWorkshopWebpageDownloaderTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamWorkshopWebpageDownloaderTest.cs index 74bbf63a..1b448854 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamWorkshopWebpageDownloaderTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/GameServices/SteamWorkshopWebpageDownloaderTest.cs @@ -14,8 +14,8 @@ public async Task GetSteamWorkshopsPageHtmlAsync() var html = await downloader.GetSteamWorkshopsPageHtmlAsync(1129810972, CultureInfo.InvariantCulture); var htmlDe = await downloader.GetSteamWorkshopsPageHtmlAsync(1129810972, new CultureInfo("de")); - var lang = html!.GetElementbyId("language_pulldown").InnerText; - var langDe = htmlDe!.GetElementbyId("language_pulldown").InnerText; + var lang = html.GetElementbyId("language_pulldown").InnerText; + var langDe = htmlDe.GetElementbyId("language_pulldown").InnerText; Assert.Equal("language", lang); Assert.Equal("Sprache", langDe); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Games/Registry/GameRegistryIntegrationTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Games/Registry/GameRegistryIntegrationTest.cs index a4a8a5f3..f25fbac3 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Games/Registry/GameRegistryIntegrationTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Games/Registry/GameRegistryIntegrationTest.cs @@ -2,10 +2,10 @@ using System.IO.Abstractions; using AnakinRaW.CommonUtilities.Registry; using AnakinRaW.CommonUtilities.Registry.Windows; +using AnakinRaW.CommonUtilities.Testing.Attributes; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Games.Registry; -using PG.TestingUtilities; using Testably.Abstractions.Testing; using Xunit; diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModBaseTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModBaseTest.cs index 2922d0f4..686f4b23 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModBaseTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModBaseTest.cs @@ -3,54 +3,41 @@ using System.Linq; using AET.Modinfo.Model; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Testing.Mods; -using PG.TestingUtilities; using Xunit; using PG.StarWarsGame.Infrastructure.Services.Dependencies; using PG.StarWarsGame.Infrastructure.Testing; using Semver; using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; namespace PG.StarWarsGame.Infrastructure.Test; public abstract class ModBaseTest : PlayableModContainerTest { - protected IGame Game; + protected IGame Game => GameInstallation.Game; + protected ITestingGameInstallation GameInstallation { get; } protected ModBaseTest() { - Game = CreateRandomGame(); + // ReSharper disable once VirtualMemberCallInConstructor + GameInstallation = GetOrCreateGameInstallation(); } - protected abstract ModBase CreateMod( + protected abstract ITestingModInstallation CreateAndAddModInstallation( string name, DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, params IList deps); - protected IMod CreateOtherMod( - string name, - DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, - params IList deps) - { - return CreateOtherMod(name, GITestUtilities.GetRandomWorkshopFlag(Game), layout, deps); - } - - - protected IMod CreateOtherMod( - string name, - bool isWorkshop, - DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, - params IList deps) - { - return CreateAndAddMod(Game, isWorkshop, name, new DependencyList(deps, layout)); - } [Fact] public void VersionRange_IsNull() { - var mod = CreateMod("Mod"); + var mod = CreateAndAddModInstallation("Mod").Mod; Assert.Null(mod.VersionRange); } @@ -59,9 +46,9 @@ public void VersionRange_IsNull() public void ResolveDependencies_ResolvesCorrectly(ModTestScenarios.TestScenario testScenario) { var mod = ModTestScenarios.CreateTestScenario( - testScenario, - CreateMod, - CreateOtherMod) + testScenario, + (name, layout, dependencies) => CreateAndAddModInstallation(name, layout, dependencies).Mod, + (name, layout, dependencies) => InstallAndAddModWithDependencies(name, layout, dependencies).Mod) .Mod; var expectedDirectDeps = mod.ModInfo!.Dependencies.Select(d => @@ -83,9 +70,9 @@ public void ResolveDependencies_ResolvesCorrectly(ModTestScenarios.TestScenario public void ResolveDependencies_DepNotAdded_Throws_ThenAddingModResolvesCorrectly() { // Do not add mod to game - var notAddedDep = Game.InstallMod("NotAddedMod", false, ServiceProvider); + var notAddedDep = GameInstallation.InstallMod("NotAddedMod", false).Mod; - var mod = CreateMod("Mod", TestHelpers.GetRandomEnum(), notAddedDep); + var mod = CreateAndAddModInstallation("Mod", Random.Enum(), notAddedDep).Mod; Game.AddMod(mod); var e = Assert.Throws(mod.ResolveDependencies); Assert.Same(Game, e.ModContainer); @@ -104,14 +91,14 @@ public void ResolveDependencies_DepNotAdded_Throws_ThenAddingModResolvesCorrectl [Fact] public void ResolveDependencies_DepOfWrongGame_Throws() { - var otherGameReference = new PetroglyphStarWarsGame(Game, Game.Directory, Game.Name, ServiceProvider); - var wrongGameDep = otherGameReference.InstallAndAddMod("WrongGameRefMod", - GITestUtilities.GetRandomWorkshopFlag(otherGameReference), ServiceProvider); - var mod = CreateMod("Mod", TestHelpers.GetRandomEnum(), wrongGameDep); + var otherGameInstallRef = GameInfrastructureTesting.Game(Game, ServiceProvider); + var wrongGameDep = otherGameInstallRef.InstallAndAddMod("WrongGameRefMod"); + + var mod = CreateAndAddModInstallation("Mod", Random.Enum(), wrongGameDep.Mod).Mod; var e = Assert.Throws(mod.ResolveDependencies); Assert.Same(Game, e.ModContainer); - Assert.Equal(wrongGameDep, e.Mod); + Assert.Equal(wrongGameDep.Mod, e.Mod); Assert.Equal(DependencyResolveStatus.Faulted, mod.DependencyResolveStatus); } @@ -119,11 +106,11 @@ public void ResolveDependencies_DepOfWrongGame_Throws() public void ResolveDependencies_VersionMismatch_Throws() { var ws = GITestUtilities.GetRandomWorkshopFlag(Game); - var depLoc = FileSystem.DirectoryInfo.New(Game.GetModDirectory("B", ws, ServiceProvider)); - var dep = Game.InstallMod(depLoc, ws, new ModinfoData("B") { Version = new SemVersion(1) }, ServiceProvider); + var depLoc = GameInstallation.GetModDirectory("B", ws); + var dep = GameInstallation.InstallMod(new ModinfoData("B") { Version = new SemVersion(1) }, depLoc, ws).Mod; Game.AddMod(dep); - var mod = CreateMod("Mod", deps: new ModReference(dep.Identifier, dep.Type, SemVersionRange.AtLeast(new SemVersion(2)))); + var mod = CreateAndAddModInstallation("Mod", deps: new ModReference(dep.Identifier, dep.Type, SemVersionRange.AtLeast(new SemVersion(2)))).Mod; var e = Assert.Throws(mod.ResolveDependencies); Assert.Equal(new ModReference(dep), e.Mod); @@ -135,19 +122,19 @@ public void ResolveDependencies_VersionMismatch_Throws() public void ResolveDependencies_VersionMatch_Throws() { var ws = GITestUtilities.GetRandomWorkshopFlag(Game); - var bLoc = FileSystem.DirectoryInfo.New(Game.GetModDirectory("B", ws, ServiceProvider)); - var cLoc = FileSystem.DirectoryInfo.New(Game.GetModDirectory("C", ws, ServiceProvider)); - var b = Game.InstallMod(bLoc, ws, new ModinfoData("B") { Version = new SemVersion(3) }, ServiceProvider); - var c = Game.InstallMod(cLoc, ws, new ModinfoData("C") { Version = null! }, ServiceProvider); + var bLoc = GameInstallation.GetModDirectory("B", ws); + var cLoc = GameInstallation.GetModDirectory("C", ws); + var b = GameInstallation.InstallMod(new ModinfoData("B") { Version = new SemVersion(3) }, bLoc, ws).Mod; + var c = GameInstallation.InstallMod(new ModinfoData("C") { Version = null! }, cLoc, ws).Mod; Game.AddMod(b); Game.AddMod(c); - var mod = CreateMod("Mod", deps: + var mod = CreateAndAddModInstallation("Mod", deps: [ new ModReference(b.Identifier, b.Type, SemVersionRange.AtLeast(new SemVersion(2))), new ModReference(c.Identifier, c.Type, SemVersionRange.AtLeast(new SemVersion(2))) ] - ); + ).Mod; mod.ResolveDependencies(); Assert.Equal([b, c], mod.Dependencies); @@ -159,8 +146,8 @@ public void ResolveDependencies_RaiseEvent() { var scenario = ModTestScenarios.CreateTestScenario( ModTestScenarios.TestScenario.SingleDepAndTransitive, - CreateMod, - CreateOtherMod); + (name, layout, dependencies) => CreateAndAddModInstallation(name, layout, dependencies).Mod, + (name, layout, dependencies) => InstallAndAddModWithDependencies(name, layout, dependencies).Mod); var mod = scenario.Mod; var b = Game.FindMod(scenario.ExpectedTraversedList![1])!; @@ -187,7 +174,7 @@ public void ResolveDependencies_RaiseEvent() [Fact] public void ResolveDependencies_AlreadyResolved_DoesNotRaiseEvent() { - var mod = CreateMod("A"); + var mod = CreateAndAddModInstallation("A").Mod; mod.ResolveDependencies(); Assert.Equal(DependencyResolveStatus.Resolved, mod.DependencyResolveStatus); @@ -206,11 +193,11 @@ public void ResolveDependencies_AlreadyResolved_DoesNotRaiseEvent() public void ResolveDependencies_Faulted_DoesNotRaiseEvent() { var ws = GITestUtilities.GetRandomWorkshopFlag(Game); - var depLoc = FileSystem.DirectoryInfo.New(Game.GetModDirectory("B", ws, ServiceProvider)); - var dep = Game.InstallMod(depLoc, ws, new ModinfoData("B") { Version = new SemVersion(1) }, ServiceProvider); + var depLoc = GameInstallation.GetModDirectory("B", ws); + var dep = GameInstallation.InstallMod(new ModinfoData("B") { Version = new SemVersion(1) }, depLoc, ws).Mod; Game.AddMod(dep); - var mod = CreateMod("Mod", deps: new ModReference(dep.Identifier, dep.Type, SemVersionRange.AtLeast(new SemVersion(2)))); + var mod = CreateAndAddModInstallation("Mod", deps: new ModReference(dep.Identifier, dep.Type, SemVersionRange.AtLeast(new SemVersion(2)))).Mod; var depsResolvedRaised = false; mod.DependenciesResolved += (_, _) => @@ -243,16 +230,16 @@ private static void AssertDependenciesResolved(IMod mod) [Fact] public void EqualsHashCode() { - var dep = CreateOtherMod("B"); - var mod = CreateMod("A"); - var samish = CreateMod("A"); - var otherA = CreateMod("A", deps: dep); + var dep = GameInstallation.InstallAndAddMod("B").Mod; + var mod = CreateAndAddModInstallation("A").Mod; + var samish = CreateAndAddModInstallation("A").Mod; + var otherA = CreateAndAddModInstallation("A", deps: dep).Mod; ModBase custom = mod.ModInfo is not null ? new CustomMod(Game, mod.Identifier, mod.Type, mod.ModInfo, ServiceProvider) : new CustomMod(Game, mod.Identifier, mod.Type, mod.Name, ServiceProvider); - Assert.False(mod.Equals(null)); + Assert.False(mod.Equals(null!)); Assert.False(mod.Equals((object)null!)); Assert.False(mod.Equals((IModIdentity)null!)); Assert.False(mod.Equals((IModReference)null!)); @@ -281,12 +268,12 @@ public void EqualsHashCode() Assert.True(mod.Equals((IModReference)custom)); } - public class ModBaseAbstractTest : CommonTestBaseWithRandomGame + public class ModBaseAbstractTest : GameInfrastructureTestBaseWithRandomGame { [Fact] public void ResolveDependencies_CalledTwice_Throws() { - var dep = CreateAndAddMod("Dep"); + var dep = GameInstallation.InstallAndAddMod("Dep").Mod; var modinfo = new ModinfoData("CustomMod") { Dependencies = new DependencyList(new List { dep }, DependencyResolveLayout.FullResolved) diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModEqualityComparerTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModEqualityComparerTest.cs index b0d887d2..b187279e 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModEqualityComparerTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModEqualityComparerTest.cs @@ -1,18 +1,17 @@ -using System; -using System.Collections.Generic; -using AET.Modinfo.Model; +using AET.Modinfo.Model; using AET.Modinfo.Spec; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; +using System; +using System.Collections.Generic; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test; -public class ModEqualityComparerTest : CommonTestBaseWithRandomGame +public class ModEqualityComparerTest : GameInfrastructureTestBaseWithRandomGame { [Theory] [InlineData(false, false)] @@ -33,8 +32,8 @@ public void GetHashCode_NullArgs_Throws(bool includeDeps, bool includeGame) [InlineData(true, true)] public void Equals_ModsShouldNeverBeEquals(bool includeDeps, bool includeGame) { - var modA = Game.InstallMod("A", false, ServiceProvider); - var modB = Game.InstallMod("B", false, ServiceProvider); + var modA = GameInstallation.InstallMod("A", false).Mod; + var modB = GameInstallation.InstallMod("B", false).Mod; var comparer = new ModEqualityComparer(includeDeps, includeGame); @@ -53,13 +52,13 @@ public void Equals_ModsShouldNeverBeEquals(bool includeDeps, bool includeGame) [InlineData(true, true)] public void Equals_ShouldAlwaysBeEquals(bool includeDeps, bool includeGame) { - var modA = Game.InstallMod("A", false, ServiceProvider); + var modA = GameInstallation.InstallMod("A", false).Mod; var comparer = new ModEqualityComparer(includeDeps, includeGame); Assert.True(comparer.Equals(modA, modA)); Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(modA)); - var samish = Game.InstallMod("A", false, ServiceProvider); + var samish = GameInstallation.InstallMod("A", false).Mod; Assert.True(comparer.Equals(modA, samish)); Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(samish)); } @@ -70,7 +69,7 @@ public void Equals_ShouldAlwaysBeEquals(bool includeDeps, bool includeGame) public void Equals_DependencyAware(bool depAware) { var dep = new ModReference("B", ModType.Default); - var modA = (IPhysicalMod)CreateAndAddMod("A", deps: dep); + var modA = InstallAndAddModWithDependencies("A", deps: dep).Mod; var sameishModindo = new ModinfoData("A") { @@ -82,7 +81,7 @@ public void Equals_DependencyAware(bool depAware) var differentDep = new Mod(Game, modA.Identifier, modA.Directory, modA.Type == ModType.Workshops, "A", ServiceProvider); - var comparer = new ModEqualityComparer(depAware, TestHelpers.RandomBool()); + var comparer = new ModEqualityComparer(depAware, Random.Bool()); Assert.True(comparer.Equals(modA, modA)); Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(modA)); @@ -106,24 +105,23 @@ public void Equals_DependencyAware(bool depAware) [InlineData(false)] [InlineData(true)] public void Equals_GameAware(bool gameAware) - { - - var modA = CreateAndAddMod("A"); + { + var modA = GameInstallation.InstallAndAddMod("A").Mod; - var sameishGame = new PetroglyphStarWarsGame(Game, Game.Directory, Game.Name, ServiceProvider); - var modSamish = sameishGame.InstallAndAddMod(modA.Name, modA.Type == ModType.Workshops, ServiceProvider); + var otherGameInstallRef = GameInfrastructureTesting.Game(Game, ServiceProvider); + var modSamish = otherGameInstallRef.InstallAndAddMod(modA.Name, modA.Type == ModType.Workshops); - var diffGame = FileSystem.InstallGame( - new GameIdentity(Game.Type == GameType.Eaw ? GameType.Foc : GameType.Eaw, Game.Platform), ServiceProvider); + var diffGame = GameInfrastructureTesting + .Game(new GameIdentity(Game.Type == GameType.Eaw ? GameType.Foc : GameType.Eaw, Game.Platform), ServiceProvider); - var diffGameMod = diffGame.InstallMod("A", modA.Type == ModType.Workshops, ServiceProvider); + var diffGameMod = diffGame.InstallMod("A", modA.Type == ModType.Workshops).Mod; - var comparer = new ModEqualityComparer(TestHelpers.RandomBool(), gameAware); + var comparer = new ModEqualityComparer(Random.Bool(), gameAware); Assert.True(comparer.Equals(modA, modA)); Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(modA)); - Assert.True(comparer.Equals(modA, modSamish)); - Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(modSamish)); + Assert.True(comparer.Equals(modA, modSamish.Mod)); + Assert.Equal(comparer.GetHashCode(modA), comparer.GetHashCode(modSamish.Mod)); if (gameAware) { @@ -140,7 +138,7 @@ public void Equals_GameAware(bool gameAware) [Fact] public void ToJson() { - var mod = CreateAndAddMod("A"); + var mod = GameInstallation.InstallAndAddMod("A").Mod; var expected = new ModReference(mod).ToJson(); Assert.Equal(expected, mod.ToJson()); } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyGraphBuilderTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyGraphBuilderTest.cs index 1ee26001..c8aaf0d2 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyGraphBuilderTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyGraphBuilderTest.cs @@ -2,18 +2,16 @@ using System.Collections.Generic; using AET.Modinfo.Model; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Dependencies; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Semver; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices.Dependencies; -public class ModDependencyGraphBuilderTest : CommonTestBaseWithRandomGame +public class ModDependencyGraphBuilderTest : GameInfrastructureTestBaseWithRandomGame { private readonly ModDependencyGraphBuilder _graphBuilder = new(); @@ -26,7 +24,7 @@ public void NullArgs_Throws() [Fact] public void Build_NoDependencies() { - var mod = CreateAndAddMod("A"); + var mod = GameInstallation.InstallAndAddMod("A").Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -36,8 +34,8 @@ public void Build_NoDependencies() [Fact] public void Build_OneDependency() { - var b = CreateAndAddMod("B"); - var mod = CreateAndAddMod("A", TestHelpers.GetRandomEnum(), b); + var b = GameInstallation.InstallAndAddMod("B").Mod; + var mod = InstallAndAddModWithDependencies("A", Random.Enum(), b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -59,9 +57,9 @@ public void Build_OneDependency() public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_FullResolved() { // C is not added to game. Building a graph should not throw, because it's not used. - var c = Game.InstallMod("C", false, ServiceProvider); - var b = CreateAndAddMod("B", DependencyResolveLayout.FullResolved, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.FullResolved, b); + var c = GameInstallation.InstallMod("C", false).Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.FullResolved, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.FullResolved, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -82,9 +80,9 @@ public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_FullResolved() [Fact] public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveRecursive() { - var c = CreateAndAddMod("C"); - var b = CreateAndAddMod("B", DependencyResolveLayout.FullResolved, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var c = GameInstallation.InstallAndAddMod("C").Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.FullResolved, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -107,10 +105,10 @@ public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveRecursive() [Fact] public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveLastItem_Variant1() { - var d = CreateAndAddMod("D"); - var c = CreateAndAddMod("C"); - var b = CreateAndAddMod("B", DependencyResolveLayout.FullResolved, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveLastItem, b, d); + var d = GameInstallation.InstallAndAddMod("D").Mod; + var c = GameInstallation.InstallAndAddMod("C").Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.FullResolved, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveLastItem, b, d).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -133,10 +131,10 @@ public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveLastItem_Var [Fact] public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveLastItem_Variant2() { - var d = CreateAndAddMod("D"); - var c = CreateAndAddMod("C"); - var b = CreateAndAddMod("B", DependencyResolveLayout.FullResolved, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveLastItem, d, b); + var d = GameInstallation.InstallAndAddMod("D").Mod; + var c = GameInstallation.InstallAndAddMod("C").Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.FullResolved, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveLastItem, d, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -162,10 +160,10 @@ public void Build_GraphContainsOnlyVerticesAsDefinedByLayout_ResolveLastItem_Var [Fact] public void Build_ResolveLayoutFromTransitiveApplied_ResolveRecursive() { - var d = CreateAndAddMod("D"); - var c = CreateAndAddMod("C", DependencyResolveLayout.FullResolved, d); - var b = CreateAndAddMod("B", DependencyResolveLayout.ResolveRecursive, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var d = GameInstallation.InstallAndAddMod("D").Mod; + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.FullResolved, d).Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.ResolveRecursive, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -191,11 +189,11 @@ public void Build_ResolveLayoutFromTransitiveApplied_ResolveRecursive() [Fact] public void Build_ResolveLayoutFromTransitiveApplied_ResolveLastItem_Variant1() { - var e = CreateAndAddMod("E"); - var d = CreateAndAddMod("D"); - var c = CreateAndAddMod("C", DependencyResolveLayout.FullResolved, d); - var b = CreateAndAddMod("B", DependencyResolveLayout.ResolveLastItem, e, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var e = GameInstallation.InstallAndAddMod("E").Mod; + var d = GameInstallation.InstallAndAddMod("D").Mod; + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.FullResolved, d).Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.ResolveLastItem, e, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -224,11 +222,11 @@ public void Build_ResolveLayoutFromTransitiveApplied_ResolveLastItem_Variant1() [Fact] public void Build_ResolveLayoutFromTransitiveApplied_ResolveLastItem_Variant2() { - var e = CreateAndAddMod("E"); - var d = CreateAndAddMod("D"); - var c = CreateAndAddMod("C", DependencyResolveLayout.FullResolved, d); - var b = CreateAndAddMod("B", DependencyResolveLayout.ResolveLastItem, c, e); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var e = GameInstallation.InstallAndAddMod("E").Mod; + var d = GameInstallation.InstallAndAddMod("D").Mod; + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.FullResolved, d).Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.ResolveLastItem, c, e).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var graph = _graphBuilder.Build(mod); Assert.False(graph.HasCycle()); @@ -260,9 +258,9 @@ public void Build_DirectCycle() Dependencies = new DependencyList(new List { depA - }, TestHelpers.GetRandomEnum()) + }, Random.Enum()) }; - var mod = Game.InstallAndAddMod(false, modinfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modinfo, false).Mod; var graph = _graphBuilder.Build(mod); Assert.True(graph.HasCycle()); @@ -273,7 +271,7 @@ public void Build_TransitiveCycle() { var depA = new ModReference("A", ModType.Default); - var b = CreateAndAddMod("B", TestHelpers.GetRandomEnum(), depA); + var b = InstallAndAddModWithDependencies("B", Random.Enum(), depA).Mod; var modinfo = new ModinfoData("A") { @@ -282,7 +280,7 @@ public void Build_TransitiveCycle() b }, DependencyResolveLayout.ResolveRecursive) }; - var mod = Game.InstallAndAddMod(false, modinfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modinfo, false).Mod; var graph = _graphBuilder.Build(mod); Assert.True(graph.HasCycle()); @@ -291,7 +289,7 @@ public void Build_TransitiveCycle() [Fact] public void Build_SelfNotFound_Throws() { - var mod = Game.InstallMod("A", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var mod = GameInstallation.InstallMod("A").Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Same(Game, e.ModContainer); Assert.Equal(mod, e.Mod); @@ -300,8 +298,8 @@ public void Build_SelfNotFound_Throws() [Fact] public void Build_DirectDependencyNotFound_Throws() { - var b = Game.InstallMod("B", false, ServiceProvider); - var mod = CreateAndAddMod("A", TestHelpers.GetRandomEnum(), b); + var b = GameInstallation.InstallMod("B", false).Mod; + var mod = InstallAndAddModWithDependencies("A", Random.Enum(), b).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Same(Game, e.ModContainer); Assert.Equal(b, e.Mod); @@ -310,9 +308,9 @@ public void Build_DirectDependencyNotFound_Throws() [Fact] public void Build_TransitiveDependencyNotFound_Throws() { - var c = Game.InstallMod("C", false, ServiceProvider); - var b = CreateAndAddMod("B", DependencyResolveLayout.FullResolved, c); - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var c = GameInstallation.InstallMod("C", false).Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.FullResolved, c).Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Same(Game, e.ModContainer); Assert.Equal(c, e.Mod); @@ -335,11 +333,11 @@ public static IEnumerable GetMatchingVersionRanges() [MemberData(nameof(GetMatchingVersionRanges))] public void Build_OneDependency_VersionRangeMatches(SemVersion? version, SemVersionRange ranges) { - var b = CreateAndAddMod(new ModinfoData("B") { Version = version }); + var b = GetOrCreateGameInstallation().InstallAndAddMod(new ModinfoData("B") { Version = version }).Mod; Assert.Equal(version, b.Version); - var mod = CreateAndAddMod("A", TestHelpers.GetRandomEnum(), - new ModReference(b.Identifier, b.Type, ranges)); + var mod = InstallAndAddModWithDependencies("A", Random.Enum(), + new ModReference(b.Identifier, b.Type, ranges)).Mod; var graph = _graphBuilder.Build(mod); @@ -382,14 +380,14 @@ public static IEnumerable GetMismatchingVersionsAndRange() [MemberData(nameof(GetMismatchingVersionsAndRange))] public void Build_OneDependency_VersionRangeDoesNotMatches_Throws(SemVersion version, SemVersionRange? range) { - var b = CreateAndAddMod(new ModinfoData("B") + var b = GetOrCreateGameInstallation().InstallAndAddMod(new ModinfoData("B") { Version = version - }); + }).Mod; Assert.Equal(version, b.Version); - var mod = CreateAndAddMod("A", TestHelpers.GetRandomEnum(), - new ModReference(b.Identifier, b.Type, range)); + var mod = InstallAndAddModWithDependencies("A", Random.Enum(), + new ModReference(b.Identifier, b.Type, range)).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Equal(new ModReference(b), e.Mod); @@ -400,15 +398,15 @@ public void Build_OneDependency_VersionRangeDoesNotMatches_Throws(SemVersion ver [MemberData(nameof(GetMismatchingVersionsAndRange))] public void Build_TransitiveDependency_VersionRangeDoesNotMatches_Throws(SemVersion version, SemVersionRange? range) { - var c = CreateAndAddMod(new ModinfoData("C") + var c = GetOrCreateGameInstallation().InstallAndAddMod(new ModinfoData("C") { Version = version - }); + }).Mod; Assert.Equal(version, c.Version); - var b = CreateAndAddMod("B", deps: new List{new ModReference(c.Identifier, c.Type, range)}); + var b = InstallAndAddModWithDependencies("B", deps: new List{new ModReference(c.Identifier, c.Type, range)}).Mod; - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, b); + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, b).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Equal(new ModReference(c), e.Mod); @@ -428,16 +426,16 @@ public void Build_VersionMismatchInOnlyOneRef_WhereEqualRefHasMatchingVersion_Th \^ C */ - var b = CreateAndAddMod(new ModinfoData("B") { Version = new SemVersion(1, 0, 0) }); + var b = GetOrCreateGameInstallation().InstallAndAddMod(new ModinfoData("B") { Version = new SemVersion(1, 0, 0) }).Mod; - var c = CreateAndAddMod("C", - deps: new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(2, 0, 0)))); + var c = InstallAndAddModWithDependencies("C", + deps: new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(2, 0, 0)))).Mod; - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, deps: + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, deps: [ new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(1, 0, 0))), c - ]); + ]).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Equal(new ModReference(b), e.Mod); Assert.Equal(b, e.Dependency); @@ -456,16 +454,16 @@ public void Build_VersionMismatchInOnlyOneRef_WhereEqualRefHasMatchingVersion_Th > C */ - var b = CreateAndAddMod(new ModinfoData("B") { Version = new SemVersion(1, 0, 0) }); + var b = GetOrCreateGameInstallation().InstallAndAddMod(new ModinfoData("B") { Version = new SemVersion(1, 0, 0) }).Mod; - var c = CreateAndAddMod("C", DependencyResolveLayout.ResolveRecursive, - deps: new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(2, 0, 0)))); + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.ResolveRecursive, + deps: new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(2, 0, 0)))).Mod; - var mod = CreateAndAddMod("A", DependencyResolveLayout.ResolveRecursive, deps: + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.ResolveRecursive, deps: [ c, // Before b in this variant new ModReference(b.Identifier, b.Type, SemVersionRange.Equals(new SemVersion(1, 0, 0))) - ]); + ]).Mod; var e = Assert.Throws(() => _graphBuilder.Build(mod)); Assert.Equal(new ModReference(b), e.Mod); Assert.Equal(b, e.Dependency); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyResolverTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyResolverTest.cs index 241f9f26..ff631831 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyResolverTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyResolverTest.cs @@ -4,14 +4,12 @@ using AET.Modinfo.Spec; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Dependencies; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices.Dependencies; -public class ModDependencyResolverTest : CommonTestBaseWithRandomGame +public class ModDependencyResolverTest : GameInfrastructureTestBaseWithRandomGame { private readonly ModDependencyResolver _resolver; @@ -30,7 +28,7 @@ public void InvalidArgs_Throws() [Fact] public void Resolve_NoDependencies() { - var mod = CreateMod("A"); + var mod = GameInstallation.InstallAndAddMod("A").Mod; var dependencies = _resolver.Resolve(mod); Assert.Empty(dependencies); } @@ -45,7 +43,7 @@ public void Resolve_DependencyNot_Found() new ModReference("B", ModType.Default) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(false, modinfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modinfo, false).Mod; Assert.Throws(() => _resolver.Resolve(mod)); } @@ -61,15 +59,15 @@ public void Resolve_SelfDependency_WithCycleCheck_Throws() depA }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(false, modinfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modinfo, false).Mod; Assert.Throws(() => _resolver.Resolve(mod)); } [Fact] public void Resolve_SingleDependency() { - var dep = CreateMod("B"); - var mod = CreateMod("A", DependencyResolveLayout.FullResolved, new ModReference(dep)); + var dep = GameInstallation.InstallAndAddMod("B").Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.FullResolved, new ModReference(dep)).Mod; var deps = _resolver.Resolve(mod); @@ -80,9 +78,9 @@ public void Resolve_SingleDependency() [Fact] public void Resolve_TwoDependency() { - var b = CreateMod("B"); - var c = CreateMod("C"); - var mod = CreateMod("A", DependencyResolveLayout.FullResolved, b, c); + var b = GameInstallation.InstallAndAddMod("B").Mod; + var c = GameInstallation.InstallAndAddMod("C").Mod; + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.FullResolved, b, c).Mod; var deps = _resolver.Resolve(mod); @@ -92,12 +90,12 @@ public void Resolve_TwoDependency() [Fact] public void Resolve_ResolveCompleteChain_DependenciesHaveDeps_ButResolveLayoutIsFullResolved() { - var b2 = CreateMod("B2"); - var b = CreateMod("B", DependencyResolveLayout.ResolveRecursive, b2); - var c2 = CreateMod("C2"); - var c = CreateMod("C", DependencyResolveLayout.ResolveRecursive, c2); + var b2 = GameInstallation.InstallAndAddMod("B2").Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.ResolveRecursive, b2).Mod; + var c2 = GameInstallation.InstallAndAddMod("C2").Mod; + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.ResolveRecursive, c2).Mod; // Layout is recursive - var mod = CreateMod("A", DependencyResolveLayout.FullResolved, b, c); + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.FullResolved, b, c).Mod; var deps = _resolver.Resolve(mod); @@ -112,30 +110,17 @@ public void Resolve_ResolveCompleteChain_DependenciesHaveDeps_ButResolveLayoutIs [Fact] public void Resolve_ResolveCompleteChain_DependenciesHaveResolvedDeps_ButResolveLayoutIsFullResolved() { - var b2 = CreateMod("B2"); - var b = CreateMod("B", DependencyResolveLayout.ResolveRecursive, b2); + var b2 = GameInstallation.InstallAndAddMod("B2").Mod; + var b = InstallAndAddModWithDependencies("B", DependencyResolveLayout.ResolveRecursive, b2).Mod; b.ResolveDependencies(); - var c2 = CreateMod("C2"); - var c = CreateMod("C", DependencyResolveLayout.ResolveRecursive, c2); + var c2 = GameInstallation.InstallAndAddMod("C2").Mod; + var c = InstallAndAddModWithDependencies("C", DependencyResolveLayout.ResolveRecursive, c2).Mod; c.ResolveDependencies(); - var mod = CreateMod("A", DependencyResolveLayout.FullResolved, b, c); + var mod = InstallAndAddModWithDependencies("A", DependencyResolveLayout.FullResolved, b, c).Mod; var deps = _resolver.Resolve(mod); // Only b and c, because a has layout FullResolved Assert.Equal([b, c], deps); } - - private IMod CreateMod(string name, DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, params IModReference[] deps) - { - if (deps.Length == 0) - return Game.InstallAndAddMod(name, GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - - var modinfo = new ModinfoData("A") - { - Dependencies = new DependencyList(deps, layout) - }; - - return Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modinfo, ServiceProvider); - } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyTraverserTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyTraverserTest.cs index 054fd1fe..a58e72af 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyTraverserTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/Dependencies/ModDependencyTraverserTest.cs @@ -1,16 +1,14 @@ using System; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Dependencies; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices.Dependencies; -public class ModDependencyTraverserTest : CommonTestBaseWithRandomGame +public class ModDependencyTraverserTest : GameInfrastructureTestBaseWithRandomGame { private readonly ModDependencyTraverser _traverser; @@ -21,6 +19,7 @@ public ModDependencyTraverserTest() _traverser = new ModDependencyTraverser(ServiceProvider); } + [Theory] [MemberData(nameof(ModTestScenarios.ValidScenarios), MemberType = typeof(ModTestScenarios))] public void Traverse_ValidScenarios(ModTestScenarios.TestScenario testScenario) @@ -28,8 +27,8 @@ public void Traverse_ValidScenarios(ModTestScenarios.TestScenario testScenario) var scenario = ModTestScenarios.CreateTestScenario( testScenario, - CreateAndAddMod, - CreateAndAddMod); + (name, layout, dependencies) => InstallAndAddModWithDependencies(name, layout, dependencies).Mod, + (name, layout, dependencies) => InstallAndAddModWithDependencies(name, layout, dependencies).Mod); var mod = scenario.Mod; mod.ResolveDependencies(); @@ -38,14 +37,14 @@ public void Traverse_ValidScenarios(ModTestScenarios.TestScenario testScenario) Assert.Equal(scenario.ExpectedTraversedList, traversedList); } - + [Fact] public void Traverse_FaultedResolvedMod_Throws() { // Do not add to provoke faulted - var dep = Game.InstallMod("B", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var dep = GameInstallation.InstallMod("B").Mod; - var mod = CreateAndAddMod("Mod", TestHelpers.GetRandomEnum(), dep); + var mod = InstallAndAddModWithDependencies("Mod", Random.Enum(), dep).Mod; try { @@ -64,8 +63,8 @@ public void Traverse_FaultedResolvedMod_Throws() public void Traverse_NotResolvedMod_Throws() { // Do not add to provoke faulted - var dep = Game.InstallMod("B", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - var mod = CreateAndAddMod("Mod", TestHelpers.GetRandomEnum(), dep); + var dep = GameInstallation.InstallMod("B").Mod; + var mod = InstallAndAddModWithDependencies("Mod", Random.Enum(), dep).Mod; Assert.Equal(DependencyResolveStatus.None, mod.DependencyResolveStatus); Assert.Throws(() => _traverser.Traverse(mod)); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/DirectoryModNameResolverTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/DirectoryModNameResolverTest.cs index f6d54da7..01eedd59 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/DirectoryModNameResolverTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/DirectoryModNameResolverTest.cs @@ -38,7 +38,7 @@ public void Ctor_NullArgs_Throws() [Theory] [InlineData("path/1125718579", "z3r0x's mod version 3.5")] - [InlineData("path/2508288191", "Empire at War Expanded: Deep Core 3.1")] + [InlineData("path/2978074984", "EAWFOC Mod Template")] public void ResolveName_Steam_WithoutModinfo_FindNameOnline(string path, string containsExpected) { var modRef = CreateDetectedModReference(path, ModType.Workshops, null); @@ -53,7 +53,7 @@ public void ResolveName_Steam_WithoutModinfo_FindNameOnline(string path, string } } -public abstract class ModNameResolverTestBase : CommonTestBase +public abstract class ModNameResolverTestBase : GameInfrastructureTestBase { public abstract ModNameResolverBase CreateResolver(); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFactoryTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFactoryTest.cs index b9f42c25..1e8e6dc2 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFactoryTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFactoryTest.cs @@ -2,28 +2,29 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.IO.Abstractions; using System.Text.Json; using AET.Modinfo; using AET.Modinfo.Model; using AET.Modinfo.Spec; using AET.Modinfo.Spec.Steam; using AET.Modinfo.Utilities; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services; using PG.StarWarsGame.Infrastructure.Services.Name; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Semver; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices; -public class ModFactoryTest : CommonTestBase +public class ModFactoryTest : GameInfrastructureTestBase { private const string DefaultModName = "Default Mod Name"; private const string SteamModName = "Steam Mod Name"; @@ -36,10 +37,10 @@ public ModFactoryTest() _factory = new ModFactory(ServiceProvider); } - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(_ => _nameResolver); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_ => _nameResolver); } #region CreatePhysicalMod @@ -47,8 +48,9 @@ protected override void SetupServiceProvider(IServiceCollection sc) [Fact] public void CreatePhysicalMod_NullArgs_Throws() { - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - var modData = CreateDetectedModReference(game, "path", null, null); + var gameInstallation = GetOrCreateGameInstallation(); + var game = gameInstallation.Game; + var modData = CreateDetectedModReference(gameInstallation, FileSystem.DirectoryInfo.New("path"), null, null); Assert.Throws(() => _factory.CreatePhysicalMod(null!, modData, CultureInfo.CurrentCulture)); Assert.Throws(() => _factory.CreatePhysicalMod(game, null!, CultureInfo.CurrentCulture)); @@ -58,7 +60,7 @@ public void CreatePhysicalMod_NullArgs_Throws() [Fact] public void CreatePhysicalMod_VirtualMod_Throws() { - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); + var game = GetOrCreateGameInstallation().Game; var modDir = FileSystem.DirectoryInfo.New("path"); modDir.Create(); var modData = new DetectedModReference(new ModReference("SOME_ID", ModType.Virtual), modDir, null); @@ -68,20 +70,22 @@ public void CreatePhysicalMod_VirtualMod_Throws() [Fact] public void CreatePhysicalMod_ModDirectoryNotFound_Throws() { - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - var modData = CreateDetectedModReference(game, "path", null, null); + var gameInstallation = GetOrCreateGameInstallation(); + var game = gameInstallation.Game; + var modData = CreateDetectedModReference(gameInstallation, FileSystem.DirectoryInfo.New("path"), null, null); modData.Directory.Delete(true); Assert.Throws(() => _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreatePhysicalMod_FromModsDir_WithoutModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var modDir = game.GetModDirectory("Mod_Name", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var modDir = gameInstallation.GetModDirectory("Mod_Name", false); - var modData = CreateDetectedModReference(game, modDir, false, null); + var modData = CreateDetectedModReference(gameInstallation, modDir, false, null); var mod = _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture); Assert.Null(mod.ModInfo); @@ -91,15 +95,16 @@ public void CreatePhysicalMod_FromModsDir_WithoutModinfo(GameIdentity gameIdenti } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreatePhysicalMod_FromModsDir_WithModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var modDir = game.GetModDirectory("Mod_Name", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var modDir = gameInstallation.GetModDirectory("Mod_Name", false); var modinfo = new ModinfoData("MyMod"); - var modData = CreateDetectedModReference(game, modDir, false, modinfo); + var modData = CreateDetectedModReference(gameInstallation, modDir, false, modinfo); var mod = _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture); Assert.Same(modinfo, mod.ModInfo); @@ -113,12 +118,13 @@ public void CreatePhysicalMod_FromModsDir_WithModinfo(GameIdentity gameIdentity) [InlineData(GameType.Foc)] public void CreatePhysicalMod_Steam_WithoutModinfo(GameType gameType) { - var game = FileSystem.InstallGame(new GameIdentity(gameType, GamePlatform.SteamGold), ServiceProvider); - var modDir = game.GetModDirectory("Mod_Name", true, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, GamePlatform.SteamGold)); + var game = gameInstallation.Game; + var modDir = gameInstallation.GetModDirectory("Mod_Name", true); var modinfo = new ModinfoData("MyMod"); - var modRef = CreateDetectedModReference(game, modDir, true, modinfo); + var modRef = CreateDetectedModReference(gameInstallation, modDir, true, modinfo); var mod = _factory.CreatePhysicalMod(game, modRef, CultureInfo.CurrentCulture); Assert.Same(modinfo, mod.ModInfo); @@ -132,10 +138,11 @@ public void CreatePhysicalMod_Steam_WithoutModinfo(GameType gameType) [InlineData(GameType.Foc)] public void CreatePhysicalMod_Steam_WithModinfo(GameType gameType) { - var game = FileSystem.InstallGame(new GameIdentity(gameType, GamePlatform.SteamGold), ServiceProvider); - var modDir = game.GetModDirectory("Mod_Name", true, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, GamePlatform.SteamGold)); + var game = gameInstallation.Game; + var modDir = gameInstallation.GetModDirectory("Mod_Name", true); - var modRef = CreateDetectedModReference(game, modDir, true, null); + var modRef = CreateDetectedModReference(gameInstallation, modDir, true, null); var mod = _factory.CreatePhysicalMod(game, modRef, CultureInfo.CurrentCulture); Assert.Null(mod.ModInfo); @@ -145,46 +152,47 @@ public void CreatePhysicalMod_Steam_WithModinfo(GameType gameType) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreatePhysicalMod_WithInvalidModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var ws = GITestUtilities.GetRandomWorkshopFlag(game); - var modDir = game.GetModDirectory("Mod_Name", ws, ServiceProvider); + var modDir = gameInstallation.GetModDirectory("Mod_Name", ws); var invalidModinfo = new CustomModInfo(string.Empty); // string.Empty is not valid - var modData = CreateDetectedModReference(game, modDir, ws, invalidModinfo); + var modData = CreateDetectedModReference(gameInstallation, modDir, ws, invalidModinfo); Assert.Throws(() => _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreatePhysicalMod_InvalidNameResolved_Throws(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var ws = GITestUtilities.GetRandomWorkshopFlag(game); - var modDir = game.GetModDirectory("Mod_Name", ws, ServiceProvider); - var modData = CreateDetectedModReference(game, modDir, ws, null); + var modDir = gameInstallation.GetModDirectory("Mod_Name", ws); + var modData = CreateDetectedModReference(gameInstallation, modDir, ws, null); _nameResolver.ReturnCorrectName = false; Assert.Throws(() => _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreatePhysicalMod_ModNotCompatible_Throws(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; + + var otherGameInstallation = GameInfrastructureTesting + .Game(new GameIdentity(gameIdentity.Type.Opposite(), Random.Item(GITestUtilities.RealPlatforms)), ServiceProvider); - var oppositeGameType = gameIdentity.Type == GameType.Eaw ? GameType.Foc : GameType.Eaw; - var otherGame = FileSystem.InstallGame( - new GameIdentity(oppositeGameType, TestHelpers.GetRandom(GITestUtilities.RealPlatforms)), ServiceProvider); - - var modDir = otherGame.GetModDirectory("Mod_Name", false, ServiceProvider); - var modData = CreateDetectedModReference(otherGame, modDir, false, null); + var modDir = otherGameInstallation.GetModDirectory("Mod_Name", false); + var modData = CreateDetectedModReference(otherGameInstallation, modDir, false, null); Assert.Throws(() => _factory.CreatePhysicalMod(game, modData, CultureInfo.CurrentCulture)); } @@ -196,8 +204,9 @@ public void CreatePhysicalMod_ModNotCompatible_Throws(GameIdentity gameIdentity) [Fact] public void CreateVirtualMod_NullArgs_Throws() { - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - var dep = game.InstallMod("dep", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(); + var game = gameInstallation.Game; + var dep = gameInstallation.InstallMod("dep", false).Mod; Assert.Throws(() => _factory.CreateVirtualMod(null!, new ModinfoData("Name") { @@ -207,11 +216,12 @@ public void CreateVirtualMod_NullArgs_Throws() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateVirtualMod_WithInvalidModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var dep = game.InstallMod("dep", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var dep = gameInstallation.InstallMod("dep", false).Mod; var invalidModinfo = new CustomModInfo(string.Empty) { @@ -222,10 +232,10 @@ public void CreateVirtualMod_WithInvalidModinfo(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateVirtualMod_WithInvalidModinfo_NoDependencies(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var invalidModinfo = new CustomModInfo("MyVirtualMod") { @@ -236,11 +246,12 @@ public void CreateVirtualMod_WithInvalidModinfo_NoDependencies(GameIdentity game } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void CreateVirtualMod(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var dep = game.InstallMod("dep", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var dep = gameInstallation.InstallMod("dep", false).Mod; var modinfo = new CustomModInfo("VirtualModName") { @@ -258,10 +269,10 @@ public void CreateVirtualMod(GameIdentity gameIdentity) #endregion - protected DetectedModReference CreateDetectedModReference(IGame game, string path, bool? isWorkshop, IModinfo? modinfo) + protected DetectedModReference CreateDetectedModReference(ITestingGameInstallation gameInstallation, IDirectoryInfo path, bool? isWorkshop, IModinfo? modinfo) { - var mod = game.InstallMod(FileSystem.DirectoryInfo.New(path), isWorkshop ?? GITestUtilities.GetRandomWorkshopFlag(game), - new ModinfoData("MyMod"), ServiceProvider); + var workshop = isWorkshop ?? GITestUtilities.GetRandomWorkshopFlag(gameInstallation.Game); + var mod = gameInstallation.InstallMod(new ModinfoData("MyMod"), path, workshop).Mod; return new DetectedModReference(new ModReference(mod), mod.Directory, modinfo); } @@ -294,7 +305,7 @@ public bool Equals(IModIdentity? other) } public string Name { get; } = name; - public SemVersion? Version { get; } + public SemVersion? Version => null; public IModDependencyList Dependencies { get; init; } = DependencyList.EmptyDependencyList; public string ToJson() { @@ -306,12 +317,12 @@ public void ToJson(Stream stream) JsonSerializer.Serialize(stream, this, JsonSerializerOptions.Default); } - public string? Summary { get; } - public string? Icon { get; } + public string? Summary => null; + public string? Icon => null; public IDictionary Custom { get; } = new Dictionary(); - public ISteamData? SteamData { get; } + public ISteamData? SteamData => null; public IReadOnlyCollection Languages { get; } = new List(); - public bool LanguagesExplicitlySet { get; } + public bool LanguagesExplicitlySet => false; } } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFinderTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFinderTest.cs index 394d75a2..c1c22429 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFinderTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModFinderTest.cs @@ -7,22 +7,21 @@ using AET.Modinfo.Spec; using AET.Modinfo.Spec.Steam; using AET.Modinfo.Utilities; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; 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 PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Semver; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices; -public class ModFinderTest : CommonTestBase +public class ModFinderTest : GameInfrastructureTestBase { private readonly ModFinder _modFinder; private readonly ISteamGameHelpers _steamGameHelpers; @@ -38,25 +37,24 @@ public void FindMods_NullArg_Throws() { Assert.Throws(() => _modFinder.FindMods(null!)); Assert.Throws(() => _modFinder.FindMods(null!, FileSystem.Directory.CreateDirectory("path"))); - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - Assert.Throws(() => _modFinder.FindMods(game, null!)); + Assert.Throws(() => _modFinder.FindMods(GetOrCreateGameInstallation().Game, null!)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_GameNotExists_Throws(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; game.Directory.Delete(true); Assert.Throws(() => _modFinder.FindMods(game)); Assert.Throws(() => _modFinder.FindMods(game, FileSystem.DirectoryInfo.New("path"))); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_NoModsDirectory_ShouldNotFindMods(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; game.ModsLocation.Delete(true); if (game.Platform is GamePlatform.SteamGold) @@ -73,10 +71,10 @@ public void FindMods_NoModsDirectory_ShouldNotFindMods(GameIdentity gameIdentity } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_EmptyModsDirectory_ShouldNotFindMods(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; game.ModsLocation.Create(); if (game.Platform is GamePlatform.SteamGold) @@ -90,11 +88,13 @@ public void FindMods_EmptyModsDirectory_ShouldNotFindMods(GameIdentity gameIdent } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_OneMod_WithoutModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + + var expectedMod = gameInstallation.InstallMod("MyMod").Mod; var installedMods = _modFinder.FindMods(game); AssertSingleFoundMod(installedMods, expectedMod, expectedMod.Directory.Name, null); @@ -104,13 +104,15 @@ public void FindMods_OneMod_WithoutModinfo(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_OneMod_WithInvalidModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; - var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); - expectedMod.InstallInvalidModinfoFile(); + var expectedModInstallation = gameInstallation.InstallMod("MyMod"); + expectedModInstallation.InstallInvalidModinfoFile(); + var expectedMod = expectedModInstallation.Mod; var installedMods = _modFinder.FindMods(game); AssertSingleFoundMod(installedMods, expectedMod, expectedMod.Directory.Name, null); @@ -120,16 +122,18 @@ public void FindMods_OneMod_WithInvalidModinfo(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_OneMod_WithOneInvalidModinfoVariant(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; - var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var expectedModInstallation = gameInstallation.InstallMod("MyMod"); var expectedModinfo = new ModinfoData("Variant1"); + var expectedMod = expectedModInstallation.Mod; - expectedMod.InstallModinfoFile(expectedModinfo, "variant1"); - expectedMod.InstallInvalidModinfoFile("variant2"); + expectedModInstallation.InstallModinfoFile(expectedModinfo, "variant1"); + expectedModInstallation.InstallInvalidModinfoFile("variant2"); var installedMods = _modFinder.FindMods(game); AssertSingleFoundMod(installedMods, expectedMod, $"{expectedMod.Directory.Name}:Variant1", expectedModinfo); @@ -139,14 +143,16 @@ public void FindMods_OneMod_WithOneInvalidModinfoVariant(GameIdentity gameIdenti } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_OneMod_WithMainModinfo(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var modinfoData = new ModinfoData("MyMod"); - var expectedMod = game.InstallMod(GITestUtilities.GetRandomWorkshopFlag(game), modinfoData, ServiceProvider); - expectedMod.InstallModinfoFile(modinfoData); + var expectedModInstallation = gameInstallation.InstallMod(modinfoData); + expectedModInstallation.InstallModinfoFile(modinfoData); + var expectedMod = expectedModInstallation.Mod; var installedMods = _modFinder.FindMods(game); AssertSingleFoundMod(installedMods, expectedMod, expectedMod.Directory.Name, modinfoData); @@ -156,16 +162,18 @@ public void FindMods_OneMod_WithMainModinfo(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_WithOnlyManyVariantModinfos(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; 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 expectedModInstallation = gameInstallation.InstallMod("DirName"); + expectedModInstallation.InstallModinfoFile(info1, "variant1"); + expectedModInstallation.InstallModinfoFile(info2, "variant2"); + var expectedMod = expectedModInstallation.Mod; var installedMods = _modFinder.FindMods(game).ToList(); AssertMultipleModsOfSameLocation( @@ -189,18 +197,20 @@ public void FindMods_WithOnlyManyVariantModinfos(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_WithMainAndManyVariantModinfos(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; 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 expectedModInstallation = gameInstallation.InstallMod("DirName"); + expectedModInstallation.InstallModinfoFile(main); + expectedModInstallation.InstallModinfoFile(info1, "variant1"); + expectedModInstallation.InstallModinfoFile(info2, "variant2"); + var expectedMod = expectedModInstallation.Mod; var installedMods = _modFinder.FindMods(game).ToList(); AssertMultipleModsOfSameLocation( @@ -222,12 +232,14 @@ public void FindMods_WithMainAndManyVariantModinfos(GameIdentity gameIdentity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_FindAllInstalledMods(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var mod1 = game.InstallMod("Mod1", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); - var mod2 = game.InstallMod("Mod2", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + + var mod1 = gameInstallation.InstallMod("Mod1").Mod; + var mod2 = gameInstallation.InstallMod("Mod2").Mod; var expectedDirs = new[] {mod1.Directory.FullName, mod2.Directory.FullName}; var expectedIds = new[] {mod1.Directory.Name, mod2.Directory.Name}; @@ -244,13 +256,15 @@ public void FindMods_FindAllInstalledMods(GameIdentity gameIdentity) [InlineData(GameType.Foc)] public void FindMods_Steam_ShouldAddWorkshopsAndMods(GameType type) { - var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(type, GamePlatform.SteamGold)); + var game = gameInstallation.Game; - var steamMod = game.InstallMod("SteamMod", true, ServiceProvider); + var steamMod = gameInstallation.InstallMod("SteamMod", true).Mod; var modinfo = new ModinfoData("Name"); - var defaultMod = game.InstallMod(false, modinfo, ServiceProvider); - defaultMod.InstallModinfoFile(modinfo); + var defaultModInstallation = gameInstallation.InstallMod(modinfo, false); + defaultModInstallation.InstallModinfoFile(modinfo); + var defaultMod = defaultModInstallation.Mod; var installedMods = _modFinder.FindMods(game).ToList(); @@ -272,52 +286,53 @@ public void FindMods_Steam_ShouldAddWorkshopsAndMods(GameType type) [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 gameInstallation = GetOrCreateGameInstallation(new GameIdentity(type, GamePlatform.SteamGold)); + var game = gameInstallation.Game; + var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", - [$"{oppositeGameType.ToString().ToUpper()}"]); + [$"{type.Opposite().ToString().ToUpper()}"]); var modinfo = new ModinfoData("Name") { SteamData = steamData }; - var modOfWrongGameType = game.InstallMod(true, modinfo, ServiceProvider); + var modOfWrongGameType = gameInstallation.InstallMod(modinfo, true); modOfWrongGameType.InstallModinfoFile(modinfo); Assert.Empty(_modFinder.FindMods(game)); - Assert.Empty(_modFinder.FindMods(game, modOfWrongGameType.Directory)); + Assert.Empty(_modFinder.FindMods(game, modOfWrongGameType.Mod.Directory)); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_FromExternal(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var modPath = FileSystem.DirectoryInfo.New("external/myMod"); modPath.Create(); - var mod = game.InstallMod(modPath, false, new ModinfoData("MyMod"), ServiceProvider); + var mod = gameInstallation.InstallMod(new ModinfoData("MyMod"), modPath, false).Mod; var installedMods = _modFinder.FindMods(game, mod.Directory).ToList(); AssertSingleFoundMod(installedMods, mod, mod.Directory.FullName, null); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_FromExternal_DirectoryNotFoundShouldSkip(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var modPath = FileSystem.DirectoryInfo.New("external/myMod"); modPath.Create(); - var mod = game.InstallMod(modPath, false, new ModinfoData("MyMod"), ServiceProvider); + var mod = gameInstallation.InstallMod(new ModinfoData("MyMod"), modPath, false).Mod; modPath.Delete(true); var installedMods = _modFinder.FindMods(game, mod.Directory).ToList(); @@ -325,25 +340,26 @@ public void FindMods_FromExternal_DirectoryNotFoundShouldSkip(GameIdentity gameI } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_FromExternal_WithVariantModinfoLayout(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; var modPath = FileSystem.DirectoryInfo.New("external/123456"); // Use a number so it may look like a Steam WS ID modPath.Create(); var main = new ModinfoData("Main"); var info1 = new ModinfoData("MyName1"); var info2 = new ModinfoData("MyName2"); - var expectedMod = game.InstallMod(modPath, false, main, ServiceProvider); - expectedMod.InstallModinfoFile(main); - expectedMod.InstallModinfoFile(info1, "variant1"); - expectedMod.InstallModinfoFile(info2, "variant2"); + var expectedModInstallation = gameInstallation.InstallMod(main, modPath, false); + expectedModInstallation.InstallModinfoFile(main); + expectedModInstallation.InstallModinfoFile(info1, "variant1"); + expectedModInstallation.InstallModinfoFile(info2, "variant2"); - var baseId = expectedMod.Directory.FullName; + var baseId = expectedModInstallation.Mod.Directory.FullName; - var installedMods = _modFinder.FindMods(game, expectedMod.Directory).ToList(); - AssertMultipleModsOfSameLocation(installedMods, 3, expectedMod.Directory.FullName, ModType.Default, + var installedMods = _modFinder.FindMods(game, expectedModInstallation.Mod.Directory).ToList(); + AssertMultipleModsOfSameLocation(installedMods, 3, expectedModInstallation.Mod.Directory.FullName, ModType.Default, [$"{baseId}", $"{baseId}:MyName1", $"{baseId}:MyName2"], ["Main", "MyName1", "MyName2"]); } @@ -353,7 +369,8 @@ public void FindMods_FromExternal_WithVariantModinfoLayout(GameIdentity gameIden [InlineData(GameType.Foc)] public void FindMods_FromExternal_InsideSteamWsDirWithNonIdName(GameType type) { - var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(type, GamePlatform.SteamGold)); + var game = gameInstallation.Game; var steamHelper = ServiceProvider.GetRequiredService(); var steamLocation = steamHelper.GetWorkshopsLocation(game); steamLocation.Create(); @@ -361,7 +378,7 @@ public void FindMods_FromExternal_InsideSteamWsDirWithNonIdName(GameType type) var modPath = FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(steamLocation.FullName, "notASteamID")); modPath.Create(); - var expectedMod = game.InstallMod(modPath, false, new ModinfoData("MyMod"), ServiceProvider); + var expectedMod = gameInstallation.InstallMod(new ModinfoData("MyMod"), modPath, false).Mod; Assert.Equal(ModType.Default ,expectedMod.Type); var installedMods = _modFinder.FindMods(game, expectedMod.Directory).ToList(); @@ -373,7 +390,8 @@ public void FindMods_FromExternal_InsideSteamWsDirWithNonIdName(GameType type) [InlineData(GameType.Foc)] public void FindMods_ModInsideSteamWsDirWithNonIdName_ShouldBeSkipped(GameType type) { - var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(type, GamePlatform.SteamGold)); + var game = gameInstallation.Game; var steamHelper = ServiceProvider.GetRequiredService(); var steamLocation = steamHelper.GetWorkshopsLocation(game); steamLocation.Create(); @@ -381,7 +399,7 @@ public void FindMods_ModInsideSteamWsDirWithNonIdName_ShouldBeSkipped(GameType t var modPath = FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(steamLocation.FullName, "notASteamID")); modPath.Create(); - game.InstallMod(modPath, false, new ModinfoData("MyMod"), ServiceProvider); + gameInstallation.InstallMod(new ModinfoData("MyMod"), modPath, false); var installedMods = _modFinder.FindMods(game).ToList(); Assert.Empty(installedMods); @@ -392,12 +410,12 @@ public void FindMods_ModInsideSteamWsDirWithNonIdName_ShouldBeSkipped(GameType t [InlineData(GameType.Foc)] public void FindMods_ModInstalledInWrongGameModsDirectoryShouldBeSkipped(GameType type) { - var oppositeGameType = type is GameType.Eaw ? GameType.Foc : GameType.Eaw; - var game = FileSystem.InstallGame(new GameIdentity(type, TestHelpers.GetRandom(GITestUtilities.RealPlatforms)), ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(type, Random.Item(GITestUtilities.RealPlatforms))).Game; // Other, random platform to shuffle a bit more. - var otherTypeGame = FileSystem.InstallGame(new GameIdentity(oppositeGameType, TestHelpers.GetRandom(GITestUtilities.RealPlatforms)), ServiceProvider); + var otherTypeGame = GameInfrastructureTesting + .Game(new GameIdentity(type.Opposite(), Random.Item(GITestUtilities.RealPlatforms)), ServiceProvider); - var wrongMod = otherTypeGame.InstallMod("MyMod", false, ServiceProvider); + var wrongMod = otherTypeGame.InstallMod("MyMod", false).Mod; var installedMods = _modFinder.FindMods(game, wrongMod.Directory).ToList(); Assert.Empty(installedMods); @@ -408,7 +426,8 @@ public void FindMods_ModInstalledInWrongGameModsDirectoryShouldBeSkipped(GameTyp [InlineData(GameType.Foc)] public void FindMods_NoSteamWsDirectoryExistsShouldStillFindExternalMods(GameType type) { - var game = FileSystem.InstallGame(new GameIdentity(type, GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(type, GamePlatform.SteamGold)); + var game = gameInstallation.Game; var steamHelper = ServiceProvider.GetRequiredService(); var steamLocation = steamHelper.GetWorkshopsLocation(game); steamLocation.Delete(true); @@ -416,24 +435,25 @@ public void FindMods_NoSteamWsDirectoryExistsShouldStillFindExternalMods(GameTyp var modPath = FileSystem.DirectoryInfo.New("external/MyMod"); modPath.Create(); - game.InstallMod(modPath, false, new ModinfoData("MyMod"), ServiceProvider); + gameInstallation.InstallMod(new ModinfoData("MyMod"), modPath, false); var installedMods = _modFinder.FindMods(game).ToList(); Assert.Empty(installedMods); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void FindMods_InvalidModinfoContentIsSkippedButModIsFound(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); - var expectedMod = game.InstallMod("MyMod", GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); - expectedMod.InstallModinfoFile(new CustomModinfo(string.Empty)); // string.Empty is not valid + var gameInstallation = GetOrCreateGameInstallation(gameIdentity); + var game = gameInstallation.Game; + var expectedModInstallation = gameInstallation.InstallMod("MyMod"); + expectedModInstallation.InstallModinfoFile(new CustomModinfo(string.Empty)); // string.Empty is not valid var installedMods = _modFinder.FindMods(game); - var expectedId = expectedMod.Type == ModType.Workshops ? ((ulong)"MyMod".GetHashCode()).ToString() : "MyMod"; + var expectedId = expectedModInstallation.Mod.Type == ModType.Workshops ? ((ulong)"MyMod".GetHashCode()).ToString() : "MyMod"; - AssertSingleFoundMod(installedMods, expectedMod, expectedId, null); + AssertSingleFoundMod(installedMods, expectedModInstallation.Mod, expectedId, null); } private static void AssertSingleFoundMod(IEnumerable foundMods, IPhysicalMod expectedMod, string expectedId, IModinfo? expectedModinfo) @@ -450,6 +470,7 @@ private static void AssertSingleFoundMod(IEnumerable found Assert.Equal(expectedId, foundMod.ModReference.Identifier); } + // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local private static void AssertMultipleModsOfSameLocation( ICollection detectedMods, int expectedCount, @@ -470,6 +491,7 @@ private static void AssertMultipleModsOfSameLocation( Assert.Equivalent(expectedModinfoNames, detectedMods.Select(x => x.Modinfo?.Name), true); } + // ReSharper restore ParameterOnlyUsedForPreconditionCheck.Local private class CustomModinfo(string name) : IModinfo { @@ -479,8 +501,9 @@ public bool Equals(IModIdentity? other) } public string Name { get; } = name; - public SemVersion? Version { get; } - public IModDependencyList Dependencies { get; } = DependencyList.EmptyDependencyList; + public SemVersion? Version => null; + public IModDependencyList Dependencies => DependencyList.EmptyDependencyList; + public string ToJson() { return JsonSerializer.Serialize(this, JsonSerializerOptions.Default); @@ -491,11 +514,11 @@ public void ToJson(Stream stream) JsonSerializer.Serialize(stream, this, JsonSerializerOptions.Default); } - public string? Summary { get; } - public string? Icon { get; } + public string? Summary => null; + public string? Icon => null; public IDictionary Custom { get; } = new Dictionary(); - public ISteamData? SteamData { get; } + public ISteamData? SteamData => null; public IReadOnlyCollection Languages { get; } = new List(); - public bool LanguagesExplicitlySet { get; } + public bool LanguagesExplicitlySet => false; } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModGameTypeResolverTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModGameTypeResolverTestBase.cs index 76130879..2f0ff539 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModGameTypeResolverTestBase.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/ModGameTypeResolverTestBase.cs @@ -6,20 +6,18 @@ using AET.Modinfo.Spec; using AET.Modinfo.Spec.Steam; using AET.Modinfo.Utilities; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; 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 PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices; -public abstract class ModGameTypeResolverTestBase : CommonTestBase +public abstract class ModGameTypeResolverTestBase : GameInfrastructureTestBase { public abstract ModGameTypeResolver CreateResolver(); @@ -32,7 +30,7 @@ protected static DetectedModReference CreateDetectedModReference(IDirectoryInfo public void NullArg_Throws() { Assert.Throws(() => CreateResolver().TryGetGameType((DetectedModReference)null!, out _)); - Assert.Throws(() => CreateResolver().IsDefinitelyNotCompatibleToGame((DetectedModReference)null!, TestHelpers.GetRandomEnum())); + Assert.Throws(() => CreateResolver().IsDefinitelyNotCompatibleToGame((DetectedModReference)null!, Random.Enum())); } [Fact] @@ -40,7 +38,7 @@ public void Modinfo_IsNull_CannotGetType() { var resolver = CreateResolver(); Assert.False(resolver.TryGetGameType((IModinfo?)null!, out _)); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame((IModinfo?)null!, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame((IModinfo?)null!, Random.Enum())); } [Fact] @@ -50,7 +48,7 @@ public void Modinfo_WithoutSteamData_CannotGetType() var resolver = CreateResolver(); Assert.False(resolver.TryGetGameType(modinfo, out _)); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, Random.Enum())); } [Theory] @@ -63,7 +61,7 @@ public void Modinfo_WithoutSteamGameTag_CannotGetType(params string[] tags) var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", tags); var modinfo = new ModinfoData("Name") @@ -73,7 +71,7 @@ public void Modinfo_WithoutSteamGameTag_CannotGetType(params string[] tags) var resolver = CreateResolver(); Assert.False(resolver.TryGetGameType(modinfo, out _)); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, Random.Enum())); } public static IEnumerable GetSteamTagsSuccessTestData() @@ -93,7 +91,7 @@ public void Modinfo_WithSteamDataAndSteamTag_CanDetermineGameType(IList var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", tags); var modinfo = new ModinfoData("Name") { @@ -104,7 +102,7 @@ public void Modinfo_WithSteamDataAndSteamTag_CanDetermineGameType(IList Assert.True(resolver.TryGetGameType(modinfo, out var types)); Assert.Equivalent(expectedTypes, types, true); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, TestHelpers.GetRandom(expectedTypes))); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(modinfo, Random.Item(expectedTypes))); if (incompatibleWith is not null) Assert.True(resolver.IsDefinitelyNotCompatibleToGame(modinfo, incompatibleWith.Value)); @@ -116,7 +114,7 @@ public void Directory_WithModinfo_ModinfoIsAlwaysSuperiorForSteamTypes() var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["EAW"]); var modinfo = new ModinfoData("Name") @@ -125,7 +123,7 @@ public void Directory_WithModinfo_ModinfoIsAlwaysSuperiorForSteamTypes() }; // Installing FOC, while tags has EAW. So technically, EAW does not even exist. - var game = FileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.SteamGold), ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(GameType.Foc, GamePlatform.SteamGold)).Game; var steamHelpers = ServiceProvider.GetRequiredService(); // Using a known MODID (RaW), which is FOC, to implicitly assert cache is not used. var modDir = steamHelpers.GetWorkshopsLocation(game).CreateSubdirectory("1129810972"); @@ -147,14 +145,14 @@ public void Directory_SteamWithoutModinfoCannotDecide() // No SteamData here var modinfo = new ModinfoData("Name"); - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), GamePlatform.SteamGold)); var steamHelpers = ServiceProvider.GetRequiredService(); // Using an ID here, which never points to a real mod. - var modDir = steamHelpers.GetWorkshopsLocation(game).CreateSubdirectory("1234"); + var modDir = steamHelpers.GetWorkshopsLocation(gameInstallation.Game).CreateSubdirectory("1234"); - var steamMod = game.InstallMod(modDir, true, modinfo, ServiceProvider); + var steamMod = gameInstallation.InstallMod(modinfo, modDir, true).Mod; var info = CreateDetectedModReference(steamMod.Directory, ModType.Workshops, modinfo); var resolver = CreateResolver(); @@ -163,7 +161,7 @@ public void Directory_SteamWithoutModinfoCannotDecide() Assert.False(resolver.TryGetGameType(info, out var types)); Assert.Empty(types); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Enum())); } [Fact] @@ -172,7 +170,7 @@ public void Directory_SteamWithInvalidDirName() var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["FOC"]); var modinfo = new ModinfoData("Name") @@ -180,12 +178,12 @@ public void Directory_SteamWithInvalidDirName() SteamData = steamData }; - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), GamePlatform.SteamGold)); var steamHelpers = ServiceProvider.GetRequiredService(); - var modDir = steamHelpers.GetWorkshopsLocation(game).CreateSubdirectory("notASteamId"); + var modDir = steamHelpers.GetWorkshopsLocation(gameInstallation.Game).CreateSubdirectory("notASteamId"); - var steamMod = game.InstallMod(modDir, true, modinfo, ServiceProvider); + var steamMod = gameInstallation.InstallMod(modinfo, modDir, true).Mod; // This asserts that we do not use steam data from modinfo if the directory is not a valid steam workshops id var info = CreateDetectedModReference(steamMod.Directory, ModType.Workshops, modinfo); @@ -194,7 +192,7 @@ public void Directory_SteamWithInvalidDirName() Assert.False(resolver.TryGetGameType(info, out var types)); Assert.Empty(types); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Enum())); } public static IEnumerable GetCachedModsTestData() @@ -205,7 +203,7 @@ public static IEnumerable GetCachedModsTestData() if (knownMod.Value.Types.Length == 2) incompatible = null; else - incompatible = knownMod.Value.Types.First() == GameType.Foc ? GameType.Eaw : GameType.Foc; + incompatible = knownMod.Value.Types.First().Opposite(); yield return [knownMod.Key.ToString(), knownMod.Value.Types, incompatible!]; } @@ -218,7 +216,7 @@ public void Directory_SteamWithoutModinfoButKnownModID(string knownId, ICollecti // No SteamData here var modinfo = new ModinfoData("Name"); - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), GamePlatform.SteamGold)).Game; var steamHelpers = ServiceProvider.GetRequiredService(); @@ -230,7 +228,7 @@ public void Directory_SteamWithoutModinfoButKnownModID(string knownId, ICollecti Assert.True(resolver.TryGetGameType(info, out var types)); Assert.Equivalent(expectedTypes, types, true); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandom(expectedTypes))); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Item(expectedTypes))); if (incompatibleWith is not null) Assert.True(resolver.IsDefinitelyNotCompatibleToGame(info, incompatibleWith.Value)); } @@ -241,7 +239,7 @@ public void VirtualMods_VirtualModsAreAlwaysUndecidable() var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["FOC"]); var modinfo = new ModinfoData("Name") @@ -249,8 +247,7 @@ public void VirtualMods_VirtualModsAreAlwaysUndecidable() SteamData = steamData }; - var game = FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - var mod = game.InstallMod("Name", false, ServiceProvider); + var mod = GetOrCreateGameInstallation().InstallMod("Name", false).Mod; var info = CreateDetectedModReference(mod.Directory, ModType.Virtual, modinfo); var resolver = CreateResolver(); @@ -259,7 +256,7 @@ public void VirtualMods_VirtualModsAreAlwaysUndecidable() Assert.False(CreateResolver().TryGetGameType(info, out var types)); Assert.Empty(types); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Enum())); } [Fact] @@ -268,7 +265,7 @@ public void ExternalModsAreAlwaysUndecidable() var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["FOC"]); var modinfo = new ModinfoData("Name") @@ -285,7 +282,7 @@ public void ExternalModsAreAlwaysUndecidable() Assert.False(CreateResolver().TryGetGameType(info, out var types)); Assert.Empty(types); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandomEnum())); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Enum())); } [Theory] @@ -296,7 +293,7 @@ public void ModsInModsDirUseGameType(GameType gameType) var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["FOC"]); var modinfo = new ModinfoData("Name") @@ -304,8 +301,9 @@ public void ModsInModsDirUseGameType(GameType gameType) SteamData = steamData }; - var game = FileSystem.InstallGame(new GameIdentity(gameType, TestHelpers.GetRandom(GITestUtilities.RealPlatforms)), ServiceProvider); - var mod = game.InstallMod("Name", false, ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, Random.Item(GITestUtilities.RealPlatforms))); + var game = gameInstallation.Game; + var mod = gameInstallation.InstallMod("Name", false).Mod; var info = CreateDetectedModReference(mod.Directory, ModType.Default, modinfo); var resolver = CreateResolver(); @@ -326,7 +324,7 @@ public void ModsNotInModsDirButSomeOtherGameBasesDir_NotDecidable(GameType gameT var steamData = new SteamData( new Random().Next(0, int.MaxValue).ToString(), "path", - TestHelpers.GetRandomEnum(), + Random.Enum(), "Title", ["FOC"]); var modinfo = new ModinfoData("Name") @@ -334,9 +332,10 @@ public void ModsNotInModsDirButSomeOtherGameBasesDir_NotDecidable(GameType gameT SteamData = steamData }; - var game = FileSystem.InstallGame(new GameIdentity(gameType, TestHelpers.GetRandom(GITestUtilities.RealPlatforms)), ServiceProvider); + var gameInstallation = GetOrCreateGameInstallation(new GameIdentity(gameType, Random.Item(GITestUtilities.RealPlatforms))); + var game = gameInstallation.Game; var modDir = game.Directory.CreateSubdirectory("ModsOther").CreateSubdirectory("MyMod"); - var mod = game.InstallMod(modDir, false, modinfo, ServiceProvider); + var mod = gameInstallation.InstallMod(modinfo, modDir, false).Mod; var info = CreateDetectedModReference(mod.Directory, ModType.Default, modinfo); var resolver = CreateResolver(); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/OnlineModGameTypeResolverTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/OnlineModGameTypeResolverTest.cs index 57854c23..27e06965 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModServices/OnlineModGameTypeResolverTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModServices/OnlineModGameTypeResolverTest.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Services.Steam; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.TestingUtilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.ModServices; @@ -20,14 +20,14 @@ public override ModGameTypeResolver CreateResolver() public static IEnumerable GetOnlineModsData() { yield return ["1125718579", new[] {GameType.Foc}, GameType.Eaw]; //z3r0x's Mod (3.5) - yield return ["2508288191", new[] {GameType.Foc, GameType.Eaw}, null!]; //Deep Core SDK + yield return ["2508288191", new[] {GameType.Foc, GameType.Eaw}, null!]; //Mod Template } [Theory] [MemberData(nameof(GetOnlineModsData))] public void Online_GetTagsFromSteamOnline(string knownId, ICollection expectedTypes, GameType? incompatibleWith) { - var game = FileSystem.InstallGame(new GameIdentity(TestHelpers.GetRandomEnum(), GamePlatform.SteamGold), ServiceProvider); + var game = GetOrCreateGameInstallation(new GameIdentity(Random.Enum(), GamePlatform.SteamGold)).Game; var steamHelpers = ServiceProvider.GetRequiredService(); var modDir = steamHelpers.GetWorkshopsLocation(game).CreateSubdirectory(knownId); @@ -39,7 +39,7 @@ public void Online_GetTagsFromSteamOnline(string knownId, ICollection Assert.True(CreateResolver().TryGetGameType(info, out var types)); Assert.Equivalent(expectedTypes, types, true); - Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, TestHelpers.GetRandom(expectedTypes))); + Assert.False(resolver.IsDefinitelyNotCompatibleToGame(info, Random.Item(expectedTypes))); if (incompatibleWith is not null) Assert.True(resolver.IsDefinitelyNotCompatibleToGame(info, incompatibleWith.Value)); } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/ModTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/ModTest.cs index b8ead9e7..2ce248cb 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/ModTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/ModTest.cs @@ -6,7 +6,8 @@ using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Dependencies; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; using Semver; using Xunit; @@ -23,7 +24,7 @@ public ModTest() private IDirectoryInfo CreateModDirectoryInfo(string name) { - return FileSystem.DirectoryInfo.New(Game.GetModDirectory(name, _isWorkshop, ServiceProvider)); + return GameInstallation.GetModDirectory(name, _isWorkshop); } private IModReference CreateModRef(string name) @@ -32,7 +33,7 @@ private IModReference CreateModRef(string name) return new ModReference(name, modType); } - private Mod CreatePhysicalMod( + private ITestingPhysicalModInstallation CreateAndAddPhysicalModInstallation( string name, string? iconPath = null, ICollection? languages = null, @@ -44,39 +45,39 @@ private Mod CreatePhysicalMod( Dependencies = new DependencyList(deps, layout) }; - var mod = Game.InstallMod(CreateModDirectoryInfo(name), _isWorkshop, modinfo, ServiceProvider); - Game.AddMod(mod); + var modInstallation = GetOrCreateGameInstallation() + .InstallAndAddMod(modinfo, CreateModDirectoryInfo(name), _isWorkshop); if (languages is not null) { - foreach (var languageInfo in languages) - mod.InstallLanguage(languageInfo); + foreach (var languageInfo in languages) + modInstallation.InstallLanguage(languageInfo); } if (iconPath is not null) - FileSystem.File.Create(FileSystem.Path.Combine(mod.Directory.FullName, iconPath)); + FileSystem.File.Create(FileSystem.Path.Combine(modInstallation.Mod.Directory.FullName, iconPath)); - return mod; + return modInstallation; } - protected override ModBase CreateMod( + protected override ITestingModInstallation CreateAndAddModInstallation( string name, DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, params IList deps) { - return CreatePhysicalMod(name, layout: layout, deps: deps); + return CreateAndAddPhysicalModInstallation(name, layout: layout, deps: deps); } - protected override IPlayableObject CreatePlayableObject( + protected override ITestingPlayableObjectInstallation CreatePlayableObjectInstallation( string? iconPath = null, ICollection? languages = null) { - return CreatePhysicalMod("MyMod", iconPath, languages); + return CreateAndAddPhysicalModInstallation("MyMod", iconPath, languages); } - protected override PlayableModContainer CreateModContainer() + protected override ITestingModContainerInstallation CreateModContainerInstallation() { - return CreateMod("MyMod"); + return CreateAndAddModInstallation("MyMod"); } [Fact] @@ -94,9 +95,9 @@ public void InvalidCtor_Throws() public void ValidCtor_Properties_FromName() { var ws = GITestUtilities.GetRandomWorkshopFlag(Game); - var loc = Game.GetModDirectory("Mod", ws, ServiceProvider); + var loc = GameInstallation.GetModDirectory("Mod", ws); - var mod = new Mod(Game, "ModId", FileSystem.DirectoryInfo.New(loc), ws, "Mod", ServiceProvider); + var mod = new Mod(Game, "ModId", loc, ws, "Mod", ServiceProvider); Assert.Same(Game, mod.Game); Assert.Equal("Mod", mod.Name); @@ -119,7 +120,7 @@ public void ValidCtor_Properties_FromName() public void ValidCtor_Properties_FromModinfo_WithoutDependencies() { var ws = GITestUtilities.GetRandomWorkshopFlag(Game); - var loc = Game.GetModDirectory("Mod", ws, ServiceProvider); + var loc = GameInstallation.GetModDirectory("Mod", ws); var modInfo = new ModinfoData("Mod") { @@ -127,7 +128,7 @@ public void ValidCtor_Properties_FromModinfo_WithoutDependencies() Version = new SemVersion(1, 0, 0), Languages = new List(), }; - var mod = new Mod(Game, "ModId", FileSystem.DirectoryInfo.New(loc), ws, modInfo, ServiceProvider); + var mod = new Mod(Game, "ModId", loc, ws, modInfo, ServiceProvider); Assert.Same(Game, mod.Game); Assert.Equal("Mod", mod.Name); @@ -150,7 +151,7 @@ public void ValidCtor_Properties_FromModinfo_WithoutDependencies() [Fact] public void ValidCtor_Properties_FromModinfo_WithDependencies() { - var dep = CreateOtherMod("dep"); + var dep = GameInstallation.InstallAndAddMod("dep").Mod; var ws = GITestUtilities.GetRandomWorkshopFlag(Game); @@ -158,7 +159,7 @@ public void ValidCtor_Properties_FromModinfo_WithDependencies() { Dependencies = new DependencyList(new List{ dep }, DependencyResolveLayout.ResolveLastItem) }; - var mod = Game.InstallAndAddMod(ws, modInfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modInfo, ws).Mod; Assert.Empty(mod.Dependencies); Assert.Single(((IModIdentity)mod).Dependencies); @@ -172,7 +173,7 @@ public void ValidCtor_Properties_FromModinfo_WithDependencies() [Fact] public void ResolveDependencies_NoDependenciesIsNOP() { - var mod = CreateMod("Mod"); + var mod = CreateAndAddModInstallation("Mod").Mod; // Should not throw or anything else mod.ResolveDependencies(); Assert.Empty(mod.Dependencies); @@ -185,8 +186,8 @@ public void ResolveDependencies_ResolvesCycle_Throws(ModTestScenarios.CycleTestS { var mod = ModTestScenarios.CreateTestScenarioCycle( testScenario, - CreateMod, - CreateOtherMod, + (name, layout, dependencies) => CreateAndAddModInstallation(name, layout, dependencies).Mod, + (name, layout, dependencies) => InstallAndAddModWithDependencies(name, layout, dependencies).Mod, CreateModRef) .Mod; diff --git a/test/PG.StarWarsGame.Infrastructure.Test/PG.StarWarsGame.Infrastructure.Test.csproj b/test/PG.StarWarsGame.Infrastructure.Test/PG.StarWarsGame.Infrastructure.Test.csproj index 29c43ac0..d6e0a262 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/PG.StarWarsGame.Infrastructure.Test.csproj +++ b/test/PG.StarWarsGame.Infrastructure.Test/PG.StarWarsGame.Infrastructure.Test.csproj @@ -1,4 +1,4 @@ - + PG.StarWarsGame.Infrastructure.Test @@ -9,19 +9,15 @@ $(TargetFrameworks);net481 false true + Exe - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphGameInfrastructureIntegrationTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphGameInfrastructureIntegrationTest.cs index 0d28c712..693dee4f 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphGameInfrastructureIntegrationTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphGameInfrastructureIntegrationTest.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using AET.Modinfo.Model; +using AET.Modinfo.Model; using AET.Modinfo.Spec; using AET.Modinfo.Spec.Equality; using AET.Modinfo.Utilities; @@ -15,38 +11,46 @@ using PG.StarWarsGame.Infrastructure.Services.Dependencies; using PG.StarWarsGame.Infrastructure.Services.Detection; using PG.StarWarsGame.Infrastructure.Services.Steam; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Game.Registry; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using Semver; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using Xunit; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; namespace PG.StarWarsGame.Infrastructure.Test; -public class PetroglyphGameInfrastructureIntegrationTest : CommonTestBase +public class PetroglyphGameInfrastructureIntegrationTest : GameInfrastructureTestBase { private readonly IRegistry _registry = new InMemoryRegistry(InMemoryRegistryCreationFlags.WindowsLike); private const string ExternalModPath = "externalMods/MyExternalMod"; - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(_registry); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(_registry); } [Theory] - [MemberData(nameof(RealPlatforms))] + [MemberData(nameof(GITestUtilities.GetRealPlatforms), MemberType = typeof(GITestUtilities))] public void FullWorkflow_WithGamesAndMultipleModsWithMultipleModsDependencies(GamePlatform platform) { // Init Mods uninitialized - var eaw = FileSystem.InstallGame(new GameIdentity(GameType.Eaw, platform), ServiceProvider); - var foc = FileSystem.InstallGame(new GameIdentity(GameType.Foc, platform), ServiceProvider); + var eawInstallation = GameInfrastructureTesting.Game(new GameIdentity(GameType.Eaw, platform), ServiceProvider); + var focInstallation = GameInfrastructureTesting.Game(new GameIdentity(GameType.Foc, platform), ServiceProvider); + + var eaw = eawInstallation.Game; + var foc = focInstallation.Game; - TestGameRegistrySetupData.Uninitialized(GameType.Eaw).Create(ServiceProvider); - TestGameRegistrySetupData.Uninitialized(GameType.Foc).Create(ServiceProvider); + GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(TestGameRegistrySetupData.Uninitialized(GameType.Eaw)); + GameInfrastructureTesting.Registry(ServiceProvider).CreateFrom(TestGameRegistrySetupData.Uninitialized(GameType.Foc)); var registryFactory = ServiceProvider.GetRequiredService(); var eawRegistry = registryFactory.CreateRegistry(GameType.Eaw); @@ -58,10 +62,8 @@ public void FullWorkflow_WithGamesAndMultipleModsWithMultipleModsDependencies(Ga var initCount = 0; gameDetector.InitializationRequested += (_, args) => { - if (args.GameType == GameType.Eaw) - TestGameRegistrySetupData.Installed(GameType.Eaw, eaw.Directory).Create(ServiceProvider); - else - TestGameRegistrySetupData.Installed(GameType.Foc, foc.Directory).Create(ServiceProvider); + var game = args.GameType == GameType.Eaw ? eaw : foc; + GameInfrastructureTesting.Registry(ServiceProvider).CreateInstalled(game); args.Handled = true; initCount++; }; @@ -80,10 +82,10 @@ public void FullWorkflow_WithGamesAndMultipleModsWithMultipleModsDependencies(Ga AssertExpectedGame(foc, actualFoc); // Init Mods - CreateExternalMod(actualFoc); + CreateExternalMod(focInstallation); if (platform == GamePlatform.SteamGold) - CreateAndAddSteamScenario(actualFoc); - Eaw_CreateModInModsDir(eaw); + CreateAndAddSteamScenario(focInstallation); + Eaw_CreateModInModsDir(eawInstallation); // Test Mod detection @@ -216,18 +218,18 @@ public void FullWorkflow_WithGamesAndMultipleModsWithMultipleModsDependencies(Ga } } - private void CreateAndAddSteamScenario(IGame actualFoc) + private void CreateAndAddSteamScenario(ITestingGameInstallation gameInstallation) { - Assert.Equal(GamePlatform.SteamGold, actualFoc.Platform); + var game = gameInstallation.Game; + Assert.Equal(GamePlatform.SteamGold, game.Platform); var steamHelper = ServiceProvider.GetRequiredService(); - var republicAtWarDir = FileSystem.Path.Combine(steamHelper.GetWorkshopsLocation(actualFoc).FullName, "1129810972"); // This is RaW's Steam ID - actualFoc.InstallMod(FileSystem.DirectoryInfo.New(republicAtWarDir), true, new ModinfoData("NOT USED"), ServiceProvider); + var republicAtWarDir = FileSystem.Path.Combine(steamHelper.GetWorkshopsLocation(game).FullName, "1129810972"); // This is RaW's Steam ID + gameInstallation.InstallMod(new ModinfoData("NOT USED"), FileSystem.DirectoryInfo.New(republicAtWarDir), true); - var rawSubModDir = FileSystem.Path.Combine(steamHelper.GetWorkshopsLocation(actualFoc).FullName, "123456"); // Just some ID - var rawSubMod = actualFoc.InstallMod(FileSystem.DirectoryInfo.New(rawSubModDir), true, - new ModinfoData("NOT USED"), ServiceProvider); + var rawSubModDir = FileSystem.Path.Combine(steamHelper.GetWorkshopsLocation(game).FullName, "123456"); // Just some ID + var rawSubModInstallation = gameInstallation.InstallMod(new ModinfoData("NOT USED"), FileSystem.DirectoryInfo.New(rawSubModDir), true); var rawSubModModinfoContent = @" @@ -251,7 +253,7 @@ private void CreateAndAddSteamScenario(IGame actualFoc) ], } }"; - rawSubMod.InstallModinfoFile(ModinfoData.Parse(rawSubModModinfoContent)); + rawSubModInstallation.InstallModinfoFile(ModinfoData.Parse(rawSubModModinfoContent)); } private void AssertModFinderResult(ICollection finderResult, @@ -271,7 +273,7 @@ private void AssertTraversedDependencies(IMod mod, IList expectedDepList) Assert.Equal(expectedDepList, depList); } - private void AssertExpectedGame(PetroglyphStarWarsGame expected, IGame actual) + private void AssertExpectedGame(IGame expected, IGame actual) { Assert.Equal(expected.Directory.FullName, actual.Directory.FullName); Assert.Equal(expected.Type, actual.Type); @@ -287,16 +289,16 @@ private void AssertModAddToGame(IGame game, IMod mod, Action assertAction) assertAction(mod); } - private void CreateExternalMod(IGame game) + private void CreateExternalMod(ITestingGameInstallation gameInstallation) { var modinfo = new ModinfoData("NAME NOT TAKE CAUSE NO MODINFO"); - game.InstallMod(FileSystem.DirectoryInfo.New("externalMods/MyExternalMod"), false, modinfo, ServiceProvider); + gameInstallation.InstallMod(modinfo, FileSystem.DirectoryInfo.New("externalMods/MyExternalMod"), false); } - private void Eaw_CreateModInModsDir(IGame game) + private void Eaw_CreateModInModsDir(ITestingGameInstallation installation) { - game.InstallMod("In-Mods-Dir", false, ServiceProvider); + installation.InstallMod("In-Mods-Dir", false); } private class DetectedModReferenceEqualityComparer : IEqualityComparer diff --git a/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphStarWarsGameTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphStarWarsGameTest.cs index cd5b9248..62ca5850 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphStarWarsGameTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/PetroglyphStarWarsGameTest.cs @@ -1,47 +1,47 @@ using System; using System.Collections.Generic; using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.Testing.Extensions; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.TestingUtilities; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test; public class PetroglyphStarWarsGameTest : PlayableModContainerTest { - private PetroglyphStarWarsGame CreateGame( - string? iconPath = null, - ICollection? languages = null) + private ITestingGameInstallation CreateGameInstallation(string? iconPath = null, ICollection? languages = null) { - var gameId = new GameIdentity(TestHelpers.GetRandomEnum(), TestHelpers.GetRandom(GITestUtilities.RealPlatforms)); - var game = FileSystem.InstallGame(gameId, ServiceProvider); + var gameId = new GameIdentity(Random.Enum(), Random.Item(GITestUtilities.RealPlatforms)); + var gameInstallation = GetOrCreateGameInstallation(gameId); + if (languages is not null) { foreach (var languageInfo in languages) - game.InstallLanguage(languageInfo); + gameInstallation.InstallLanguage(languageInfo); } if (iconPath is not null) { - iconPath = game.Type == GameType.Eaw ? "eaw.ico" : "foc.ico"; - FileSystem.File.Create(FileSystem.Path.Combine(game.Directory.FullName, iconPath)); + iconPath = gameInstallation.Game.Type == GameType.Eaw ? "eaw.ico" : "foc.ico"; + FileSystem.File.Create(FileSystem.Path.Combine(gameInstallation.Game.Directory.FullName, iconPath)); } - return game; + return gameInstallation; } - protected override IPlayableObject CreatePlayableObject( - string? iconPath = null, + protected override ITestingPlayableObjectInstallation CreatePlayableObjectInstallation( + string? iconPath = null, ICollection? languages = null) { - return CreateGame(iconPath, languages); + return CreateGameInstallation(iconPath, languages); } - protected override PlayableModContainer CreateModContainer() + protected override ITestingModContainerInstallation CreateModContainerInstallation() { - return CreateGame(); + return CreateGameInstallation(); } [Fact] @@ -67,11 +67,11 @@ public void Equals_GetHashCode() var focSteamId = new GameIdentity(GameType.Foc, GamePlatform.SteamGold); var eawDiskId = new GameIdentity(GameType.Eaw, GamePlatform.Disk); - var eawSteam = FileSystem.InstallGame(eawSteamId, ServiceProvider); - var focSteam = FileSystem.InstallGame(focSteamId, ServiceProvider); - var eawDisc = FileSystem.InstallGame(eawDiskId, ServiceProvider); + var eawSteam = GameInfrastructureTesting.Game(eawSteamId, ServiceProvider).Game; + var focSteam = GameInfrastructureTesting.Game(focSteamId, ServiceProvider).Game; + var eawDisc = GameInfrastructureTesting.Game(eawDiskId, ServiceProvider).Game; - Assert.False(eawSteam.Equals(null)); + Assert.False(eawSteam.Equals(null!)); Assert.False(eawSteam.Equals((object)null!)); Assert.False(eawSteam.Equals(new object())); @@ -101,10 +101,10 @@ public void Equals_GetHashCode() } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void GetModDirTest(GameIdentity gameIdentity) { - var game = FileSystem.InstallGame(gameIdentity, ServiceProvider); + var game = GetOrCreateGameInstallation(gameIdentity).Game; var dataLocation = game.ModsLocation; Assert.Equal(FileSystem.Path.GetFullPath(FileSystem.Path.Combine(game.Directory.FullName, "Mods")), dataLocation.FullName); } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/PlayableModContainerTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/PlayableModContainerTest.cs index 8e9669a8..2d4a4be4 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/PlayableModContainerTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/PlayableModContainerTest.cs @@ -1,14 +1,13 @@ using System; using AET.Modinfo.Model; -using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using Xunit; +using PG.StarWarsGame.Infrastructure.Testing.Installations; #if NET5_0_OR_GREATER using System.Collections.Generic; #else -using PG.TestingUtilities; +using AnakinRaW.CommonUtilities.Testing.EqualityComparers; #endif namespace PG.StarWarsGame.Infrastructure.Test; @@ -17,7 +16,7 @@ public abstract class PlayableModContainerTest : PlayableObjectTest { private readonly string _randomModName; - protected abstract PlayableModContainer CreateModContainer(); + protected abstract ITestingModContainerInstallation CreateModContainerInstallation(); protected PlayableModContainerTest() { @@ -28,18 +27,18 @@ protected PlayableModContainerTest() [Fact] public void Mods_NoMods() { - var obj = CreateModContainer(); + var obj = CreateModContainerInstallation().ModContainer; Assert.Empty(obj.Mods); } [Fact] public void AddMod_RemoveMod() { - var container = CreateModContainer(); - var game = container.Game; + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; - var mod = game.InstallMod(_randomModName, false, ServiceProvider); - var modSame = game.InstallMod(_randomModName, false, ServiceProvider); + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName, false).Mod; + var modSame = containerInstallation.GameInstallation.InstallMod(_randomModName, false).Mod; Assert.DoesNotContain(mod, container.Mods); Assert.DoesNotContain(modSame, container.Mods); @@ -85,22 +84,23 @@ public void AddMod_RemoveMod() [Fact] public void AddMod_DifferentGameRef_Throws() { - var container = CreateModContainer(); + var container = CreateModContainerInstallation().ModContainer; var game = container.Game; - var otherGame = new PetroglyphStarWarsGame(game, game.Directory, game.Name, ServiceProvider); - var mod = otherGame.InstallAndAddMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + // Same game, just different reference + var otherInstallation = GameInfrastructureTesting.Game(game, ServiceProvider); + var mod = otherInstallation.InstallAndAddMod(_randomModName).Mod; Assert.Throws(() => container.AddMod(mod)); } [Fact] public void AddMod_ShouldNotAddSelf() { - var game = CreateModContainer().Game; + var game = CreateModContainerInstallation().GameInstallation; - var isWs = GITestUtilities.GetRandomWorkshopFlag(game); - var mod = game.InstallAndAddMod(_randomModName, isWs, ServiceProvider); - var sameMod = new Mod(game, mod.Identifier, mod.Directory, isWs, mod.Name, ServiceProvider); + var isWs = GITestUtilities.GetRandomWorkshopFlag(game.Game); + var mod = game.InstallAndAddMod(_randomModName, isWs).Mod; + var sameMod = new Mod(game.Game, mod.Identifier, mod.Directory, isWs, mod.Name, ServiceProvider); Assert.False(mod.AddMod(mod)); Assert.False(mod.AddMod(sameMod)); @@ -109,10 +109,9 @@ public void AddMod_ShouldNotAddSelf() [Fact] public void AddMod_RemoveMod_RaiseEvent() { - var container = CreateModContainer(); - var game = container.Game; - - var mod = game.InstallMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName).Mod; var evtAdd = Assert.Raises( a => container.ModsCollectionModified += a, @@ -141,10 +140,9 @@ public void AddMod_RemoveMod_RaiseEvent() [Fact] public void RemoveMod_NotExisting_DoesNotRaiseEvent() { - var container = CreateModContainer(); - var game = container.Game; - - var mod = game.InstallMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName).Mod; var containerRaised = false; container.ModsCollectionModified += (_, _) => @@ -158,18 +156,19 @@ public void RemoveMod_NotExisting_DoesNotRaiseEvent() gameRaised = true; }; - game.RemoveMod(mod); + container.Game.RemoveMod(mod); Assert.False(containerRaised); Assert.False(gameRaised); } [Fact] - public void AddMod_Existing_DoesNotRaiseEvent() + public void AddMod_AlreadyExisting_DoesNotRaiseEvent() { - var container = CreateModContainer(); - var game = container.Game; + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName).Mod; - var mod = game.InstallMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + // Add before registering events container.AddMod(mod); var containerRaised = false; @@ -192,23 +191,22 @@ public void AddMod_Existing_DoesNotRaiseEvent() [Fact] public void AddMod_ExistingFromContainer_ShouldBeAlreadyInGame() { - var container = CreateModContainer(); - var game = container.Game; - - var mod = game.InstallMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; + var game = containerInstallation.GameInstallation.Game; + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName).Mod; + Assert.True(container.AddMod(mod)); - Assert.False(game.AddMod(mod)); } [Fact] public void FindMod() { - var container = CreateModContainer(); - var game = container.Game; + var containerInstallation = CreateModContainerInstallation(); + var container = containerInstallation.ModContainer; + var mod = containerInstallation.GameInstallation.InstallMod(_randomModName).Mod; - var mod = game.InstallMod(_randomModName, GITestUtilities.GetRandomWorkshopFlag(game), ServiceProvider); - Assert.True(container.AddMod(mod)); Assert.Same(mod, container.FindMod(mod)); @@ -220,7 +218,7 @@ public void FindMod() [Fact] public void ModContainerMethod_NullArgs_Throws() { - var container = CreateModContainer(); + var container = CreateModContainerInstallation().ModContainer; Assert.Throws(() => container.AddMod(null!)); Assert.Throws(() => container.RemoveMod(null!)); Assert.Throws(() => container.FindMod(null!)); diff --git a/test/PG.StarWarsGame.Infrastructure.Test/PlayableObjectTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/PlayableObjectTest.cs index 5fb0df25..aeef5d45 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/PlayableObjectTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/PlayableObjectTest.cs @@ -1,29 +1,30 @@ -using System.Collections.Generic; -using AET.Modinfo.Spec; +using AET.Modinfo.Spec; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Services.Language; +using PG.StarWarsGame.Infrastructure.Testing; +using PG.StarWarsGame.Infrastructure.Testing.Installations; using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using System.Collections.Generic; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test; -public abstract class PlayableObjectTest : CommonTestBase +public abstract class PlayableObjectTest : GameInfrastructureTestBase { - protected abstract IPlayableObject CreatePlayableObject( - string? iconPath = null, - ICollection? languages = null); + protected abstract ITestingPlayableObjectInstallation CreatePlayableObjectInstallation(string? iconPath = null, ICollection? languages = null); [Fact] public void IconFile_NoIcon() { - var obj = CreatePlayableObject(); + var obj = CreatePlayableObjectInstallation().PlayableObject; Assert.Null(obj.IconFile); } [Fact] public void IconFile_IconInstalled() { - var obj = CreatePlayableObject(iconPath: $"{FileSystem.Path.GetRandomFileName()}.ico"); + var obj = CreatePlayableObjectInstallation(iconPath: $"{FileSystem.Path.GetRandomFileName()}.ico") + .PlayableObject; Assert.NotNull(obj.IconFile); Assert.NotNull(obj.IconFile); } @@ -31,7 +32,7 @@ public void IconFile_IconInstalled() [Fact] public void InstalledLanguages_NoLanguagesFound() { - var obj = CreatePlayableObject(); + var obj = CreatePlayableObjectInstallation().PlayableObject; Assert.Empty(obj.InstalledLanguages); // Get a second time Assert.Empty(obj.InstalledLanguages); @@ -40,19 +41,19 @@ public void InstalledLanguages_NoLanguagesFound() [Fact] public void InstalledLanguages() { - var expected = GetRandomLanguages(); - var obj = CreatePlayableObject(languages: expected); + var expected = GITestUtilities.GetRandomLanguages(); + var obj = CreatePlayableObjectInstallation(languages: expected).PlayableObject; Assert.Equivalent(expected, obj.InstalledLanguages, true); // Get a second time Assert.Equivalent(expected, obj.InstalledLanguages, true); } - public class PlayableObjectAbstractTest : CommonTestBaseWithRandomGame + public class PlayableObectAbstractTest : GameInfrastructureTestBaseWithRandomGame { - protected override void SetupServiceProvider(IServiceCollection sc) + protected override void SetupServices(IServiceCollection serviceCollection) { - base.SetupServiceProvider(sc); - sc.AddSingleton(new NullLanguageFinder()); + base.SetupServices(serviceCollection); + serviceCollection.AddSingleton(new NullLanguageFinder()); } [Fact] diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Services/IconFinderTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/Services/IconFinderTest.cs index 28c1aecc..e77093d1 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Services/IconFinderTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Services/IconFinderTest.cs @@ -5,15 +5,13 @@ using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Icon; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; using PG.StarWarsGame.Infrastructure.Utilities; using Xunit; namespace PG.StarWarsGame.Infrastructure.Test.Services; -public class IconFinderTest : CommonTestBaseWithRandomGame +public class IconFinderTest : GameInfrastructureTestBaseWithRandomGame { private readonly IconFinder _iconFinder = new(); @@ -57,7 +55,7 @@ public void FindIcon_Game_NotInstalledWrongLocation() [Fact] public void FindIcon_Mod_NotInstalled() { - var mod = Game.InstallAndAddMod("Mod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var mod = GameInstallation.InstallAndAddMod("Mod").Mod; FileSystem.File.Create(FileSystem.Path.Combine(mod.Directory.FullName, "Data", "icon.ico")); FileSystem.File.Create(FileSystem.Path.Combine(mod.Directory.FullName, "icon.txt")); FileSystem.File.Create(FileSystem.Path.Combine(mod.Directory.FullName, "icon.ic")); @@ -67,8 +65,7 @@ public void FindIcon_Mod_NotInstalled() [Fact] public void FindIcon_Mod_Installed() { - var mod = Game.InstallAndAddMod("Mod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - + var mod = GameInstallation.InstallAndAddMod("Mod").Mod; var icon1 = $"{FileSystem.Path.GetRandomFileName()}.ico"; var icon2 = $"{FileSystem.Path.GetRandomFileName()}.ico"; @@ -87,7 +84,7 @@ public void FindIcon_Mod_Installed() [Fact] public void FindIcon_Mod_UseIconFromFs_ModinfoIconIsNull() { - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), new ModinfoData("name"), ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(new ModinfoData("name")).Mod; var icon1 = $"{FileSystem.Path.GetRandomFileName()}.ico"; var icon2 = $"{FileSystem.Path.GetRandomFileName()}.ico"; @@ -107,10 +104,10 @@ public void FindIcon_Mod_UseIconFromFs_ModinfoIconIsNull() [Fact] public void FindIcon_Mod_UseIconFromFs_ModinfoIconIsEmpty() { - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), new ModinfoData("name") + var mod = GameInstallation.InstallAndAddMod(new ModinfoData("name") { Icon = string.Empty - }, ServiceProvider); + }).Mod; var icon1 = $"{FileSystem.Path.GetRandomFileName()}.ico"; var icon2 = $"{FileSystem.Path.GetRandomFileName()}.ico"; @@ -130,10 +127,10 @@ public void FindIcon_Mod_UseIconFromFs_ModinfoIconIsEmpty() [Fact] public void FindIcon_Mod_UseIconFromModinfo() { - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), new ModinfoData("name") + var mod = GameInstallation.InstallAndAddMod(new ModinfoData("name") { Icon = "icon.ico" - }, ServiceProvider); + }).Mod; var icon1 = $"{FileSystem.Path.GetRandomFileName()}.ico"; var icon2 = $"{FileSystem.Path.GetRandomFileName()}.ico"; @@ -153,7 +150,7 @@ public void FindIcon_Mod_UseIconFromGame() FileSystem.File.Create(FileSystem.Path.Combine(Game.Directory.FullName, "foc.ico")); var expectedFileName = Game.Type == GameType.Eaw ? "eaw.ico" : "foc.ico"; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), new ModinfoData("name"), ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(new ModinfoData("name")).Mod; FileSystem.File.Create(FileSystem.Path.Combine(mod.Directory.FullName, "Data", "notAnIcon.ico")); @@ -167,7 +164,7 @@ public void FindIcon_Mod_UseIconFromGame() [Fact] public void FindIcon_VirtualMod_UseIconFromModinfo() { - var dep = Game.InstallAndAddMod("dep", false, ServiceProvider); + var dep = GameInstallation.InstallAndAddMod("Mod", false).Mod; var mod = new VirtualMod(Game, "Mod", new ModinfoData("Mod") { diff --git a/test/PG.StarWarsGame.Infrastructure.Test/Services/LanguageFinderTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Test/Services/LanguageFinderTestBase.cs index 04c3bfb0..99da7aa6 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/Services/LanguageFinderTestBase.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/Services/LanguageFinderTestBase.cs @@ -1,19 +1,18 @@ -using System; -using System.Collections.Generic; -using AET.Modinfo.Model; +using AET.Modinfo.Model; using AET.Modinfo.Spec; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Language; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; using PG.StarWarsGame.Infrastructure.Testing.TestBases; +using System; +using System.Collections.Generic; using Xunit; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; namespace PG.StarWarsGame.Infrastructure.Test.Services; -public class LanguageFinderTest : CommonTestBaseWithRandomGame +public class LanguageFinderTest : GameInfrastructureTestBaseWithRandomGame { private readonly InstalledLanguageFinder _languageFinder; @@ -22,8 +21,9 @@ public LanguageFinderTest() _languageFinder = new InstalledLanguageFinder(ServiceProvider); } - private void InstallGameLanguage(LanguageInfo language) => Game.InstallLanguage(language); - private void InstallModLanguage(IPhysicalMod mod, LanguageInfo language) => mod.InstallLanguage(language); + private void InstallGameLanguage(LanguageInfo language) => GameInstallation.InstallLanguage(language); + + private void InstallModLanguage(ITestingPhysicalModInstallation modInstallation, LanguageInfo language) => modInstallation.InstallLanguage(language); [Fact] public void Ctor_NullArgTest_Throws() @@ -62,7 +62,7 @@ public void FindLanguages_Game_WithLanguages_En_De() public void FindLanguages_Mod_WithNoLanguages_UsesGame() { InstallGameLanguage(new LanguageInfo("de", LanguageSupportLevel.SFX)); - var mod = Game.InstallMod("myMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var mod = GameInstallation.InstallMod("myMod").Mod; var langs = _languageFinder.FindLanguages(mod); Assert.Equivalent(new List { new LanguageInfo("de", LanguageSupportLevel.SFX) }, langs, true); @@ -71,12 +71,12 @@ public void FindLanguages_Mod_WithNoLanguages_UsesGame() [Fact] public void FindLanguages_Mod_WithLanguages_En_De_Steam() { - var game = FileSystem.InstallGame(new GameIdentity(GameType.Foc, GamePlatform.SteamGold), ServiceProvider); - var mod = game.InstallMod("myMod", true, ServiceProvider); - InstallModLanguage(mod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - InstallModLanguage(mod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + var game = GameInfrastructureTesting.Game(new GameIdentity(GameType.Foc, GamePlatform.SteamGold), ServiceProvider); + var modInstallation = game.InstallMod("myMod", true); + InstallModLanguage(modInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + InstallModLanguage(modInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); - var langs = _languageFinder.FindLanguages(mod); + var langs = _languageFinder.FindLanguages(modInstallation.Mod); Assert.Equivalent(new List { @@ -88,18 +88,18 @@ public void FindLanguages_Mod_WithLanguages_En_De_Steam() [Fact] public void FindLanguages_Mod_InheritLanguage_TargetModDoesNotHaveLanguages() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - InstallModLanguage(baseMod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + InstallModLanguage(baseModInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List { - new ModReference(baseMod) + new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modInfo).Mod; mod.ResolveDependencies(); var langs = _languageFinder.FindLanguages(mod); @@ -114,7 +114,7 @@ public void FindLanguages_Mod_InheritLanguage_TargetModDoesNotHaveLanguages() [Fact] public void FindLanguages_Mod_InheritLanguage_TargetAndDependencyModDoNotHaveLanguages() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var baseMod = GameInstallation.InstallAndAddMod("baseMod").Mod; var modInfo = new ModinfoData("myMod") { @@ -123,7 +123,7 @@ public void FindLanguages_Mod_InheritLanguage_TargetAndDependencyModDoNotHaveLan new ModReference(baseMod) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modInfo).Mod; mod.ResolveDependencies(); var langs = _languageFinder.FindLanguages(mod); @@ -134,7 +134,7 @@ public void FindLanguages_Mod_InheritLanguage_TargetAndDependencyModDoNotHaveLan [Fact] public void FindLanguages_Mod_InheritLanguage_TargetModDoesNotHaveLanguagesAndDependencyIsNotResolved() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var baseMod = GameInstallation.InstallAndAddMod("baseMod").Mod; var modInfo = new ModinfoData("myMod") { @@ -143,7 +143,7 @@ public void FindLanguages_Mod_InheritLanguage_TargetModDoesNotHaveLanguagesAndDe new ModReference(baseMod) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var mod = GameInstallation.InstallMod(modInfo).Mod; // Do not resolve dependencies here! var langs = _languageFinder.FindLanguages(mod); @@ -154,22 +154,23 @@ public void FindLanguages_Mod_InheritLanguage_TargetModDoesNotHaveLanguagesAndDe [Fact] public void FindLanguages_Mod_TargetModDoesHaveDefaultLanguageInstalled() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - InstallModLanguage(baseMod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + InstallModLanguage(baseModInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List { - new ModReference(baseMod) + new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var modInstallation = GameInstallation.InstallAndAddMod(modInfo); + var mod = modInstallation.Mod; mod.ResolveDependencies(); // Only english is installed - InstallModLanguage(mod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + InstallModLanguage(modInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); var langs = _languageFinder.FindLanguages(mod); @@ -180,16 +181,15 @@ public void FindLanguages_Mod_TargetModDoesHaveDefaultLanguageInstalled() [Fact] public void FindLanguages_Mod_TargetModDoesHaveModinfoLanguages() { - - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - InstallModLanguage(baseMod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + InstallModLanguage(baseModInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List { - new ModReference(baseMod) + new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.FullResolved), Languages = new List { @@ -197,11 +197,12 @@ public void FindLanguages_Mod_TargetModDoesHaveModinfoLanguages() new LanguageInfo("de", LanguageSupportLevel.SFX) } }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var modInstallation = GameInstallation.InstallAndAddMod(modInfo); + var mod = modInstallation.Mod; mod.ResolveDependencies(); // Should not be considered - InstallModLanguage(mod, new LanguageInfo("it", LanguageSupportLevel.FullLocalized)); + InstallModLanguage(modInstallation, new LanguageInfo("it", LanguageSupportLevel.FullLocalized)); var langs = _languageFinder.FindLanguages(mod); @@ -217,24 +218,25 @@ public void FindLanguages_Mod_TargetModDoesHaveModinfoLanguages() [Fact] public void FindLanguages_Mod_TargetModDoesHaveModinfoWithDefaultLanguagesExplicitlySet() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - InstallModLanguage(baseMod, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + InstallModLanguage(baseModInstallation, new LanguageInfo("en", LanguageSupportLevel.FullLocalized)); var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List { - new ModReference(baseMod) + new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.FullResolved), // Set language Languages = new List { LanguageInfo.Default } }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var modInstallation = GameInstallation.InstallAndAddMod(modInfo); + var mod = modInstallation.Mod; mod.ResolveDependencies(); // Should not be considered - InstallModLanguage(mod, new LanguageInfo("it", LanguageSupportLevel.FullLocalized)); + InstallModLanguage(modInstallation, new LanguageInfo("it", LanguageSupportLevel.FullLocalized)); var langs = _languageFinder.FindLanguages(mod); @@ -249,7 +251,7 @@ public void FindLanguages_Mod_TargetModDoesHaveModinfoWithDefaultLanguagesExplic public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndDependencyAlsoDoesNotHaveLanguages_UsesGameFallback() { InstallGameLanguage(new LanguageInfo("de", LanguageSupportLevel.SFX)); - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var baseMod = GameInstallation.InstallAndAddMod("baseMod").Mod; var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List @@ -257,7 +259,7 @@ public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndDependencyAlsoDoes new ModReference(baseMod) }, DependencyResolveLayout.FullResolved) }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modInfo).Mod; mod.ResolveDependencies(); var langs = _languageFinder.FindLanguages(mod); @@ -268,16 +270,16 @@ public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndDependencyAlsoDoes [Fact] public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndTransitiveDependencyHasLanguages() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); var middleModInfo = new ModinfoData("middleMod") { Dependencies = new DependencyList(new List { - new ModReference(baseMod) + new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.FullResolved) }; - var middleMod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), middleModInfo, ServiceProvider); + var middleMod = GameInstallation.InstallAndAddMod(middleModInfo).Mod; var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List @@ -285,7 +287,7 @@ public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndTransitiveDependen new ModReference(middleMod) }, DependencyResolveLayout.ResolveRecursive) }; - var mod = Game.InstallAndAddMod(GITestUtilities.GetRandomWorkshopFlag(Game), modInfo, ServiceProvider); + var mod = GameInstallation.InstallAndAddMod(modInfo).Mod; mod.ResolveDependencies(); var langs = _languageFinder.FindLanguages(mod); @@ -296,14 +298,14 @@ public void FindLanguages_Mod_TargetModDoesNotHaveLanguagesAndTransitiveDependen [Fact] public void FindLanguages_VirtualMod_TargetModDoesNotHaveLanguagesAndSecondDependencyHasLanguages() { - var baseMod = Game.InstallAndAddMod("baseMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); - InstallModLanguage(baseMod, new LanguageInfo("de", LanguageSupportLevel.SFX)); - var middleMod = Game.InstallAndAddMod("middleMod", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + var baseModInstallation = GameInstallation.InstallAndAddMod("baseMod"); + InstallModLanguage(baseModInstallation, new LanguageInfo("de", LanguageSupportLevel.SFX)); + var middleMod = GameInstallation.InstallAndAddMod("middleMod").Mod; var modInfo = new ModinfoData("myMod") { Dependencies = new DependencyList(new List { - new ModReference(middleMod), new ModReference(baseMod) + new ModReference(middleMod), new ModReference(baseModInstallation.Mod) }, DependencyResolveLayout.ResolveRecursive) }; var mod = new VirtualMod(Game, "VirtualModId", modInfo, ServiceProvider); @@ -319,7 +321,7 @@ public void FindLanguages_VirtualMod_TargetModDoesNotHaveLanguagesAndSecondDepen [Fact] public void FindLanguages_Mod_FromModinfo_WithNoLanguages() { - var mod = Game.InstallMod(GITestUtilities.GetRandomWorkshopFlag(Game), new ModinfoData("myMod"), ServiceProvider); + var mod = GameInstallation.InstallMod(new ModinfoData("myMod")).Mod; var langs = _languageFinder.FindLanguages(mod); Assert.Equivalent(new List(), langs, true); } diff --git a/test/PG.StarWarsGame.Infrastructure.Test/VirtualModTest.cs b/test/PG.StarWarsGame.Infrastructure.Test/VirtualModTest.cs index 3e0ae39f..4722df50 100644 --- a/test/PG.StarWarsGame.Infrastructure.Test/VirtualModTest.cs +++ b/test/PG.StarWarsGame.Infrastructure.Test/VirtualModTest.cs @@ -6,8 +6,8 @@ using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Mods; using PG.StarWarsGame.Infrastructure.Services.Dependencies; -using PG.StarWarsGame.Infrastructure.Testing; -using PG.StarWarsGame.Infrastructure.Testing.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; using Semver; using Xunit; @@ -15,7 +15,7 @@ namespace PG.StarWarsGame.Infrastructure.Test; public class VirtualModTest : ModBaseTest { - private VirtualMod CreateVirtualMod( + private ITestingVirtualModInstallation CreateVirtualMod( string name, string? iconPath = null, ICollection? languages = null, @@ -25,7 +25,7 @@ private VirtualMod CreateVirtualMod( IModDependencyList depList; if (deps.Count == 0) { - var dep = CreateOtherMod("dep", false); + var dep = GameInstallation.InstallAndAddMod("dep", false).Mod; depList = new DependencyList(new List { dep }, layout); } else @@ -40,12 +40,10 @@ private VirtualMod CreateVirtualMod( Dependencies = depList }; - var mod = new VirtualMod(Game, "VirtualModId", modinfo, ServiceProvider); - Game.AddMod(mod); - return mod; + return GetOrCreateGameInstallation().AddVirtualMod("VirtualModId", modinfo); } - protected override ModBase CreateMod( + protected override ITestingModInstallation CreateAndAddModInstallation( string name, DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, params IList deps) @@ -53,22 +51,22 @@ protected override ModBase CreateMod( return CreateVirtualMod(name, layout: layout, deps: deps); } - protected override IPlayableObject CreatePlayableObject( + protected override ITestingPlayableObjectInstallation CreatePlayableObjectInstallation( string? iconPath = null, ICollection? languages = null) { return CreateVirtualMod("Mod", iconPath, languages); } - protected override PlayableModContainer CreateModContainer() + protected override ITestingModContainerInstallation CreateModContainerInstallation() { - return CreateMod("Mod"); + return CreateAndAddModInstallation("Mod"); } [Fact] public void InvalidCtor_ArgumentNull_Throws() { - Game.InstallAndAddMod("Dep", GITestUtilities.GetRandomWorkshopFlag(Game), ServiceProvider); + GameInstallation.InstallAndAddMod("Dep"); Assert.Throws(() => new VirtualMod(null!, "VirtualModId", new ModinfoData("Name"), ServiceProvider)); Assert.Throws(() => new VirtualMod(Game, "VirtualModId", null!, ServiceProvider)); @@ -92,7 +90,7 @@ public void Ctor_EmptyDependencies_Throws() [Fact] public void Ctor_FromModinfo_Properties() { - var dep = CreateOtherMod("dep"); + var dep = GameInstallation.InstallAndAddMod("dep").Mod; var modinfo = new ModinfoData("VirtualMod") { diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Clients/TestGameProcessLauncher.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Clients/TestGameProcessLauncher.cs index 24781aed..7ff7e9ef 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Clients/TestGameProcessLauncher.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Clients/TestGameProcessLauncher.cs @@ -1,22 +1,72 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; using System.Diagnostics; using System.IO.Abstractions; using System.Runtime.InteropServices; +using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Clients; using PG.StarWarsGame.Infrastructure.Clients.Processes; +using Xunit; namespace PG.StarWarsGame.Infrastructure.Testing.Clients; -public class TestGameProcessLauncher : IGameProcessLauncher, IDisposable +/// +/// Provides a test implementation for launching game processes and asserting the process creation in a controlled testing environment. +/// +/// +/// This class is designed to simulate the behavior of a game process launcher, allowing for assertions and +/// controlled exceptions during testing scenarios. It ensures that the expected executable and process +/// information match the provided inputs. +/// +public sealed class TestGameProcessLauncher : IGameProcessLauncher, IDisposable { private Process? _process; + /// + /// Gets or sets a value indicating whether the should throw + /// a when attempting to start a game process. + /// + /// + /// if a should be thrown during the game process start; + /// otherwise, . + /// + /// + /// This property is primarily used in testing scenarios to simulate failure conditions + /// when starting a game process. + /// public bool ThrowsGameStartException { get; set; } + /// + /// Gets or sets the expected executable file for the game process during testing. + /// public IFileInfo ExpectedExecutable { get; set; } = null!; + /// + /// Gets or sets the expected process information used for validating the game process during testing. + /// public GameProcessInfo ExpectedProcessInfo { get; set; } = null!; + /// + /// Registers the specified instance as a singleton service in the provided . + /// + /// The to which the service will be added. + /// The instance to register as the implementation of . + public static void RegisterAsService(IServiceCollection serviceCollection, TestGameProcessLauncher processLauncher) + { + serviceCollection.AddSingleton(processLauncher); + } + + /// + /// Initiates the execution of a fake game process using the provided executable. + /// The inputs and are for asserted + /// against and . + /// + /// The executable file that will be launched to start the game process. + /// An object containing details about the game process, such as the game instance, build type, and any additional arguments. + /// A new instance of representing the running game process. + /// Thrown if is set to . public IGameProcess StartGameProcess(IFileInfo executable, GameProcessInfo processInfo) { Assert.Equal(ExpectedExecutable.FullName, executable.FullName); @@ -36,6 +86,14 @@ public IGameProcess StartGameProcess(IFileInfo executable, GameProcessInfo proce return new GameProcess(process, processInfo); } + /// + /// Releases the resources used by the instance, including terminating + /// and disposing of any associated game process. + /// + /// + /// This method ensures that any running game process started by this launcher is properly terminated + /// and its resources are released. Exceptions during the disposal process are suppressed. + /// public void Dispose() { try diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/GITestUtilities.cs b/test/PG.StarWarsGame.Infrastructure.Testing/GITestUtilities.cs index c5ef6ac9..6677b6be 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/GITestUtilities.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/GITestUtilities.cs @@ -1,16 +1,37 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.Modinfo.Model; +using AET.Modinfo.Spec; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; +using System; +using System.Collections.Generic; +using System.Linq; +using AnakinRaW.CommonUtilities.Testing.Extensions; +using Xunit; namespace PG.StarWarsGame.Infrastructure.Testing; // ReSharper disable once InconsistentNaming +/// +/// Provides utility methods for testing game infrastructure components. +/// public static class GITestUtilities { + private static readonly string[] PossibleLanguages = ["en", "de", "es", "it"]; + + /// + /// Gets a collection of real game platforms. + /// public static ICollection RealPlatforms { get; } = [GamePlatform.Disk, GamePlatform.DiskGold, GamePlatform.SteamGold, GamePlatform.GoG, GamePlatform.Origin]; + /// + /// Verifies that two instances are equal by comparing their properties. + /// + /// The expected instance. + /// The actual instance to compare against the expected one. public static void AssertEqual(this GameDetectionResult expected, GameDetectionResult actual) { Assert.Equal(expected.Installed, actual.Installed); @@ -19,10 +40,99 @@ public static void AssertEqual(this GameDetectionResult expected, GameDetectionR Assert.Equal(expected.InitializationRequired, actual.InitializationRequired); } - public static bool GetRandomWorkshopFlag(IGame game) + /// + /// Generates a random workshop flag for the specified game based on its platform. + /// + /// The game identity for which the workshop flag is being determined. + /// + /// A random value, which is never if does not support workshops. + /// + public static bool GetRandomWorkshopFlag(IGameIdentity game) { if (game.Platform is not GamePlatform.SteamGold) return false; - return new Random().NextDouble() >= 0.5; + return Random.Bool(); + } + + /// + /// Retrieves a collection of real game platforms as enumerable test data. + /// + /// + /// An of object arrays, where each array contains a single . + /// + public static IEnumerable GetRealPlatforms() + { + return RealPlatforms.Select(platform => (object[])[platform]); + } + + /// + /// Generates a collection of real game identities for testing purposes. + /// + /// + /// This method yields game identities for all supported platforms and game types, + /// including both Empire at War (Eaw) and Forces of Corruption (Foc). + /// + /// + /// An of arrays where each element contains + /// a single instance representing a specific game type and platform. + /// + public static IEnumerable RealGameIdentities() + { + foreach (var platform in RealPlatforms) + { + yield return [new GameIdentity(GameType.Eaw, platform)]; + yield return [new GameIdentity(GameType.Foc, platform)]; + } + } + + /// + /// Generates a collection of random languages with also randomized support levels. + /// + /// + /// A collection of objects, where each object represents a language + /// and its corresponding support level. + /// + public static ICollection GetRandomLanguages() + { + var languages = new HashSet(); + + foreach (var _ in PossibleLanguages) + { + var code = Random.Item(PossibleLanguages); + var support = Random.Enum(); + languages.Add(new LanguageInfo(code, support)); + } + + return languages; + } + + /// + /// Generates a random instance. + /// + /// + /// If set to , the method will only use platforms defined in . + /// If set to , the method will include also the platform. + /// + /// + /// A randomly generated object, containing a random + /// and a platform determined by the parameter. + /// + public static IGameIdentity GetRandomGameIdentity(bool realOnly = true) + { + var platforms = realOnly ? RealPlatforms : (GamePlatform[])Enum.GetValues(typeof(GamePlatform)); + return new GameIdentity(Random.Enum(), Random.Item(platforms)); + } + + /// + /// Gets the opposite . + /// + /// The current . + /// + /// The opposite . If the input is , the result is ; + /// if the input is , the result is . + /// + public static GameType Opposite(this GameType type) + { + return (GameType)((int)type ^ 1); } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.cs deleted file mode 100644 index f17b0f9d..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.IO.Abstractions; -using PG.StarWarsGame.Infrastructure.Games; -using Testably.Abstractions.Testing; - -namespace PG.StarWarsGame.Infrastructure.Testing.Game.Installation; - -public static partial class GameInstallation -{ - // Ensure starts on path 'steam'. See SteamInstallation.cs - private const string SteamBasePath = "steam/steamapps/common/Star Wars Empire at War"; - private const string GogBasePath = "games/gog"; - private const string OriginBasePath = "games/origin"; - - public static PetroglyphStarWarsGame InstallGame(this MockFileSystem fs, GameIdentity gameIdentity, IServiceProvider sp) - { - Func installFunc; - - if (gameIdentity.Type == GameType.Foc) - installFunc = InstallFoc; - else - installFunc = InstallEaw; - - var gameDir = installFunc(fs, gameIdentity.Platform); - - fs.InstallModsLocations(gameDir); - - var game = new PetroglyphStarWarsGame(gameIdentity, gameDir, gameIdentity.ToString(), sp); - Assert.True(game.Exists()); - return game; - } - - public static void InstallDebug(this IGame game) - { - if (game.Platform is not GamePlatform.SteamGold) - Assert.Fail($"Cannot install Debug files for non-Steam game '{game}'"); - - var fs = game.Directory.FileSystem; - CreateFile(fs, fs.Path.Combine(game.Directory.FullName, "StarWarsI.exe")); - } - - private static void InstallDataAndMegaFilesXml(this MockFileSystem fs, IDirectoryInfo directory) - { - fs.Initialize(); - CreateFile(fs, fs.Path.Combine(directory.FullName, "Data", "megafiles.xml")); - } - - private static void InstallSteamFiles(this MockFileSystem fs, Action initAction) - { - fs.Initialize(); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "32470_install.vdf")); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "32472_install.vdf")); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme.dat")); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "runm2.dat")); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme.exe")); - CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme2.exe")); - - fs.Directory.CreateDirectory(fs.Path.Combine(SteamBasePath, "..", "..", "workshop", "content", "32470")); - initAction(); - } - - private static void InstallGoGFiles(this MockFileSystem fs, Action initAction) - { - fs.Initialize(); - CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame.sdb")); - CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame-1421404887.hashdb")); - CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame-1421404887.info")); - CreateFile(fs, fs.Path.Combine(GogBasePath, "Language.exe")); - initAction(); - } - - private static void InstallOriginFiles(this MockFileSystem fs, Action initAction) - { - fs.Initialize(); - fs.Directory.CreateDirectory(fs.Path.Combine(OriginBasePath, "Manuals")); - fs.Directory.CreateDirectory(fs.Path.Combine(OriginBasePath, "__Installer")); - initAction(); - } - - private static void InstallModsLocations(this MockFileSystem fileSystem, IDirectoryInfo directory) - { - fileSystem.Directory.CreateDirectory(fileSystem.Path.Combine(directory.FullName, "Mods")); - } - - private static void CreateFile(IFileSystem fs, string path) - { - var dir = fs.Path.GetDirectoryName(path)!; - fs.Directory.CreateDirectory(dir); - using var file = fs.File.Create(path); - } -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/TestGameRegistrySetupData.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/TestGameRegistrySetupData.cs deleted file mode 100644 index c7954677..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/TestGameRegistrySetupData.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.IO.Abstractions; -using PG.StarWarsGame.Infrastructure.Games; - -namespace PG.StarWarsGame.Infrastructure.Testing.Game.Registry; - -public class TestGameRegistrySetupData -{ - public required GameType GameType { get; init; } - - public bool CreateRegistry { get; set; } - - public bool InitRegistry { get; set; } - - public string? InstallPath { get; set; } - - public int? Revision { get; set; } - - public int? EawGold { get; set; } - - public string? Launcher { get; set; } - - public string? CdKey { get; set; } - - public static TestGameRegistrySetupData Uninitialized(GameType gameType) - { - return new TestGameRegistrySetupData - { - GameType = gameType, - CreateRegistry = true, - InitRegistry = false - }; - } - - public static TestGameRegistrySetupData Installed(GameType gameType, IDirectoryInfo gameLocation) - { - var revision = gameType == GameType.Eaw ? 10105 : 10100; - var launcherPath = gameType == GameType.Eaw ? $"{gameLocation.FullName}\\LaunchEAW.exe" : null; - - return new TestGameRegistrySetupData - { - GameType = gameType, - CreateRegistry = true, - InitRegistry = true, - Revision = revision, - EawGold = 20070323, - CdKey = "%CDKEY%", - InstallPath = gameLocation.FullName, - Launcher = launcherPath, - }; - } -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Eaw.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Eaw.cs similarity index 80% rename from test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Eaw.cs rename to test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Eaw.cs index bcce128d..5994c21f 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Eaw.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Eaw.cs @@ -1,17 +1,20 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; using System.IO.Abstractions; using PG.StarWarsGame.Infrastructure.Games; using Testably.Abstractions.Testing; -namespace PG.StarWarsGame.Infrastructure.Testing.Game.Installation; +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; -public static partial class GameInstallation +internal static partial class GameInstallationHelper { private const string EawNormalPath = "games/eaw"; private const string EawGoldPath = "games/gold/eaw"; private const string EawGameDataSubPath = "GameData"; - private static IDirectoryInfo InstallEaw(this MockFileSystem fs, GamePlatform platform) + internal static IDirectoryInfo InstallEaw(IFileSystem fs, GamePlatform platform) { IDirectoryInfo gameDirectory; switch (platform) @@ -39,7 +42,7 @@ private static IDirectoryInfo InstallEaw(this MockFileSystem fs, GamePlatform pl return gameDirectory; } - private static IDirectoryInfo InstallEawDisk(this MockFileSystem fs) + private static IDirectoryInfo InstallEawDisk(this IFileSystem fs) { fs.Initialize(); CreateFile(fs, fs.Path.Combine(EawNormalPath, "sweaw.exe")); @@ -47,7 +50,7 @@ private static IDirectoryInfo InstallEawDisk(this MockFileSystem fs) return gameDir; } - private static IDirectoryInfo InstallEawOrigin(this MockFileSystem fs) + private static IDirectoryInfo InstallEawOrigin(this IFileSystem fs) { var basePath = fs.Path.Combine(OriginBasePath, EawGameDataSubPath); @@ -58,7 +61,7 @@ private static IDirectoryInfo InstallEawOrigin(this MockFileSystem fs) return fs.DirectoryInfo.New(basePath); } - private static IDirectoryInfo InstallEawGog(this MockFileSystem fs) + private static IDirectoryInfo InstallEawGog(this IFileSystem fs) { var basePath = fs.Path.Combine(GogBasePath, EawGameDataSubPath); @@ -70,7 +73,7 @@ private static IDirectoryInfo InstallEawGog(this MockFileSystem fs) return fs.DirectoryInfo.New(basePath); } - private static IDirectoryInfo InstallEawSteam(this MockFileSystem fs) + private static IDirectoryInfo InstallEawSteam(this IFileSystem fs) { var basePath = fs.Path.Combine(SteamBasePath, EawGameDataSubPath); @@ -82,7 +85,7 @@ private static IDirectoryInfo InstallEawSteam(this MockFileSystem fs) return fs.DirectoryInfo.New(fs.Path.Combine(basePath)); } - private static IDirectoryInfo InstallEawDiskGold(this MockFileSystem fs) + private static IDirectoryInfo InstallEawDiskGold(this IFileSystem fs) { fs.Initialize(); CreateFile(fs, fs.Path.Combine(EawGoldPath, EawGameDataSubPath, "sweaw.exe")); diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Foc.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Foc.cs similarity index 79% rename from test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Foc.cs rename to test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Foc.cs index 24eaa91e..1d71c3d3 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Installation/GameInstallation.Foc.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.Foc.cs @@ -1,11 +1,14 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; using System.IO.Abstractions; using PG.StarWarsGame.Infrastructure.Games; using Testably.Abstractions.Testing; -namespace PG.StarWarsGame.Infrastructure.Testing.Game.Installation; +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; -public static partial class GameInstallation +internal static partial class GameInstallationHelper { private const string FocNormalPath = "games/foc"; private const string FocGoldPath = "games/gold/foc"; @@ -13,12 +16,7 @@ public static partial class GameInstallation private const string FocGogSubPath = "EAWX"; private const string FocOriginSubPath = "EAWX"; - public static IDirectoryInfo GetWrongOriginFocRegistryLocation(this IFileSystem fs) - { - return fs.DirectoryInfo.New(fs.Path.Combine(OriginBasePath, "corruption")); - } - - public static IDirectoryInfo InstallFoc(MockFileSystem fs, GamePlatform platform) + public static IDirectoryInfo InstallFoc(IFileSystem fs, GamePlatform platform) { IDirectoryInfo gameDirectory; switch (platform) @@ -46,7 +44,7 @@ public static IDirectoryInfo InstallFoc(MockFileSystem fs, GamePlatform platform return gameDirectory; } - private static IDirectoryInfo InstallFocDisk(this MockFileSystem fs) + private static IDirectoryInfo InstallFocDisk(this IFileSystem fs) { fs.Initialize(); CreateFile(fs, fs.Path.Combine(FocNormalPath, "swfoc.exe")); @@ -54,7 +52,7 @@ private static IDirectoryInfo InstallFocDisk(this MockFileSystem fs) return gameDir; } - private static IDirectoryInfo InstallFocOrigin(this MockFileSystem fs) + private static IDirectoryInfo InstallFocOrigin(this IFileSystem fs) { var basePath = fs.Path.Combine(OriginBasePath, FocOriginSubPath); @@ -66,7 +64,7 @@ private static IDirectoryInfo InstallFocOrigin(this MockFileSystem fs) return fs.DirectoryInfo.New(basePath); } - private static IDirectoryInfo InstallFocGog(this MockFileSystem fs) + private static IDirectoryInfo InstallFocGog(this IFileSystem fs) { var basePath = fs.Path.Combine(GogBasePath, FocGogSubPath); @@ -77,7 +75,7 @@ private static IDirectoryInfo InstallFocGog(this MockFileSystem fs) return fs.DirectoryInfo.New(basePath); } - private static IDirectoryInfo InstallFocSteam(this MockFileSystem fs) + private static IDirectoryInfo InstallFocSteam(this IFileSystem fs) { var basePath = fs.Path.Combine(SteamBasePath, FocSteamSubPath); @@ -89,7 +87,7 @@ private static IDirectoryInfo InstallFocSteam(this MockFileSystem fs) return fs.DirectoryInfo.New(basePath); } - private static IDirectoryInfo InstallFocDiskGold(this MockFileSystem fs) + private static IDirectoryInfo InstallFocDiskGold(this IFileSystem fs) { fs.Initialize(); CreateFile(fs, fs.Path.Combine(FocGoldPath, "swfoc.exe")); diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.cs new file mode 100644 index 00000000..02f7e041 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/GameInstallationHelper.cs @@ -0,0 +1,66 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.IO.Abstractions; +using Testably.Abstractions.Testing; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +internal static partial class GameInstallationHelper +{ + // Ensure starts on path 'steam'. See SteamInstallation.cs + internal const string SteamBasePath = "steam/steamapps/common/Star Wars Empire at War"; + internal const string GogBasePath = "games/gog"; + internal const string OriginBasePath = "games/origin"; + + private static void InstallDataAndMegaFilesXml(this IFileSystem fs, IDirectoryInfo directory) + { + fs.Initialize(); + CreateFile(fs, fs.Path.Combine(directory.FullName, "Data", "megafiles.xml")); + } + + private static void InstallSteamFiles(this IFileSystem fs, Action initAction) + { + fs.Initialize(); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "32470_install.vdf")); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "32472_install.vdf")); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme.dat")); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "runm2.dat")); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme.exe")); + CreateFile(fs, fs.Path.Combine(SteamBasePath, "runme2.exe")); + + fs.Directory.CreateDirectory(fs.Path.Combine(SteamBasePath, "..", "..", "workshop", "content", "32470")); + initAction(); + } + + private static void InstallGoGFiles(this IFileSystem fs, Action initAction) + { + fs.Initialize(); + CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame.sdb")); + CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame-1421404887.hashdb")); + CreateFile(fs, fs.Path.Combine(GogBasePath, "goggame-1421404887.info")); + CreateFile(fs, fs.Path.Combine(GogBasePath, "Language.exe")); + initAction(); + } + + private static void InstallOriginFiles(this IFileSystem fs, Action initAction) + { + fs.Initialize(); + fs.Directory.CreateDirectory(fs.Path.Combine(OriginBasePath, "Manuals")); + fs.Directory.CreateDirectory(fs.Path.Combine(OriginBasePath, "__Installer")); + initAction(); + } + + internal static void InstallModsLocations(this IFileSystem fileSystem, IDirectoryInfo directory) + { + fileSystem.Directory.CreateDirectory(fileSystem.Path.Combine(directory.FullName, "Mods")); + } + + internal static void CreateFile(IFileSystem fs, string path) + { + var dir = fs.Path.GetDirectoryName(path)!; + fs.Directory.CreateDirectory(dir); + using var file = fs.File.Create(path); + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/ITestingGameInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/ITestingGameInstallation.cs new file mode 100644 index 00000000..22fc129e --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/ITestingGameInstallation.cs @@ -0,0 +1,164 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using AET.Modinfo.Model; +using AET.Modinfo.Spec; +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; +using System.IO.Abstractions; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +/// +/// Represents an abstraction for a test installation game installation, providing methods and properties to install mods. +/// +public interface ITestingGameInstallation : ITestingModContainerInstallation, ITestingPhysicalPlayableObjectInstallation +{ + /// + /// Gets the game instance associated with this installation. + /// + IGame Game { get; } + + /// + /// Installs debug executable files to the game installation. + /// + void InstallDebug(); + + /// + /// Retrieves the incorrect directory from the EA Origin Forces of Corruption setup that gets written to the registry. + /// + /// The directory information of the incorrect registry location. + IDirectoryInfo GetWrongOriginFocRegistryLocation(); + + /// + /// Installs a mod with the specified name. + /// + /// + /// Depending on the platform of the game installation, the installed mod is randomly selected to be a normal or Workshops mod. + /// + /// The name of the mod to install. + /// An instance of representing the installed mod. + ITestingPhysicalModInstallation InstallMod(string name); + + /// + /// Installs a mod with the specified name and workshop flag. + /// + /// The name of the mod to install. + /// Indicates whether the mod is a Workshops mod. + /// An instance of representing the installed mod. + ITestingPhysicalModInstallation InstallMod(string name, bool workshop); + + /// + /// Installs a mod using the provided mod information. + /// + /// + /// Depending on the platform of the game installation, the installed mod is randomly selected to be a normal or Workshops mod. + /// + /// The mod information to use for installation. + /// An instance of representing the installed mod. + ITestingPhysicalModInstallation InstallMod(IModinfo modinfo); + + /// + /// Installs a mod using the provided mod information and workshop flag. + /// + /// The mod information to use for installation. + /// Indicates whether the mod is a Workshops mod. + /// An instance of representing the installed mod. + ITestingPhysicalModInstallation InstallMod(IModinfo modinfo, bool workshop); + + /// + /// Installs a mod using the provided mod information, directory, and workshop flag. + /// + /// The mod information to use for installation. + /// The directory where the mod will be installed. + /// Indicates whether the mod is a workshop mod. + /// An instance of representing the installed mod. + ITestingPhysicalModInstallation InstallMod(IModinfo modinfo, IDirectoryInfo directory, bool workshop); + + /// + /// Installs and adds a mod with the specified name to the game installation. + /// + /// + /// Depending on the platform of the game installation, the installed mod is randomly selected to be a normal or Workshops mod. + /// + /// The name of the mod to install and add. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(string name); + + /// + /// Installs and adds a mod with the specified name and workshop flag to the game installation. + /// + /// The name of the mod to install and add. + /// Indicates whether the mod is a Workshops mod. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(string name, bool workshop); + + /// + /// Installs and adds a mod using the provided mod information to the game installation. + /// + /// + /// Depending on the platform of the game installation, the installed mod is randomly selected to be a normal or Workshops mod. + /// + /// The mod information to use for installation and addition. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo); + + /// + /// Installs and adds a mod using the provided mod information and workshop flag to the game installation. + /// + /// The mod information to use for installation and addition. + /// Indicates whether the mod is a Workshops mod. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo, bool workshop); + + /// + /// Installs and adds a mod using the provided mod information, directory, and workshop flag to the game installation. + /// + /// The mod information to use for installation and addition. + /// The directory where the mod will be installed and added. + /// Indicates whether the mod is a Workshops mod. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo, IDirectoryInfo directory, bool workshops); + + /// + /// Installs and adds a mod with the specified name, workshop flag, and dependencies to the game installation. + /// + /// The name of the mod to install and add. + /// Indicates whether the mod is a Workshops mod. + /// The dependencies of the mod. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(string name, bool isWorkshop, IModDependencyList dependencies); + + /// + /// Installs and adds a mod with the specified name and dependencies to the game installation. + /// + /// + /// Depending on the platform of the game installation, the installed mod is randomly selected to be a normal or Workshops mod. + /// + /// The name of the mod to install and add. + /// The dependencies of the mod. + /// An instance of representing the installed and added mod. + ITestingPhysicalModInstallation InstallAndAddMod(string name, IModDependencyList dependencies); + + /// + /// Adds a virtual mod with the specified name and mod information to the game installation. + /// + /// The name of the virtual mod to add. + /// The mod information of the virtual mod. + /// An instance of representing the added virtual mod. + ITestingVirtualModInstallation AddVirtualMod(string name, ModinfoData modinfo); + + /// + /// Gets the directory of a mod for the specified name and workshop flag. + /// + /// The created is not created on the file system. + /// The name of the mod. + /// Indicates whether the mod is a workshop mod. + /// The directory information of the mod. + /// + /// Thrown when is + /// but the associated game is not a Steam installation. + /// + IDirectoryInfo GetModDirectory(string name, bool workshop); +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/ITestingGameRegistry.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/ITestingGameRegistry.cs new file mode 100644 index 00000000..e5ddb391 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/ITestingGameRegistry.cs @@ -0,0 +1,40 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Games.Registry; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; + +/// +/// Represents an abstraction for a test registry that provides access to the actual . +/// +public interface ITestingGameRegistry +{ + /// + /// Creates a game registry instance for a game type that does not exist in the registry. + /// + /// The type of the game for which the registry should be created. + /// An instance of representing a non-existing game registry. + IGameRegistry CreateNonExistingRegistry(GameType gameType); + + /// + /// Creates a registry for a game that is considered installed. + /// + /// The game for which the registry is to be created. + /// An instance of representing the installed game registry. + IGameRegistry CreateInstalled(IGame game); + + /// + /// Creates an instance of based on the provided setup data. + /// + /// The setup data used to configure the game registry. + /// + /// An instance of configured according to the provided setup data. + /// + /// + /// This method is intended for testing purposes and allows for the creation of a game registry + /// that simulates various states, such as installed or uninitialized. + /// + IGameRegistry CreateFrom(TestGameRegistrySetupData registrySetupData); +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestGameRegistrySetupData.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestGameRegistrySetupData.cs new file mode 100644 index 00000000..344ab245 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestGameRegistrySetupData.cs @@ -0,0 +1,91 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System.IO.Abstractions; +using PG.StarWarsGame.Infrastructure.Games; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; + +/// +/// Represents the setup data for configuring a test game registry. +/// +public sealed class TestGameRegistrySetupData +{ + /// + /// Gets or sets the type of the game. + /// + public required GameType GameType { get; init; } + + /// + /// Gets or sets a value indicating whether to create the registry. + /// + public bool CreateRegistry { get; set; } + + /// + /// Gets or sets a value indicating whether to initialize the registry. + /// + public bool InitRegistry { get; set; } + + /// + /// Gets or sets the installation path of the game. + /// + public string? InstallPath { get; set; } + + /// + /// Gets or sets the revision number of the game. + /// + public int? Revision { get; set; } + + /// + /// Gets or sets the EAW Gold version identifier. + /// + public int? EawGold { get; set; } + + /// + /// Gets or sets the path to the game launcher. + /// + public string? Launcher { get; set; } + + /// + /// Gets or sets the CD key for the game. + /// + public string? CdKey { get; set; } + + /// + /// Creates an uninitialized setup data instance for the specified game type. + /// + /// The type of the game. + /// A new instance of with default values for uninitialized state. + public static TestGameRegistrySetupData Uninitialized(GameType gameType) + { + return new TestGameRegistrySetupData + { + GameType = gameType, + CreateRegistry = true, + InitRegistry = false + }; + } + + /// + /// Creates a setup data instance for an installed game. + /// + /// The type of the game. + /// The directory information of the game installation. + /// A new instance of configured for an installed game. + public static TestGameRegistrySetupData Installed(GameType gameType, IDirectoryInfo gameLocation) + { + var revision = gameType == GameType.Eaw ? 10105 : 10100; + var launcherPath = gameType == GameType.Eaw ? $"{gameLocation.FullName}\\LaunchEAW.exe" : null; + return new TestGameRegistrySetupData + { + GameType = gameType, + CreateRegistry = true, + InitRegistry = true, + Revision = revision, + EawGold = 20070323, + CdKey = "%CDKEY%", + InstallPath = gameLocation.FullName, + Launcher = launcherPath, + }; + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/GameRegistryTestExtensions.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestingGameRegistryImpl.cs similarity index 50% rename from test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/GameRegistryTestExtensions.cs rename to test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestingGameRegistryImpl.cs index b0e18e4d..8a95ba29 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Game/Registry/GameRegistryTestExtensions.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/Registry/TestingGameRegistryImpl.cs @@ -1,41 +1,50 @@ -using System; -using System.IO.Abstractions; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + using AnakinRaW.CommonUtilities.Registry; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Games.Registry; +using System; +using System.IO.Abstractions; +using Xunit; +using RegistryHive = AnakinRaW.CommonUtilities.Registry.RegistryHive; +using RegistryView = AnakinRaW.CommonUtilities.Registry.RegistryView; -namespace PG.StarWarsGame.Infrastructure.Testing.Game.Registry; +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; -public static class GameRegistryTestExtensions +internal sealed class TestingGameRegistryImpl(IServiceProvider serviceProvider) : ITestingGameRegistry { - public static IGameRegistry CreateNonExistingRegistry(this GameType gameType, IServiceProvider serviceProvider) + private readonly IGameRegistryFactory _registryFactory = serviceProvider.GetRequiredService(); + private readonly IRegistry _registry = serviceProvider.GetRequiredService(); + + public IGameRegistry CreateNonExistingRegistry(GameType gameType) { - var factory = new GameRegistryFactory(serviceProvider); - return factory.CreateRegistry(gameType); + return _registryFactory.CreateRegistry(gameType); } - - public static IGameRegistry Create(this TestGameRegistrySetupData registrySetupData, IServiceProvider serviceProvider) + + public IGameRegistry CreateInstalled(IGame game) { - var gameRegistry = CreateNonExistingRegistry(registrySetupData.GameType, serviceProvider); - var registry = serviceProvider.GetRequiredService(); - InitializeRegistry(registry, registrySetupData, null, serviceProvider); + return CreateFrom(TestGameRegistrySetupData.Installed(game.Type, game.Directory)); + } + + public IGameRegistry CreateFrom(TestGameRegistrySetupData registrySetupData) + { + var gameRegistry = _registryFactory.CreateRegistry(registrySetupData.GameType); + InitializeRegistry(registrySetupData, null); return gameRegistry; } - private static void InitializeRegistry( - IRegistry registry, - TestGameRegistrySetupData setupData, - IDirectoryInfo? customDirectoryInfo, IServiceProvider serviceProvider) + private void InitializeRegistry(TestGameRegistrySetupData setupData, IDirectoryInfo? customDirectoryInfo) { var gameKeyPath = setupData.GameType == GameType.Eaw ? GameRegistryFactory.EawRegistryPath : GameRegistryFactory.FocRegistryPath; - using var hklm = registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); + using var hklm = _registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); hklm.DeleteKey(gameKeyPath, true); if (!setupData.CreateRegistry) return; - + using var gameKey = hklm.CreateSubKey(gameKeyPath); if (!setupData.InitRegistry) diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.Mod.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.Mod.cs new file mode 100644 index 00000000..b30b909a --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.Mod.cs @@ -0,0 +1,152 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.Modinfo.Model; +using AET.Modinfo.Spec; +using Microsoft.Extensions.DependencyInjection; +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Mods; +using PG.StarWarsGame.Infrastructure.Services.Steam; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; +using System; +using System.IO.Abstractions; +using PG.StarWarsGame.Infrastructure.Utilities; +using Xunit; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +internal partial class TestingGameInstallationImpl +{ + public ITestingPhysicalModInstallation InstallMod(string name, bool workshop) + { + var mod = CreateMod(name, workshop, modDir => new Mod(Game, name, modDir, workshop, name, ServiceProvider)); + return new TestingPhysicalModInstallationImpl(this, mod, ServiceProvider); + } + + public ITestingPhysicalModInstallation InstallMod(IModinfo modinfo) + { + var workshop = GITestUtilities.GetRandomWorkshopFlag(Game); + return InstallMod(modinfo, workshop); + } + + public ITestingPhysicalModInstallation InstallMod(IModinfo modinfo, bool workshop) + { + var name = modinfo.Name; + var mod = CreateMod(name, workshop, modDir => new Mod(Game, name, modDir, workshop, modinfo, ServiceProvider)); + return new TestingPhysicalModInstallationImpl(this, mod, ServiceProvider); + } + + public ITestingPhysicalModInstallation InstallMod(IModinfo modinfo, IDirectoryInfo directory) + { + var workshop = GITestUtilities.GetRandomWorkshopFlag(Game); + return InstallMod(modinfo, directory, workshop); + } + + public ITestingPhysicalModInstallation InstallMod(IModinfo modinfo, IDirectoryInfo directory, bool workshop) + { + var mod = CreateMod(directory, dir => new Mod(Game, modinfo.Name, dir, workshop, modinfo, ServiceProvider)); + return new TestingPhysicalModInstallationImpl(this, mod, ServiceProvider); + } + + public ITestingPhysicalModInstallation InstallMod(string name) + { + var workshop = GITestUtilities.GetRandomWorkshopFlag(Game); + return InstallMod(name, workshop); + } + + public ITestingPhysicalModInstallation InstallAndAddMod(string name) + { + var isWorkshop = GITestUtilities.GetRandomWorkshopFlag(Game); + return InstallAndAddMod(name, isWorkshop); + } + + public ITestingPhysicalModInstallation InstallAndAddMod(string name, bool workshop) + { + var modInstallation = InstallMod(name, workshop); + Game.AddMod(modInstallation.Mod); + return modInstallation; + } + + public ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo) + { + return InstallAndAddMod(modinfo, GITestUtilities.GetRandomWorkshopFlag(Game)); + } + + public ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo, bool workshop) + { + var modInstallation = InstallMod(modinfo, workshop); + Game.AddMod(modInstallation.Mod); + return modInstallation; + } + + public ITestingPhysicalModInstallation InstallAndAddMod(IModinfo modinfo, IDirectoryInfo directory, bool workshops) + { + var modInstallation = InstallMod(modinfo, directory, workshops); + Game.AddMod(modInstallation.Mod); + return modInstallation; + } + + public ITestingPhysicalModInstallation InstallAndAddMod(string name, IModDependencyList dependencies) + { + var workshop = GITestUtilities.GetRandomWorkshopFlag(Game); + return InstallAndAddMod(name, workshop, dependencies); + } + + public ITestingVirtualModInstallation AddVirtualMod(string name, ModinfoData modinfo) + { + var mod = new VirtualMod(Game, "VirtualModId", modinfo, ServiceProvider); + Game.AddMod(mod); + return new TestingVirtualModInstallationImpl(this, mod, ServiceProvider); + } + + public ITestingPhysicalModInstallation InstallAndAddMod(string name, bool isWorkshop, IModDependencyList dependencies) + { + if (dependencies.Count == 0) + return InstallAndAddMod(name, isWorkshop); + + var modinfo = new ModinfoData(name) + { + Dependencies = dependencies + }; + return InstallAndAddMod(modinfo, isWorkshop); + } + + public IDirectoryInfo GetModDirectory(string name, bool workshop) + { + if (!workshop) + return FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(Game.ModsLocation.FullName, name)); + if (workshop && Game.Platform is not GamePlatform.SteamGold) + { + Assert.Fail($"Game: {Game}, Mod: {name}, {workshop}"); + throw new InvalidOperationException("compiler flow"); + } + + var steamHelpers = ServiceProvider.GetRequiredService(); + var wsDir = steamHelpers.GetWorkshopsLocation(Game); + Assert.True(wsDir.Exists); + + var nameHash = name.GetHashCode(); + var steamId = (ulong)nameHash; + if (!FileSystem.Directory.Exists(FileSystem.Path.Combine(wsDir.FullName, steamId.ToString()))) + { + steamHelpers.ToSteamWorkshopsId(steamId.ToString(), out var id); + Assert.Equal(steamId, id); + } + return FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(wsDir.FullName, steamId.ToString())); + } + + private Mod CreateMod(string modName, bool workshop, Func modFactory) + { + var modDir = GetModDirectory(modName, workshop); + return CreateMod(modDir, modFactory); + } + + private Mod CreateMod(IDirectoryInfo directory, Func modFactory) + { + Assert.True(Game.ModsLocation.Exists); + var mod = modFactory(directory); + mod.Directory.Create(); + mod.DataDirectory().Create(); + return mod; + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.cs new file mode 100644 index 00000000..01023614 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Game/TestingGameInstallationImpl.cs @@ -0,0 +1,59 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Games; +using System; +using System.IO.Abstractions; +using AET.Modinfo.Spec; +using Xunit; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +internal partial class TestingGameInstallationImpl : TestingModContainerInstallation, ITestingGameInstallation +{ + public IGame Game { get; } + + public override ITestingGameInstallation GameInstallation => this; + + IPhysicalPlayableObject ITestingPhysicalPlayableObjectInstallation.PlayableObject => Game; + + public override IPlayableObject PlayableObject => Game; + + public override PlayableModContainer ModContainer => (Game as PlayableModContainer)!; + + public TestingGameInstallationImpl(IGameIdentity gameIdentity, IServiceProvider serviceProvider) : base(serviceProvider) + { + Game = Install(gameIdentity); + } + + public void InstallDebug() + { + if (Game.Platform is not GamePlatform.SteamGold) + Assert.Fail($"Cannot install Debug files for non-Steam game '{Game}'"); + GameInstallationHelper.CreateFile(FileSystem, FileSystem.Path.Combine(Game.Directory.FullName, "StarWarsI.exe")); + } + + public IDirectoryInfo GetWrongOriginFocRegistryLocation() + { + return FileSystem.DirectoryInfo.New(FileSystem.Path.Combine(GameInstallationHelper.OriginBasePath, "corruption")); + } + + public void InstallLanguage(ILanguageInfo language) + { + PlayableObjectTestingUtilities.InstallLanguage(Game, language, FileSystem); + } + + private IGame Install(IGameIdentity gameIdentity) + { + var gameDir = gameIdentity.Type == GameType.Foc + ? GameInstallationHelper.InstallFoc(FileSystem, gameIdentity.Platform) + : GameInstallationHelper.InstallEaw(FileSystem, gameIdentity.Platform); + + FileSystem.InstallModsLocations(gameDir); + + var game = new PetroglyphStarWarsGame(gameIdentity, gameDir, gameIdentity.ToString()!, ServiceProvider); + Assert.True(game.Exists()); + return game; + } +} + diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/GameInfrastructureTesting.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/GameInfrastructureTesting.cs new file mode 100644 index 00000000..930957bd --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/GameInfrastructureTesting.cs @@ -0,0 +1,42 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game.Registry; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +/// +/// Provides utility methods for creating testing game installations and registries +/// within the Petroglyph Star Wars game infrastructure testing environment. +/// +/// +/// This class serves as a static entry point for creating instances of +/// and . +/// It is designed to facilitate testing scenarios by providing test environments of game installations and registries. +/// +public static class GameInfrastructureTesting +{ + /// + /// Creates a new instance of for the specified and service provider. + /// + /// The identity of the game for which the testing installation is being created. + /// The service provider used to resolve dependencies required by the testing installation. + /// An instance of representing the testing installation for the specified game. + public static ITestingGameInstallation Game(IGameIdentity gameIdentity, IServiceProvider serviceProvider) + { + return new TestingGameInstallationImpl(gameIdentity, serviceProvider); + } + + /// + /// Creates a new instance of . + /// + /// The used to resolve dependencies required by the registry. + /// An instance of that provides methods to create and manage test game registries. + public static ITestingGameRegistry Registry(IServiceProvider serviceProvider) + { + return new TestingGameRegistryImpl(serviceProvider); + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingModContainerInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingModContainerInstallation.cs new file mode 100644 index 00000000..766477c4 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingModContainerInstallation.cs @@ -0,0 +1,15 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +/// +/// Represents an abstraction for a test installation that provides access to a . +/// +public interface ITestingModContainerInstallation : ITestingPlayableObjectInstallation +{ + /// + /// Gets the associated with this installation. + /// + PlayableModContainer ModContainer { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPhysicalPlayableObjectInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPhysicalPlayableObjectInstallation.cs new file mode 100644 index 00000000..309e441d --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPhysicalPlayableObjectInstallation.cs @@ -0,0 +1,27 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.Modinfo.Spec; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +/// +/// Represents an abstraction for a test installation that provides access +/// to a and its associated . +/// +public interface ITestingPhysicalPlayableObjectInstallation : ITestingPlayableObjectInstallation +{ + /// + /// Gets the physical playable object associated with this test installation. + /// This object represents a playable entity stored on the file system, such as a game or mod, + /// and provides access to its directory and other related properties. + /// + new IPhysicalPlayableObject PlayableObject { get; } + + /// + /// Installs the specified language for the playable object. + /// + /// The language information to be installed. + void InstallLanguage(ILanguageInfo language); +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPlayableObjectInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPlayableObjectInstallation.cs new file mode 100644 index 00000000..2406d3a8 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/ITestingPlayableObjectInstallation.cs @@ -0,0 +1,23 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +/// +/// Represents an abstraction for a test installation that provides access +/// to a and its associated . +/// +public interface ITestingPlayableObjectInstallation +{ + /// + /// Gets the game installation associated with this testing playable object installation. + /// + ITestingGameInstallation GameInstallation { get; } + + /// + /// Gets the playable object associated with the test installation. + /// + IPlayableObject PlayableObject { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingModInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingModInstallation.cs new file mode 100644 index 00000000..3820bc05 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingModInstallation.cs @@ -0,0 +1,17 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Mods; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +/// +/// Represents an abstraction for a test installation of a mod of the Petroglyph Star Wars game infrastructure. +/// +public interface ITestingModInstallation : ITestingModContainerInstallation +{ + /// + /// Gets the mod associated with this testing mod installation. + /// + IMod Mod { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingPhysicalModInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingPhysicalModInstallation.cs new file mode 100644 index 00000000..7d71a8ba --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingPhysicalModInstallation.cs @@ -0,0 +1,38 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.Modinfo.Spec; +using PG.StarWarsGame.Infrastructure.Mods; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +/// +/// Represents an abstraction for a test installation of a physical mod of the Petroglyph Star Wars game infrastructure. +/// +public interface ITestingPhysicalModInstallation : ITestingModInstallation, ITestingPhysicalPlayableObjectInstallation +{ + /// + /// Gets the physical mod associated with this testing installation. + /// + /// + /// This property provides access to the instance that represents + /// the mod being tested. The mod is expected to be located on the file system and adheres + /// to the structure and requirements defined for physical mods. + /// + new IPhysicalMod Mod { get; } + + /// + /// Installs an invalid modinfo file to the mod installation. + /// + /// An optional name for the modinfo variant. If not specified, the main modinfo file is created. + /// An instance of representing the installed, invalid modinfo file. + IModinfoFile InstallInvalidModinfoFile(string? variantSubFileName = null); + + /// + /// Installs a modinfo file to the mod installation. + /// + /// The modinfo data to be installed. + /// An optional name for the modinfo variant. If not specified, the main modinfo file is created. + /// An instance of representing the installed modinfo file. + IModinfoFile InstallModinfoFile(IModinfo modinfo, string? variantSubFileName = null); +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingVirtualModInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingVirtualModInstallation.cs new file mode 100644 index 00000000..c192978c --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/ITestingVirtualModInstallation.cs @@ -0,0 +1,17 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Mods; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +/// +/// Represents an abstraction for a test installation of a virtual mod of the Petroglyph Star Wars game infrastructure. +/// +public interface ITestingVirtualModInstallation : ITestingModInstallation +{ + /// + /// Gets the virtual mod associated of the test installation. + /// + new IVirtualMod Mod { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingModInstallationImpl.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingModInstallationImpl.cs new file mode 100644 index 00000000..809678a2 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingModInstallationImpl.cs @@ -0,0 +1,20 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using PG.StarWarsGame.Infrastructure.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +internal class TestingModInstallationImpl(ITestingGameInstallation gameInstallation, IMod mod, IServiceProvider serviceProvider) + : TestingModContainerInstallation(serviceProvider), ITestingModInstallation +{ + public override ITestingGameInstallation GameInstallation { get; } = gameInstallation; + + public override IPlayableObject PlayableObject => Mod; + + public IMod Mod { get; } = mod; + + public override PlayableModContainer ModContainer => (Mod as ModBase)!; +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingPhysicalModInstallationImpl.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingPhysicalModInstallationImpl.cs new file mode 100644 index 00000000..3656bde7 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingPhysicalModInstallationImpl.cs @@ -0,0 +1,56 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.IO; +using AET.Modinfo.File; +using AET.Modinfo.Spec; +using PG.StarWarsGame.Infrastructure.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +internal sealed class TestingPhysicalModInstallationImpl(ITestingGameInstallation gameInstallation, IPhysicalMod mod, IServiceProvider serviceProvider) + : TestingModInstallationImpl(gameInstallation, mod, serviceProvider), ITestingPhysicalModInstallation, ITestingPhysicalPlayableObjectInstallation +{ + public new ITestingGameInstallation GameInstallation { get; } = gameInstallation; + + public new IPhysicalPlayableObject PlayableObject => Mod; + + public void InstallLanguage(ILanguageInfo language) + { + PlayableObjectTestingUtilities.InstallLanguage(PlayableObject, language, FileSystem); + } + + public new IPhysicalMod Mod { get; } = mod; + + public IModinfoFile InstallInvalidModinfoFile(string? variantSubFileName = null) + { + return InstallModinfoFile(stream => { stream.WriteByte(0); }, variantSubFileName); + } + + public IModinfoFile InstallModinfoFile(IModinfo modinfo, string? variantSubFileName = null) + { + return InstallModinfoFile(modinfo.ToJson, variantSubFileName); + } + + private IModinfoFile InstallModinfoFile(Action writeAction, string? variantSubFileName) + { + var dir = Mod.Directory; + dir.Create(); + + var modinfoFilePath = FileSystem.Path.Combine(dir.FullName, + variantSubFileName != null + ? $"{variantSubFileName}-modinfo.json" + : "modinfo.json"); + + using var fileStream = FileSystem.FileStream.New(modinfoFilePath, FileMode.Create); + writeAction(fileStream); + + var fileInfo = FileSystem.FileInfo.New(modinfoFilePath); + + if (variantSubFileName is null) + return new MainModinfoFile(fileInfo); + return new ModinfoVariantFile(fileInfo); + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingVirtualModInstallationImpl.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingVirtualModInstallationImpl.cs new file mode 100644 index 00000000..8fe85001 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/Mods/TestingVirtualModInstallationImpl.cs @@ -0,0 +1,16 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using PG.StarWarsGame.Infrastructure.Mods; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; + +internal sealed class TestingVirtualModInstallationImpl(ITestingGameInstallation gameInstallation, IVirtualMod mod, IServiceProvider serviceProvider) + : TestingModInstallationImpl(gameInstallation, mod, serviceProvider), ITestingVirtualModInstallation +{ + public new ITestingGameInstallation GameInstallation { get; } = gameInstallation; + + public new IVirtualMod Mod { get; } = mod; +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/PlayableObjectTestingExtensions.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/PlayableObjectTestingExtensions.cs new file mode 100644 index 00000000..266ee7aa --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/PlayableObjectTestingExtensions.cs @@ -0,0 +1,55 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System.IO.Abstractions; +using AET.Modinfo.Spec; +using PG.StarWarsGame.Infrastructure.Services.Language; +using PG.StarWarsGame.Infrastructure.Utilities; +using Xunit; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +internal static class PlayableObjectTestingUtilities +{ + public static void InstallLanguage(IPhysicalPlayableObject obj, ILanguageInfo language, IFileSystem fileSystem) + { + var languageName = LanguageInfoUtilities.GetEnglishName(language); + var dataDir = obj.DataDirectory(); + Assert.NotNull(languageName); + if (language.Support.HasFlag(LanguageSupportLevel.Text)) + InstallText(dataDir, languageName, fileSystem); + if (language.Support.HasFlag(LanguageSupportLevel.SFX)) + InstallSfx(dataDir, languageName, fileSystem); + if (language.Support.HasFlag(LanguageSupportLevel.Speech)) + InstallSpeech(dataDir, languageName, fileSystem); + } + + private static void InstallText(IDirectoryInfo dataDir, string languageName, IFileSystem fileSystem) + { + var masterTextFileName = $"MasterTextFile_{languageName}.dat"; + + var dir = fileSystem.Path.Combine(dataDir.FullName, "Text"); + fileSystem.Directory.CreateDirectory(dir); + + var filePath = fileSystem.Path.Combine(dir, masterTextFileName); + using var _ = fileSystem.File.Create(filePath); + } + + private static void InstallSfx(IDirectoryInfo dataDir, string languageName, IFileSystem fileSystem) + { + var sfxFileName = $"SFX2D_{languageName}.meg"; + + var dir = fileSystem.Path.Combine(dataDir.FullName, "Audio", "SFX"); + fileSystem.Directory.CreateDirectory(dir); + + var filePath = fileSystem.Path.Combine(dir, sfxFileName); + using var _ = fileSystem.File.Create(filePath); + } + + private static void InstallSpeech(IDirectoryInfo dataDir, string languageName, IFileSystem fileSystem) + { + var sfxFileName = $"{languageName}Speech.meg"; + var filePath = fileSystem.Path.Combine(dataDir.FullName, sfxFileName); + using var _ = fileSystem.File.Create(filePath); + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingModContainerInstallation.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingModContainerInstallation.cs new file mode 100644 index 00000000..be350738 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingModContainerInstallation.cs @@ -0,0 +1,12 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +internal abstract class TestingModContainerInstallation(IServiceProvider serviceProvider) + : TestingPlayableObjectInstallationImpl(serviceProvider), ITestingModContainerInstallation +{ + public abstract PlayableModContainer ModContainer { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingPlayableObjectInstallationImpl.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingPlayableObjectInstallationImpl.cs new file mode 100644 index 00000000..d8777254 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/Installations/TestingPlayableObjectInstallationImpl.cs @@ -0,0 +1,20 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; +using System.IO.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.Installations; + +internal abstract class TestingPlayableObjectInstallationImpl(IServiceProvider serviceProvider) + : ITestingPlayableObjectInstallation +{ + protected readonly IServiceProvider ServiceProvider = serviceProvider; + protected readonly IFileSystem FileSystem = serviceProvider.GetRequiredService(); + + public abstract ITestingGameInstallation GameInstallation { get; } + + public abstract IPlayableObject PlayableObject { get; } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs deleted file mode 100644 index 39388722..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.Modinfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.IO; -using AET.Modinfo.File; -using AET.Modinfo.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 MainModinfoFile(fileInfo); - return new ModinfoVariantFile(fileInfo); - } - -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs b/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs deleted file mode 100644 index 7037d205..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/Mods/ModInstallations.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.IO.Abstractions; -using AET.Modinfo.Spec; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Mods; -using PG.StarWarsGame.Infrastructure.Services.Steam; -using PG.StarWarsGame.Infrastructure.Utilities; - -namespace PG.StarWarsGame.Infrastructure.Testing.Mods; - -public static partial class ModInstallations -{ - public static Mod InstallAndAddMod(this IGame game, string name, bool workshop, IServiceProvider serviceProvider) - { - var mod = game.InstallMod(name, workshop, serviceProvider); - game.AddMod(mod); - return mod; - } - - public static Mod InstallAndAddMod(this IGame game, bool workshop, IModinfo modinfo, IServiceProvider serviceProvider) - { - var mod = game.InstallMod(workshop, modinfo, serviceProvider); - game.AddMod(mod); - return mod; - } - - public static Mod InstallMod(this IGame game, string name, bool workshop, IServiceProvider serviceProvider) - { - return CreateMod(game, name, workshop, serviceProvider, - modDir => new Mod(game, name, modDir, workshop, name, serviceProvider)); - } - - public static Mod InstallMod(this IGame game, bool workshop, IModinfo modinfo, IServiceProvider serviceProvider) - { - var name = modinfo.Name; - return CreateMod(game, name, workshop, serviceProvider, - modDir => new Mod(game, name, modDir, workshop, modinfo, serviceProvider)); - } - - public static Mod InstallMod(this IGame game, IDirectoryInfo directory, bool isWorkshop, IModinfo modinfo, IServiceProvider serviceProvider) - { - return CreateMod(game, directory, dir => new Mod(game, modinfo.Name, dir, isWorkshop, modinfo, serviceProvider)); - } - - private static Mod CreateMod(IGame game, string modName, bool workshop, IServiceProvider serviceProvider, Func modFactory) - { - var modDir = game.Directory.FileSystem.DirectoryInfo.New(game.GetModDirectory(modName, workshop, serviceProvider)); - return CreateMod(game, modDir, modFactory); - } - - private static Mod CreateMod(IGame game, IDirectoryInfo directory, Func modFactory) - { - Assert.True(game.ModsLocation.Exists); - var mod = modFactory(directory); - mod.Directory.Create(); - mod.DataDirectory().Create(); - return mod; - } - - public static string GetModDirectory(this IGame game, string name, bool workshop, IServiceProvider serviceProvider) - { - var fs = game.Directory.FileSystem; - if (!workshop) - return fs.Path.Combine(game.ModsLocation.FullName, name); - if (workshop && game.Platform is not GamePlatform.SteamGold) - { - Assert.Fail($"Game: {game}, Mod: {name}, {workshop}"); - throw new InvalidOperationException("compiler flow"); - } - - var steamHelpers = serviceProvider.GetRequiredService(); - var wsDir = steamHelpers.GetWorkshopsLocation(game); - Assert.True(wsDir.Exists); - - var nameHash = name.GetHashCode(); - var steamId = (ulong)nameHash; - if (!fs.Directory.Exists(fs.Path.Combine(wsDir.FullName, steamId.ToString()))) - { - steamHelpers.ToSteamWorkshopsId(steamId.ToString(), out var id); - Assert.Equal(steamId, id); - } - return fs.Path.Combine(wsDir.FullName, steamId.ToString()); - } -} diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/PG.StarWarsGame.Infrastructure.Testing.csproj b/test/PG.StarWarsGame.Infrastructure.Testing/PG.StarWarsGame.Infrastructure.Testing.csproj index 72f1d12e..9d2100c1 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/PG.StarWarsGame.Infrastructure.Testing.csproj +++ b/test/PG.StarWarsGame.Infrastructure.Testing/PG.StarWarsGame.Infrastructure.Testing.csproj @@ -1,51 +1,39 @@ - + PG.StarWarsGame.Infrastructure.TestingUtilities + netstandard2.0;net10.0 + true + false - net10.0 - $(TargetFrameworks);net481 - false - false + PG.StarWarsGame.Infrastructure.Testing + Provides a testing layer that allowes to virtualize PG Star Wars game installations, so that they do not need to be physically installed. + AlamoEngineTools.PG.StarWarsGame.Infrastructure.Testing + alamo,petroglyph,glyphx + en - - - + + true + true + true + + + true + snupkg + - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/PlayableObjectTestingExtensions.cs b/test/PG.StarWarsGame.Infrastructure.Testing/PlayableObjectTestingExtensions.cs deleted file mode 100644 index b6a88ffe..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/PlayableObjectTestingExtensions.cs +++ /dev/null @@ -1,52 +0,0 @@ -using AET.Modinfo.Spec; -using PG.StarWarsGame.Infrastructure.Services.Language; -using PG.StarWarsGame.Infrastructure.Utilities; - -namespace PG.StarWarsGame.Infrastructure.Testing; - -public static class PlayableObjectTestingExtensions -{ - public static void InstallLanguage(this IPhysicalPlayableObject obj, ILanguageInfo language) - { - var languageName = LanguageInfoUtilities.GetEnglishName(language); - Assert.NotNull(languageName); - if (language.Support.HasFlag(LanguageSupportLevel.Text)) - obj.InstallText(languageName); - if (language.Support.HasFlag(LanguageSupportLevel.SFX)) - obj.InstallSfx(languageName); - if (language.Support.HasFlag(LanguageSupportLevel.Speech)) - obj.InstallSpeech(languageName); - } - - private static void InstallText(this IPhysicalPlayableObject obj, string languageName) - { - var fs = obj.Directory.FileSystem; - var masterTextFileName = $"MasterTextFile_{languageName}.dat"; - - var dir = fs.Path.Combine(obj.DataDirectory().FullName, "Text"); - fs.Directory.CreateDirectory(dir); - - var filePath = fs.Path.Combine(dir, masterTextFileName); - using var _ = fs.File.Create(filePath); - } - - private static void InstallSfx(this IPhysicalPlayableObject obj, string languageName) - { - var fs = obj.Directory.FileSystem; - var sfxFileName = $"SFX2D_{languageName}.meg"; - - var dir = fs.Path.Combine(obj.DataDirectory().FullName, "Audio", "SFX"); - fs.Directory.CreateDirectory(dir); - - var filePath = fs.Path.Combine(dir, sfxFileName); - using var _ = fs.File.Create(filePath); - } - - private static void InstallSpeech(this IPhysicalPlayableObject obj, string languageName) - { - var fs = obj.Directory.FileSystem; - var sfxFileName = $"{languageName}Speech.meg"; - var filePath = fs.Path.Combine(obj.DataDirectory().FullName, sfxFileName); - using var _ = fs.File.Create(filePath); - } -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBase.cs deleted file mode 100644 index e8f57b9a..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBase.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.IO.Abstractions; -using System.Linq; -using AET.Modinfo.Model; -using AET.Modinfo.Spec; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Mods; -using PG.StarWarsGame.Infrastructure.Testing.Game.Installation; -using PG.StarWarsGame.Infrastructure.Testing.Mods; -using PG.TestingUtilities; -using Testably.Abstractions.Testing; - -namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; - -public abstract class CommonTestBase -{ - protected readonly IServiceProvider ServiceProvider; - protected readonly MockFileSystem FileSystem = new(); - - [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")] - protected CommonTestBase() - { - var sc = new ServiceCollection(); - SetupServiceProvider(sc); - ServiceProvider = sc.BuildServiceProvider(); - } - - protected virtual void SetupServiceProvider(IServiceCollection sc) - { - sc.AddSingleton(FileSystem); - PetroglyphGameInfrastructure.InitializeServices(sc); - } - - public static IEnumerable RealPlatforms() - { - return GITestUtilities.RealPlatforms.Select(platform => (object[])[platform]); - } - - public static IEnumerable RealGameIdentities() - { - foreach (var platform in GITestUtilities.RealPlatforms) - { - yield return [new GameIdentity(GameType.Eaw, platform)]; - yield return [new GameIdentity(GameType.Foc, platform)]; - } - } - - protected static GameIdentity CreateRandomGameIdentity() - { - return new GameIdentity(TestHelpers.GetRandomEnum(), TestHelpers.GetRandom(GITestUtilities.RealPlatforms)); - } - - protected PetroglyphStarWarsGame CreateRandomGame() - { - return FileSystem.InstallGame(CreateRandomGameIdentity(), ServiceProvider); - } - - private static readonly string[] PossibleLanguages = ["en", "de", "es", "it"]; - - protected static ICollection GetRandomLanguages() - { - var languages = new HashSet(PossibleLanguages.Length); - - foreach (var _ in PossibleLanguages) - { - var code = TestHelpers.GetRandom(PossibleLanguages); - var support = TestHelpers.GetRandomEnum(); - languages.Add(new LanguageInfo(code, support)); - } - - return languages; - } - - protected IMod CreateAndAddMod(IGame game, bool isWorkshop, string name, IModDependencyList dependencies) - { - if (dependencies.Count == 0) - return game.InstallAndAddMod(name, isWorkshop, ServiceProvider); - - var modinfo = new ModinfoData(name) - { - Dependencies = dependencies - }; - return CreateAndAddMod(game, isWorkshop, modinfo); - } - - protected IMod CreateAndAddMod(IGame game, bool isWorkshop, IModinfo modinfo) - { - return game.InstallAndAddMod(isWorkshop, modinfo, ServiceProvider); - } -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBaseWithRandomGame.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBaseWithRandomGame.cs deleted file mode 100644 index 7c994c41..00000000 --- a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/CommonTestBaseWithRandomGame.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using AET.Modinfo.Model; -using AET.Modinfo.Spec; -using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Mods; - -namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; - -public abstract class CommonTestBaseWithRandomGame : CommonTestBase -{ - protected readonly IGame Game; - - protected CommonTestBaseWithRandomGame() - { - Game = CreateRandomGame(); - } - - protected IMod CreateAndAddMod( - string name, - DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, - params IList deps) - { - return CreateAndAddMod(Game, GITestUtilities.GetRandomWorkshopFlag(Game), name, new DependencyList(deps, layout)); - } - - protected IMod CreateAndAddMod(IModinfo modinfo) - { - return CreateAndAddMod(Game, GITestUtilities.GetRandomWorkshopFlag(Game), modinfo); - } -} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase.cs index eeae83b2..4799cdcd 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase.cs @@ -1,27 +1,81 @@ -using System; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using System; using System.Collections.Generic; using System.IO.Abstractions; using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; +using Xunit; namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; -public abstract partial class GameDetectorTestBase : CommonTestBase +/// +/// Provides a base class for testing game detectors in the Petroglyph Star Wars Game infrastructure. +/// +/// The type of the setup information used by the game detector during testing. +public abstract partial class GameDetectorTestBase : GameInfrastructureTestBase { + /// + /// Gets a value indicating whether the game detector is aware of uninitialized game installation. + /// protected abstract bool SupportInitialization { get; } + /// + /// Gets the collection of game platforms that are supported by the game detector. + /// protected abstract ICollection SupportedPlatforms { get; } + /// + /// Gets a value indicating whether the game detector, which support initialization, support suppressing the initialization requests. + /// protected abstract bool CanDisableInitRequest { get; } + /// + /// Creates an instance of a game detector for testing purposes. + /// + /// + /// The setup information required for the game detector, including game type, directory information, + /// and any additional setup-specific data. + /// + /// + /// A value indicating whether the detector should handle initialization events. + /// + /// An instance of configured based on the specified setup information. protected abstract IGameDetector CreateDetector(GameDetectorTestInfo gameInfo, bool shallHandleInitialization); + /// + /// Sets up the game environment for testing based on the specified game identity. + /// + /// The identity of the game. + /// A instance containing the setup information for the specified game identity. protected abstract GameDetectorTestInfo SetupGame(GameIdentity gameIdentity); + /// + /// Prepares the necessary setup so that the game detector shall detect an uninitialized game. + /// + /// The representing the uninitialized game. + /// A instance containing the setup information required for the test. protected abstract GameDetectorTestInfo SetupForRequiredInitialization(GameIdentity gameIdentity); + /// + /// Handles the initialization process for the game detector during testing. + /// + /// A value indicating whether the initialization should be simulated as successful. + /// The containing the setup information required for initialization. protected abstract void HandleInitialization(bool shallInitSuccessfully, GameDetectorTestInfo info); + /// + /// Tests the core functionality of the game detector by verifying detection results for a specified game identity. + /// + /// The representing the game to be detected. + /// + /// A function to provide custom setup logic for the test, returning a instance. + /// If , is used. + /// + /// + /// A function to create the expected based on the provided test information. + /// The platforms to query during by the detector. protected void TestDetectorCore( GameIdentity identity, Func>? customSetup, @@ -31,6 +85,26 @@ protected void TestDetectorCore( TestDetectorCore(identity, false, customSetup, expectedResultFactory, null, queryPlatforms); } + /// + /// Tests the core functionality of the game detector by verifying detection results for a specified game identity. + /// + /// The representing the game to be detected. + /// A boolean indicating whether initialization events should be handled during detection. + /// + /// A function to provide custom setup logic for the test, returning a instance. + /// If , is used. + /// + /// + /// A function to create the expected based on the provided test information. + /// + /// A predicate to handle initialization events, allowing custom logic to determine if the event is handled. + /// Can be if no initialization handling is requested. + /// + /// The platforms to query during by the detector. + /// + /// This method validates the detection result and ensures that initialization events are triggered or not + /// based on the provided parameters and the detector's capabilities. + /// protected void TestDetectorCore( GameIdentity identity, bool shallHandleInitialization, @@ -75,12 +149,29 @@ protected void TestDetectorCore( Assert.Equal(shouldTriggerInitEvent, eventTriggered); } + /// + /// Represents information required for setting up the test environment for the game detector. + /// + /// The type of the custom setup information. protected class GameDetectorTestInfo(GameType gameType, IDirectoryInfo? directoryInfo, TInfo? setupInfo) { + /// + /// Gets the type of the game being tested. + /// public GameType GameType { get; } = gameType; + /// + /// Gets the directory information for the to be detected game. + /// + /// + /// This property provides access to the directory where the game files are located. + /// It may return to indicate the game shall not get installed. + /// public IDirectoryInfo? GameDirectory { get; } = directoryInfo; + /// + /// Gets the optional, custom setup information required for configuring the game detector. + /// public TInfo? DetectorSetupInfo { get; } = setupInfo; } } \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase_Tests.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase_Tests.cs index b251cf97..440994c2 100644 --- a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase_Tests.cs +++ b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameDetectorTestBase_Tests.cs @@ -1,8 +1,13 @@ -using PG.StarWarsGame.Infrastructure.Games; +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Games; using PG.StarWarsGame.Infrastructure.Services.Detection; +using Xunit; namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public partial class GameDetectorTestBase { private void TestDetectorGameInstalled(GameIdentity identity, params GamePlatform[] queryPlatforms) @@ -17,35 +22,35 @@ private void TestDetectorGameInstalled(GameIdentity identity, params GamePlatfor } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GameInstalled_DetectWithSinglePlatform(GameIdentity identity) { TestDetectorGameInstalled(identity, identity.Platform); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GameInstalled_NoQueryPlatformSearchesAll(GameIdentity identity) { TestDetectorGameInstalled(identity, queryPlatforms: []); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GameInstalled_UndefinedPlatformPlatformSearchesAll(GameIdentity identity) { TestDetectorGameInstalled(identity, queryPlatforms: [GamePlatform.Undefined]); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GameInstalled_QueryContainsUndefinedSearchesAll(GameIdentity identity) { TestDetectorGameInstalled(identity, queryPlatforms: [GamePlatform.Disk, GamePlatform.Undefined]); } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_GameNotInstalled(GameIdentity identity) { var expected = GameDetectionResult.NotInstalled(identity.Type); @@ -57,17 +62,15 @@ public void Detect_TryDetect_GameNotInstalled(GameIdentity identity) } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_TypeOfDesiredPlatformNotFound(GameIdentity identity) { // Install the opposite of the desired game type. - var typeToInstall = identity.Type == GameType.Foc ? GameType.Eaw : GameType.Foc; - var expected = GameDetectionResult.NotInstalled(identity.Type); TestDetectorCore( identity, - _ => SetupGame(new GameIdentity(typeToInstall, identity.Platform)), // Set up the opposite game + _ => SetupGame(new GameIdentity(identity.Type.Opposite(), identity.Platform)), // Set up the opposite game _ => expected, identity.Platform ); @@ -90,7 +93,7 @@ public void Detect_TryDetect_GoG_PlatformDoesNotMatch(GameType gameType, params } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_TestRequiresGameInitialization_DetectorDoesNotHandle(GameIdentity identity) { if (!SupportInitialization) @@ -109,7 +112,7 @@ public void Detect_TryDetect_TestRequiresGameInitialization_DetectorDoesNotHandl } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_ButDoesNotHandle(GameIdentity identity) { if (!SupportInitialization) @@ -127,7 +130,7 @@ public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_Bu } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_DoesHandleAndGameIsInitialized(GameIdentity identity) { if (!SupportInitialization) @@ -155,7 +158,7 @@ public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_Do } [Theory] - [MemberData(nameof(RealGameIdentities))] + [MemberData(nameof(GITestUtilities.RealGameIdentities), MemberType = typeof(GITestUtilities))] public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_DoesHandleButGameIsNotInitialized(GameIdentity identity) { if (!SupportInitialization) @@ -181,4 +184,5 @@ public void Detect_TryDetect_TestRequiresGameInitialization_DetectorCanHandle_Do }, queryPlatforms: []); } -} \ No newline at end of file +} +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBase.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBase.cs new file mode 100644 index 00000000..7c497e7a --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBase.cs @@ -0,0 +1,62 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using AET.Modinfo.Model; +using AET.Modinfo.Spec; +using Microsoft.Extensions.DependencyInjection; +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Testing.Installations; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Mods; +using System.Collections.Generic; +using AnakinRaW.CommonUtilities.Testing; + +namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; + +/// +/// Provides a base class for testing infrastructure components of the Petroglyph Star Wars game test framework. +/// This class facilitates the setup of services, file system management, and game or mod installations +/// required for testing purposes. +/// +public abstract class GameInfrastructureTestBase : TestBaseWithFileSystem +{ + private ITestingGameInstallation? _gameInstallation; + + /// + /// Configures test services by adding them to the specified . + /// + /// The to which services will be added. + protected override void SetupServices(IServiceCollection serviceCollection) + { + base.SetupServices(serviceCollection); + PetroglyphGameInfrastructure.InitializeServices(serviceCollection); + } + + /// + /// Retrieves an existing game installation or creates a new one if it does not already exist. + /// + /// The optional identity of the game. If not provided, a random game identity will be used. + /// An instance of representing the game installation. + protected virtual ITestingGameInstallation GetOrCreateGameInstallation(IGameIdentity? identity = null) + { + if (_gameInstallation is not null) + return _gameInstallation; + identity ??= GITestUtilities.GetRandomGameIdentity(realOnly: true); + return _gameInstallation = GameInfrastructureTesting.Game(identity, ServiceProvider); + } + + /// + /// Installs a mod with the specified name and dependencies into the game installation and adds it to the collection of the game. + /// + /// The name of the mod to be installed. + /// Specifies the dependency resolution layout to be used. Defaults to . + /// A collection of mod dependencies to be resolved and added. + /// An instance of representing the installed mod. + protected ITestingPhysicalModInstallation InstallAndAddModWithDependencies( + string name, + DependencyResolveLayout layout = DependencyResolveLayout.FullResolved, + params IList deps) + { + return GetOrCreateGameInstallation().InstallAndAddMod(name, new DependencyList(deps, layout)); + } +} \ No newline at end of file diff --git a/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBaseWithRandomGame.cs b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBaseWithRandomGame.cs new file mode 100644 index 00000000..453ffad6 --- /dev/null +++ b/test/PG.StarWarsGame.Infrastructure.Testing/TestBases/GameInfrastructureTestBaseWithRandomGame.cs @@ -0,0 +1,24 @@ +// Copyright (c) Alamo Engine Tools and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +using PG.StarWarsGame.Infrastructure.Games; +using PG.StarWarsGame.Infrastructure.Testing.Installations.Game; + +namespace PG.StarWarsGame.Infrastructure.Testing.TestBases; + +/// +/// Serves as a specialized base class for testing infrastructure components of the Petroglyph Star Wars game test framework +/// with a randomly initialized game instance. +/// +public abstract class GameInfrastructureTestBaseWithRandomGame : GameInfrastructureTestBase +{ + /// + /// Gets the instance of the game associated with the current test context. + /// + protected IGame Game => GameInstallation.Game; + + /// + /// Gets the instance of the associated with the current test context. + /// + protected ITestingGameInstallation GameInstallation => GetOrCreateGameInstallation(identity: null); +} \ No newline at end of file diff --git a/test/PG.TestingUtilities/EmptyStruct.cs b/test/PG.TestingUtilities/EmptyStruct.cs deleted file mode 100644 index 826f4a15..00000000 --- a/test/PG.TestingUtilities/EmptyStruct.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System.Runtime.InteropServices; - -namespace PG.TestingUtilities; - -[StructLayout(LayoutKind.Explicit)] -public struct EmptyStruct; \ No newline at end of file diff --git a/test/PG.TestingUtilities/ExceptionTest.cs b/test/PG.TestingUtilities/ExceptionTest.cs deleted file mode 100644 index 610ca98d..00000000 --- a/test/PG.TestingUtilities/ExceptionTest.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace PG.TestingUtilities; - -public class ExceptionTest -{ - public static void AssertException(Exception e, - Exception? innerException = null, - string? message = null, - string? stackTrace = null, - bool validateMessage = true) - { - Assert.Equal(innerException, e.InnerException); - if (validateMessage) - Assert.Equal(message, e.Message); - else - Assert.NotNull(e.Message); - Assert.Equal(stackTrace, e.StackTrace); - } -} \ No newline at end of file diff --git a/test/PG.TestingUtilities/PG.TestingUtilities.csproj b/test/PG.TestingUtilities/PG.TestingUtilities.csproj deleted file mode 100644 index 16fc0df1..00000000 --- a/test/PG.TestingUtilities/PG.TestingUtilities.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net10.0 - $(TargetFrameworks);net481 - false - false - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - diff --git a/test/PG.TestingUtilities/PlatformSpecificFactAttribute.cs b/test/PG.TestingUtilities/PlatformSpecificFactAttribute.cs deleted file mode 100644 index e2d545d7..00000000 --- a/test/PG.TestingUtilities/PlatformSpecificFactAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.InteropServices; - -namespace PG.TestingUtilities; - -public sealed class PlatformSpecificFactAttribute : FactAttribute -{ - public PlatformSpecificFactAttribute(params TestPlatformIdentifier[] platformIds) - { - var platforms = platformIds.Select(targetPlatform => OSPlatform.Create(Enum.GetName(typeof(TestPlatformIdentifier), targetPlatform)!.ToUpper())); - var platformMatches = platforms.Any(RuntimeInformation.IsOSPlatform); - - if (!platformMatches) - Skip = "Test execution is not supported on the current platform"; - } -} \ No newline at end of file diff --git a/test/PG.TestingUtilities/PlatformSpecificTheoryAttribute.cs b/test/PG.TestingUtilities/PlatformSpecificTheoryAttribute.cs deleted file mode 100644 index 0ea85b11..00000000 --- a/test/PG.TestingUtilities/PlatformSpecificTheoryAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.InteropServices; - -namespace PG.TestingUtilities; - -public sealed class PlatformSpecificTheoryAttribute : TheoryAttribute -{ - public PlatformSpecificTheoryAttribute(params TestPlatformIdentifier[] platformIds) - { - var platforms = platformIds.Select(targetPlatform => OSPlatform.Create(Enum.GetName(typeof(TestPlatformIdentifier), targetPlatform)!.ToUpper())); - var platformMatches = platforms.Any(RuntimeInformation.IsOSPlatform); - - if (!platformMatches) - Skip = "Test execution is not supported on the current platform"; - } -} \ No newline at end of file diff --git a/test/PG.TestingUtilities/ReferenceEqualityComparer.cs b/test/PG.TestingUtilities/ReferenceEqualityComparer.cs deleted file mode 100644 index 58d0b3db..00000000 --- a/test/PG.TestingUtilities/ReferenceEqualityComparer.cs +++ /dev/null @@ -1,23 +0,0 @@ -#if !NET5_0_OR_GREATER -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace PG.TestingUtilities; - -public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer -{ - private ReferenceEqualityComparer() - { - } - - public static ReferenceEqualityComparer Instance { get; } = new(); - - public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); - - public int GetHashCode(object? obj) - { - return RuntimeHelpers.GetHashCode(obj!); - } -} -#endif \ No newline at end of file diff --git a/test/PG.TestingUtilities/TestHelpers.cs b/test/PG.TestingUtilities/TestHelpers.cs deleted file mode 100644 index 3960f1a6..00000000 --- a/test/PG.TestingUtilities/TestHelpers.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace PG.TestingUtilities; - -public static class TestHelpers -{ - private static readonly Random Random = new(); - - public static bool RandomBool() - { - return Random.Next() % 2 == 0; - } - - public static long RandomLong() - { - var buf = new byte[8]; - Random.NextBytes(buf); - return BitConverter.ToInt64(buf, 0); - } - - public static uint RandomUInt() - { - return (uint)Random.Next(int.MinValue, int.MaxValue); - } - - public static ushort RandomUShort() - { - return (ushort)Random.Next(ushort.MinValue, ushort.MaxValue); - } - - public static T GetRandomEnum() where T : struct, Enum - { - var values = Enum.GetValues(typeof(T)); - return (T)values.GetValue(Random.Next(values.Length))!; - } - - public static T GetRandom(IEnumerable items) - { - var list = items.ToList(); - var r = Random.Next(list.Count); - return list[r]; - } - - public static string ShuffleCasing(string input) - { - var characters = input.ToCharArray(); - - for (var i = 0; i < characters.Length; i++) - { - if (char.IsLetter(characters[i])) - { - if (Random.Next(2) == 0) - { - characters[i] = char.IsUpper(characters[i]) - ? char.ToLower(characters[i]) - : char.ToUpper(characters[i]); - } - } - } - - return new string(characters); - } -} \ No newline at end of file diff --git a/test/PG.TestingUtilities/TestPlatformIdentifier.cs b/test/PG.TestingUtilities/TestPlatformIdentifier.cs deleted file mode 100644 index da1529a9..00000000 --- a/test/PG.TestingUtilities/TestPlatformIdentifier.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace PG.TestingUtilities; - -[Flags] -public enum TestPlatformIdentifier -{ - Windows = 1, - Linux = 2, -} \ No newline at end of file