Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ jobs:
run: dotnet restore "${{ env.WORKING_DIRECTORY }}"
- name: Build
run: dotnet build "${{ env.WORKING_DIRECTORY }}" --no-restore
- name: Test
run: dotnet test "${{ env.WORKING_DIRECTORY }}"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,4 @@ ASALocalRun/

# Local History for Visual Studio
.localhistory/

.direnv/
62 changes: 62 additions & 0 deletions Stardrop.Test/EnumParserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
namespace Stardrop.Test;

using NUnit.Framework;
using Stardrop.Models.Data.Enums;
using Stardrop.Utilities.Internal;

[TestFixture]
public class EnumParserTests
{
[Test]
public void GetDescription_NullEnum_ReturnsNull()
{
NexusServers? value = null;
Assert.That(value.GetDescription(), Is.Null);
}

[Test]
[TestCase(NexusServers.NexusCDN, "Nexus CDN")]
[TestCase(NexusServers.LosAngeles, "Los Angeles")]
public void GetDescription_NexusServers_WithDescription_ReturnsAttributeText(NexusServers server, string expected)
{
Assert.That(server.GetDescription(), Is.EqualTo(expected));
}

[Test]
[TestCase(NexusServers.Chicago, "Chicago")]
[TestCase(NexusServers.Paris, "Paris")]
[TestCase(NexusServers.Amsterdam, "Amsterdam")]
[TestCase(NexusServers.Prague, "Prague")]
[TestCase(NexusServers.Miami, "Miami")]
[TestCase(NexusServers.Singapore, "Singapore")]
public void GetDescription_NexusServers_WithoutDescription_ReturnsMemberName(NexusServers server, string expected)
{
Assert.That(server.GetDescription(), Is.EqualTo(expected));
}

[Test]
[TestCase(ModGrouping.ContentPack, "Content Pack")]
[TestCase(ModGrouping.FolderCondensed, "Folder (Condensed)")]
public void GetDescription_ModGrouping_WithDescription_ReturnsAttributeText(ModGrouping grouping, string expected)
{
Assert.That(grouping.GetDescription(), Is.EqualTo(expected));
}

[Test]
[TestCase(ModGrouping.None, "None")]
[TestCase(ModGrouping.Folder, "Folder")]
public void GetDescription_ModGrouping_WithoutDescription_ReturnsMemberName(ModGrouping grouping, string expected)
{
Assert.That(grouping.GetDescription(), Is.EqualTo(expected));
}

[Test]
[TestCase(DisplayFilter.None, "None")]
[TestCase(DisplayFilter.ShowEnabled, "ShowEnabled")]
[TestCase(DisplayFilter.ShowDisabled, "ShowDisabled")]
[TestCase(DisplayFilter.RequireConfig, "RequireConfig")]
public void GetDescription_DisplayFilter_NeverHasDescription_ReturnsMemberName(DisplayFilter filter, string expected)
{
Assert.That(filter.GetDescription(), Is.EqualTo(expected));
}
}
3 changes: 3 additions & 0 deletions Stardrop.Test/MSTestSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using NUnit.Framework;

[assembly: Parallelizable(ParallelScope.All)]
164 changes: 164 additions & 0 deletions Stardrop.Test/ModConfigServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using NUnit.Framework;
using Stardrop.Models;
using Stardrop.Models.SMAPI;
using Stardrop.Utilities.Internal;

namespace Stardrop.Test;

