-
Notifications
You must be signed in to change notification settings - Fork 1
feat(#6): Auto-detect game installation directory #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| using System; | ||
| using System.IO; | ||
| using System.Threading.Tasks; | ||
| using Xunit; | ||
| using BannerlordModEditor.Common.Services; | ||
|
|
||
| namespace BannerlordModEditor.Common.Tests.Services | ||
| { | ||
| public class GameDirectoryScannerTests | ||
| { | ||
| private readonly GameDirectoryScanner _scanner; | ||
|
|
||
| public GameDirectoryScannerTests() | ||
| { | ||
| _scanner = new GameDirectoryScanner(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task ScanForGameDirectoriesAsync_ReturnsEmptyListWhenNoGameInstalled() | ||
| { | ||
| var result = await _scanner.ScanForGameDirectoriesAsync(); | ||
| Assert.NotNull(result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void IsValidGameDirectory_ReturnsFalseForNullPath() | ||
| { | ||
| var result = _scanner.IsValidGameDirectory(null!); | ||
| Assert.False(result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void IsValidGameDirectory_ReturnsFalseForEmptyPath() | ||
| { | ||
| var result = _scanner.IsValidGameDirectory(string.Empty); | ||
| Assert.False(result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void IsValidGameDirectory_ReturnsFalseForNonExistentPath() | ||
| { | ||
| var result = _scanner.IsValidGameDirectory("/nonexistent/path"); | ||
| Assert.False(result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void IsValidGameDirectory_ReturnsFalseForDirectoryWithoutModuleData() | ||
| { | ||
| var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); | ||
| Directory.CreateDirectory(tempDir); | ||
|
|
||
| try | ||
| { | ||
| var result = _scanner.IsValidGameDirectory(tempDir); | ||
| Assert.False(result); | ||
| } | ||
| finally | ||
| { | ||
| Directory.Delete(tempDir, true); | ||
| } | ||
| } | ||
|
|
||
| [Fact] | ||
| public void IsValidGameDirectory_ReturnsTrueForValidBannerlordDirectory() | ||
| { | ||
| var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); | ||
| var modulesDir = Path.Combine(tempDir, "Modules"); | ||
| var nativeDir = Path.Combine(modulesDir, "Native"); | ||
|
|
||
| Directory.CreateDirectory(nativeDir); | ||
|
|
||
| try | ||
| { | ||
| var result = _scanner.IsValidGameDirectory(tempDir); | ||
| Assert.True(result); | ||
| } | ||
| finally | ||
| { | ||
| Directory.Delete(tempDir, true); | ||
| } | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetGameVersion_ReturnsNullForNonExistentDirectory() | ||
| { | ||
| var result = _scanner.GetGameVersion("/nonexistent/path"); | ||
| Assert.Null(result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetGameVersion_ReadsFromVersionFile() | ||
| { | ||
| var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); | ||
| Directory.CreateDirectory(tempDir); | ||
|
|
||
| try | ||
| { | ||
| var versionFile = Path.Combine(tempDir, "version.txt"); | ||
| File.WriteAllText(versionFile, "1.2.9.0"); | ||
|
|
||
| var result = _scanner.GetGameVersion(tempDir); | ||
| Assert.Equal("1.2.9.0", result); | ||
| } | ||
| finally | ||
| { | ||
| Directory.Delete(tempDir, true); | ||
| } | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetGameVersion_ReadsFromConfigFile() | ||
| { | ||
| var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); | ||
| Directory.CreateDirectory(tempDir); | ||
|
|
||
| try | ||
| { | ||
| var configFile = Path.Combine(tempDir, "config.txt"); | ||
| File.WriteAllText(configFile, "version=1.3.15.0\nother_setting=value"); | ||
|
|
||
| var result = _scanner.GetGameVersion(tempDir); | ||
| Assert.Equal("1.3.15.0", result); | ||
| } | ||
| finally | ||
| { | ||
| Directory.Delete(tempDir, true); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,251 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Threading.Tasks; | ||||
|
|
||||
| namespace BannerlordModEditor.Common.Services | ||||
| { | ||||
| public class GameDirectoryScanner : IGameDirectoryScanner | ||||
| { | ||||
| private const string BannerlordAppId = "261550"; | ||||
|
||||
| private const string BannerlordAppId = "261550"; |
Copilot
AI
Mar 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libraryfolders.vdf lines like "path" "D:\\SteamLibrary" will typically split into 2 tokens (path, D:\\SteamLibrary) with the current Split('"', RemoveEmptyEntries) usage, so parts.Length >= 4 will never be satisfied and Steam libraries from the VDF won’t be discovered. Consider parsing the VDF with a more robust approach (e.g., regex to capture the second quoted string, or a minimal VDF parser) and extracting the value token directly.
Copilot
AI
Mar 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swallowing all exceptions silently makes detection failures hard to diagnose (e.g., malformed VDF, permission issues). At minimum, catch specific exceptions and either log/debug-trace them or include a comment explaining why it’s safe to ignore; otherwise troubleshooting “why auto-detect doesn’t work” becomes very difficult.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test name claims the result is empty “when no game installed”, but it only asserts
NotNulland also depends on the machine’s real Steam/GOG/Epic state (making it non-deterministic and potentially slow). To make it a real unit test, inject filesystem/environment dependencies (or an abstraction) and assert the expected contents (e.g., empty list) using a controlled fake setup.