Skip to content

Commit cdd1f10

Browse files
authored
Improve the verification of CK3 Mod Directory (#2739) #patch
Added logic to verify that CK3ModsPath points to the standard Crusader Kings III mods directory, including handling trailing separators and platform-specific path comparisons. Introduced unit tests to ensure correct validation and error handling for both valid and invalid paths. Sentry event ID: 2bfcd84eccba4d66ba420aba627f2d05
1 parent 20f2c6a commit cdd1f10

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

ImperatorToCK3.UnitTests/ConfigurationTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using commonItems.Mods;
22
using ImperatorToCK3.Exceptions;
3+
using System;
4+
using System.IO;
5+
using System.Reflection;
36
using Xunit;
47

58
namespace ImperatorToCK3.UnitTests;
@@ -32,4 +35,40 @@ public void DetectSpecificCK3ModsThrowsExceptionForUnsupportedModCombinations()
3235
Assert.Equal("The converter doesn't support combining The Fallen Eagle with Asia Expansion Project!",
3336
ex.Message);
3437
}
38+
39+
[Fact]
40+
public void VerifyCK3ModsPathThrowsWhenNotPointingToStandardModsDirectory() {
41+
var tempRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
42+
Directory.CreateDirectory(tempRoot);
43+
try {
44+
var config = new Configuration {
45+
CK3ModsPath = tempRoot
46+
};
47+
var verifyMethod = typeof(Configuration).GetMethod("VerifyCK3ModsPath", BindingFlags.Instance | BindingFlags.NonPublic);
48+
var exception = Assert.Throws<TargetInvocationException>(() => verifyMethod!.Invoke(config, null));
49+
var userError = Assert.IsType<UserErrorException>(exception.InnerException);
50+
var expectedSuffix = Path.Combine("Paradox Interactive", "Crusader Kings III", "mod");
51+
Assert.Contains(expectedSuffix, userError.Message);
52+
}
53+
finally {
54+
Directory.Delete(tempRoot, recursive: true);
55+
}
56+
}
57+
58+
[Fact]
59+
public void VerifyCK3ModsPathAcceptsStandardDirectoryWithTrailingSeparator() {
60+
var tempRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
61+
var modsPath = Path.Combine(tempRoot, "Paradox Interactive", "Crusader Kings III", "mod");
62+
Directory.CreateDirectory(modsPath);
63+
try {
64+
var config = new Configuration {
65+
CK3ModsPath = modsPath + Path.DirectorySeparatorChar
66+
};
67+
var verifyMethod = typeof(Configuration).GetMethod("VerifyCK3ModsPath", BindingFlags.Instance | BindingFlags.NonPublic);
68+
verifyMethod!.Invoke(config, null);
69+
}
70+
finally {
71+
Directory.Delete(tempRoot, recursive: true);
72+
}
73+
}
3574
}

ImperatorToCK3/Configuration.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,18 @@ private void VerifyCK3ModsPath() {
256256
if (!Directory.Exists(CK3ModsPath)) {
257257
throw new UserErrorException($"{CK3ModsPath} does not exist!");
258258
}
259-
259+
260+
var normalizedCK3ModsPath = Path.TrimEndingDirectorySeparator(
261+
CK3ModsPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
262+
);
263+
var expectedSuffix = Path.Combine("Paradox Interactive", "Crusader Kings III", "mod");
264+
var comparison = OperatingSystem.IsWindows() || OperatingSystem.IsMacOS()
265+
? StringComparison.OrdinalIgnoreCase
266+
: StringComparison.Ordinal;
267+
if (!normalizedCK3ModsPath.EndsWith(expectedSuffix, comparison)) {
268+
throw new UserErrorException($"{CK3ModsPath} is not a valid CK3 mods directory! It should end with {expectedSuffix}.");
269+
}
270+
260271
// If the mods folder contains any files, at least one on them should have a .mod extension.
261272
var filesInFolder = Directory.GetFiles(CK3ModsPath);
262273
if (filesInFolder.Length > 0) {

0 commit comments

Comments
 (0)