[TestFixture]
[NonParallelizable]
public class ModConfigServiceTests
{
private string _tempDir;
private ModConfigService _service;
private FakeModDiscoveryService _discoveryService;
private Settings _savedSettings;

[SetUp]
public void SetUp()
{
_tempDir = Path.Combine(Path.GetTempPath(), $"stardrop-test-{Guid.NewGuid()}");
Directory.CreateDirectory(_tempDir);

_savedSettings = Program.settings;
Program.settings = new Settings { ModFolderPath = _tempDir, IgnoreHiddenFolders = true };

_discoveryService = new FakeModDiscoveryService();
_service = new ModConfigService(Program.settings, _discoveryService);
}

[TearDown]
public void TearDown()
{
Program.settings = _savedSettings;
if (Directory.Exists(_tempDir))
Directory.Delete(_tempDir, recursive: true);
}



[Test]
public void GetConfigFiles_EmptyDirectory_ReturnsEmpty()
{
var result = _service.GetConfigFiles(new DirectoryInfo(_tempDir));
Assert.That(result, Is.Empty);
}

[Test]
public void GetConfigFiles_ConfigWithoutManifest_NotIncluded()
{
var modDir = CreateSubdir("Mod1");
File.WriteAllText(Path.Combine(modDir, "config.json"), "{}");

var result = _service.GetConfigFiles(new DirectoryInfo(_tempDir));

Assert.That(result, Is.Empty);
}

[Test]
public void GetConfigFiles_ConfigWithManifest_Included()
{
var modDir = CreateSubdir("Mod1");
var configPath = Path.Combine(modDir, "config.json");
File.WriteAllText(configPath, "{}");
File.WriteAllText(Path.Combine(modDir, "manifest.json"), "{}");

var result = _service.GetConfigFiles(new DirectoryInfo(_tempDir));

Assert.That(result, Has.Count.EqualTo(1));
Assert.That(result[0].FullName, Is.EqualTo(configPath));
}

[Test]
public void GetConfigFiles_MultipleModDirs_AllIncluded()
{
foreach (var name in new[] { "Mod1", "Mod2", "Mod3" })
{
var dir = CreateSubdir(name);
File.WriteAllText(Path.Combine(dir, "config.json"), "{}");
File.WriteAllText(Path.Combine(dir, "manifest.json"), "{}");
}

var result = _service.GetConfigFiles(new DirectoryInfo(_tempDir));

Assert.That(result, Has.Count.EqualTo(3));
}




[Test]
public void DiscoverConfigs_NonExistentPath_DoesNotThrow()
{
var mods = new List<Mod>();
Assert.DoesNotThrow(() => _service.DiscoverConfigs(Path.Combine(_tempDir, "missing"), mods));
}

[Test]
public void DiscoverConfigs_NonExistentPath_ModConfigRemainsNull()
{
var mod = CreateMod("Author.Mod1");

_service.DiscoverConfigs(Path.Combine(_tempDir, "missing"), new List<Mod> { mod });

Assert.That(mod.Config, Is.Null);
}

[Test]
public void DiscoverConfigs_MatchingMod_ConfigAssigned()
{
var mod = CreateMod("Author.Mod1");
var configContent = """{"key": "value"}""";
File.WriteAllText(Path.Combine(mod.ModFileInfo.DirectoryName!, "config.json"), configContent);

_service.DiscoverConfigs(_tempDir, new List<Mod> { mod });

Assert.That(mod.Config, Is.Not.Null);
Assert.That(mod.Config!.UniqueId, Is.EqualTo("Author.Mod1"));
Assert.That(mod.Config.Data, Is.EqualTo(configContent));
}

[Test]
public void DiscoverConfigs_NoMatchingMod_ConfigRemainsNull()
{
var mod = CreateMod("Author.Mod1");
var otherDir = CreateSubdir("Author.Mod2");
File.WriteAllText(Path.Combine(otherDir, "config.json"), "{}");
File.WriteAllText(Path.Combine(otherDir, "manifest.json"), "{}");

_service.DiscoverConfigs(_tempDir, new List<Mod> { mod });

Assert.That(mod.Config, Is.Null);
}




private string CreateSubdir(string name)
{
var path = Path.Combine(_tempDir, name);
Directory.CreateDirectory(path);
return path;
}

private Mod CreateMod(string uniqueId, string version = "1.0.0", string name = "Test Mod", string author = "Test Author")
{
var modDir = CreateSubdir(uniqueId);
var manifestPath = Path.Combine(modDir, "manifest.json");
File.WriteAllText(manifestPath, "{}");
var manifest = new Manifest { UniqueID = uniqueId, Name = name, Author = author, Version = version };
return new Mod(manifest, new FileInfo(manifestPath), uniqueId, version, name, null, author);
}

private sealed class FakeModDiscoveryService : IModDiscoveryService
{
public bool ReturnValue { get; set; }

public bool ParentFolderContainsPeriod(string oldestAncestorPath, DirectoryInfo? directoryInfo)
=> ReturnValue;
}
}
25 changes: 25 additions & 0 deletions Stardrop.Test/Stardrop.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Stardrop\Stardrop.csproj" />
</ItemGroup>

<!-- Avalonia's build tasks are pulled in transitively via the ProjectReference above.
The test project has no XAML files, so suppress the task to avoid a file-lock
race when both projects are built in parallel (CI reproduces this reliably). -->
<Target Name="CompileAvaloniaXaml" />

</Project>
5 changes: 5 additions & 0 deletions Stardrop/Stardrop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
<PublishSingleFile>true</PublishSingleFile>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Stardrop.Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
<Content Include="Themes\**" CopyToOutputDirectory="PreserveNewest" />
Expand Down
6 changes: 6 additions & 0 deletions Stardrop/Stardrop.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31729.503
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stardrop", "Stardrop.csproj", "{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stardrop.Test", "..\Stardrop.Test\Stardrop.Test.csproj", "{2A4FE1F1-6518-4C01-8C7D-EA14F29BF929}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,6 +17,10 @@ Global
{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68543B63-0EB4-43E8-9B7B-7AFA64097CAF}.Release|Any CPU.Build.0 = Release|Any CPU
{2A4FE1F1-6518-4C01-8C7D-EA14F29BF929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A4FE1F1-6518-4C01-8C7D-EA14F29BF929}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A4FE1F1-6518-4C01-8C7D-EA14F29BF929}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A4FE1F1-6518-4C01-8C7D-EA14F29BF929}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
13 changes: 13 additions & 0 deletions Stardrop/Utilities/Internal/IModConfigService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Stardrop.Models;

namespace Stardrop.Utilities.Internal;

public interface IModConfigService
{
void DiscoverConfigs(string modsFilePath, IReadOnlyList<Mod> mods, bool useArchive = false);

List<Config> GetPendingConfigUpdates(Profile profile, IReadOnlyList<Mod> mods,
bool excludeMissingConfigs = false, bool useArchiveAsBase = false);

}
9 changes: 9 additions & 0 deletions Stardrop/Utilities/Internal/IModDiscoveryService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.IO;

namespace Stardrop.Utilities.Internal;

public interface IModDiscoveryService
{

bool ParentFolderContainsPeriod(string oldestAncestorPath, DirectoryInfo? directoryInfo);
}
Loading
Loading