Test with long paths on Windows

Long paths can be greater than 260 characters long, but each path component is still limited to 255 characters. The latter is also commonly the component length limit on Linux.

Support for long paths requires Windows 10 1607 or later and a Registry value to be set[1], so to make the cause of test failures clearer when that isn't the case, there's one test that checks that Registry value is set, and long paths are not used in the other tests if it isn't set, so only that one test should failed if the system isn't configured as expected.

GitHub Action's Windows runners do have the Registry value set[2].

This doesn't set the manifest for the Rust tests because it seems to be very difficult to set a manifest for only the tests, and it's not worth the effort when the only tests that fail are those that try to create a symlink, especially since those cases are also covered by the C++ tests.

[1]: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later
[2]: https://github.com/actions/runner-images/blob/releases/win22/20250921/images/windows/scripts/build/Configure-BaseImage.ps1#L73
This commit is contained in:
Oliver Hamlet
2025-09-28 13:41:04 +01:00
parent 9e5d902886
commit 6bc6113bb7
6 changed files with 168 additions and 77 deletions
+3
View File
@@ -66,6 +66,9 @@ set(LIBLOOT_INTERFACE_TESTS_ALL_SOURCES
"${PROJECT_SOURCE_DIR}/src/tests/test_helpers.h"
"${PROJECT_SOURCE_DIR}/src/tests/printers.h")
if(MSVC)
list(APPEND LIBLOOT_INTERFACE_TESTS_ALL_SOURCES "${PROJECT_SOURCE_DIR}/src/tests/libloot_tests.manifest")
endif()
##############################
# Define Targets
+6
View File
@@ -113,6 +113,12 @@ TEST(Filesystem, u8pathConvertsCharacterEncodingFromUtf8ToNative) {
EXPECT_EQ(utf16, path.u16string());
}
#ifdef _WIN32
TEST(WindowsRegistry, hasLongPathsEnabled) {
EXPECT_TRUE(loot::test::windowsHasLongPathsEnabled());
}
#endif
namespace loot {
namespace test {
void testLoggingCallback(LogLevel, std::string_view) {
+8
View File
@@ -0,0 +1,8 @@
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>
+30 -2
View File
@@ -31,6 +31,10 @@ along with LOOT. If not, see
#include "loot/enum/game_type.h"
#ifdef _WIN32
#include <Windows.h>
#endif
namespace loot::test {
bool supportsLightPlugins(GameType gameType) {
return gameType == GameType::tes5se || gameType == GameType::tes5vr ||
@@ -63,6 +67,22 @@ std::filesystem::path getSourceArchivesPath(GameType gameType) {
}
}
#ifdef _WIN32
bool windowsHasLongPathsEnabled() {
DWORD value = 0;
DWORD valueSize = sizeof(value);
LONG ret = RegGetValue(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
L"LongPathsEnabled",
RRF_RT_REG_DWORD,
NULL,
&value,
&valueSize);
return ret == ERROR_SUCCESS && value == 1;
}
#endif
std::filesystem::path getRootTestPath() {
std::random_device randomDevice;
std::default_random_engine prng(randomDevice());
@@ -77,8 +97,16 @@ std::filesystem::path getRootTestPath() {
directoryName.push_back(static_cast<char>(dist(prng)));
}
return std::filesystem::absolute(std::filesystem::temp_directory_path() /
std::filesystem::u8path(directoryName));
auto tempPath = std::filesystem::temp_directory_path() /
std::filesystem::u8path(directoryName);
#ifdef _WIN32
if (windowsHasLongPathsEnabled()) {
tempPath /= std::filesystem::u8path(std::string(255, 'a'));
}
#endif
return std::filesystem::absolute(tempPath);
}
}