Skip to content

Commit 0377a04

Browse files
authored
Fix exception when provided CK3 mods folder path ends with a slash (#2918) #patch
Sentry event ID: ee16bf8bb8054f129d71436dbddfc861
1 parent 85e26c4 commit 0377a04

3 files changed

Lines changed: 78 additions & 4 deletions

File tree

ImperatorToCK3.UnitTests/ConfigurationTests.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using commonItems;
12
using commonItems.Exceptions;
23
using commonItems.Mods;
34
using System;
@@ -8,6 +9,60 @@
89
namespace ImperatorToCK3.UnitTests;
910

1011
public class ConfigurationTests {
12+
[Fact]
13+
public void TrailingSlashesAreTrimmedFromProvidedPaths() {
14+
const string configurationPath = "configuration.txt";
15+
var tempRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
16+
var imperatorPath = Path.Combine(tempRoot, "imperator");
17+
var imperatorDocPath = Path.Combine(tempRoot, "imperator_docs");
18+
var ck3Path = Path.Combine(tempRoot, "ck3");
19+
var ck3ModsPath = Path.Combine(tempRoot, "Paradox Interactive", "Crusader Kings III", "mod");
20+
21+
Directory.CreateDirectory(Path.Combine(imperatorPath, "binaries"));
22+
Directory.CreateDirectory(Path.Combine(imperatorPath, "launcher"));
23+
Directory.CreateDirectory(Path.Combine(imperatorDocPath, "mod"));
24+
Directory.CreateDirectory(Path.Combine(ck3Path, "binaries"));
25+
Directory.CreateDirectory(Path.Combine(ck3Path, "launcher"));
26+
Directory.CreateDirectory(ck3ModsPath);
27+
28+
var imperatorExeName = OperatingSystem.IsWindows() ? "imperator.exe" : "imperator";
29+
var ck3ExeName = OperatingSystem.IsWindows() ? "ck3.exe" : "ck3";
30+
File.WriteAllText(Path.Combine(imperatorPath, "binaries", imperatorExeName), "");
31+
File.WriteAllText(Path.Combine(ck3Path, "binaries", ck3ExeName), "");
32+
File.WriteAllText(Path.Combine(imperatorPath, "launcher", "launcher-settings.json"), "{\"version\":\"2.0.4\"}");
33+
File.WriteAllText(Path.Combine(ck3Path, "launcher", "launcher-settings.json"), "{\"version\":\"1.15.0\"}");
34+
35+
var imperatorPathForConfig = imperatorPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
36+
var imperatorDocPathForConfig = imperatorDocPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
37+
var ck3PathForConfig = ck3Path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
38+
var ck3ModsPathForConfig = ck3ModsPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
39+
40+
var imperatorPathWithTrailingSlash = imperatorPathForConfig + Path.AltDirectorySeparatorChar;
41+
var imperatorDocPathWithTrailingSlash = imperatorDocPathForConfig + Path.AltDirectorySeparatorChar;
42+
var ck3PathWithTrailingSlash = ck3PathForConfig + Path.AltDirectorySeparatorChar;
43+
var ck3ModsPathWithTrailingSlash = ck3ModsPathForConfig + Path.AltDirectorySeparatorChar;
44+
45+
try {
46+
string content =
47+
$"ImperatorDirectory = \"{imperatorPathWithTrailingSlash}\"{Environment.NewLine}" +
48+
$"ImperatorDocDirectory = \"{imperatorDocPathWithTrailingSlash}\"{Environment.NewLine}" +
49+
$"CK3directory = \"{ck3PathWithTrailingSlash}\"{Environment.NewLine}" +
50+
$"targetGameModPath = \"{ck3ModsPathWithTrailingSlash}\"{Environment.NewLine}";
51+
52+
File.WriteAllText(configurationPath, content);
53+
var config = new Configuration(new ConverterVersion());
54+
55+
Assert.Equal(imperatorPathForConfig, config.ImperatorPath);
56+
Assert.Equal(imperatorDocPathForConfig, config.ImperatorDocPath);
57+
Assert.Equal(ck3PathForConfig, config.CK3Path);
58+
Assert.Equal(ck3ModsPathForConfig, config.CK3ModsPath);
59+
}
60+
finally {
61+
File.Delete(configurationPath);
62+
Directory.Delete(tempRoot, recursive: true);
63+
}
64+
}
65+
1166
[Fact]
1267
public void DetectSpecificCK3ModsThrowsExceptionForUnsupportedModCombinations() {
1368
const string tfeName = "The Fallen Eagle";
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.IO;
2+
3+
namespace ImperatorToCK3.CommonUtils;
4+
5+
internal static class PathHelper {
6+
internal static string RemoveTrailingSeparators(string path) {
7+
if (string.IsNullOrEmpty(path))
8+
return path;
9+
10+
string root = Path.GetPathRoot(path) ?? string.Empty;
11+
string trimmed = path.TrimEnd(
12+
Path.DirectorySeparatorChar,
13+
Path.AltDirectorySeparatorChar
14+
);
15+
16+
return trimmed.Length == 0 ? root : trimmed;
17+
}
18+
}

ImperatorToCK3/Configuration.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using commonItems.Collections;
33
using commonItems.Exceptions;
44
using commonItems.Mods;
5+
using ImperatorToCK3.CommonUtils;
56
using System;
67
using System.Collections.Generic;
78
using System.Globalization;
@@ -65,10 +66,10 @@ private void RegisterKeys(Parser parser) {
6566
SaveGamePath = reader.GetString();
6667
Logger.Info($"Save game set to: {SaveGamePath}");
6768
});
68-
parser.RegisterKeyword("ImperatorDirectory", reader => ImperatorPath = reader.GetString());
69-
parser.RegisterKeyword("ImperatorDocDirectory", reader => ImperatorDocPath = reader.GetString());
70-
parser.RegisterKeyword("CK3directory", reader => CK3Path = reader.GetString());
71-
parser.RegisterKeyword("targetGameModPath", reader => CK3ModsPath = reader.GetString());
69+
parser.RegisterKeyword("ImperatorDirectory", reader => ImperatorPath = PathHelper.RemoveTrailingSeparators(reader.GetString()));
70+
parser.RegisterKeyword("ImperatorDocDirectory", reader => ImperatorDocPath = PathHelper.RemoveTrailingSeparators(reader.GetString()));
71+
parser.RegisterKeyword("CK3directory", reader => CK3Path = PathHelper.RemoveTrailingSeparators(reader.GetString()));
72+
parser.RegisterKeyword("targetGameModPath", reader => CK3ModsPath = PathHelper.RemoveTrailingSeparators(reader.GetString()));
7273
parser.RegisterKeyword("selectedMods", reader => {
7374
SelectedCK3Mods.Clear();
7475
SelectedCK3Mods.UnionWith(reader.GetStrings());

0 commit comments

Comments
 (0)