From dfa47a6f473142b357b39f2807b54dd9d6958241 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 18 Aug 2018 17:35:18 +0100 Subject: [PATCH] Switch from boost::filesystem to std::filesystem This commit mostly just swaps namespaces. Boost and std handle character encoding changes differently, so additional changes and tests will be required. Other than namespace swapping, changes were made to resolve the following issues causing compilation or test failures: - std parent_path() doesn't throw if the path is empty, so some thrown exceptions have changed type - std path doesn't throw if it's an invalid path, so some thrown exceptions have changed type - there is no std unique_path(), so I'm using Boost.UUID to generate something unique instead. A std-only solution is possible but messier - last_write_time() doesn't work with time_t, but std::chrono clocks instead - Removing the owner_write permission is now insufficient, but setting permissions to be only owner_read works - Junction links in Windows no longer appear as directories, and calling is_directory() on a symlink throws an exception. - Creating symlink directories expects an absolute link path or the link will be created but will be unresolvable. --- .travis.yml | 2 +- CMakeLists.txt | 5 +- src/api/api.cpp | 14 ++- src/api/api_database.cpp | 22 ++--- src/api/api_database.h | 2 +- src/api/game/game.cpp | 12 ++- src/api/game/game.h | 11 ++- src/api/game/game_cache.cpp | 4 +- src/api/game/game_cache.h | 6 +- src/api/game/load_order_handler.cpp | 6 +- src/api/game/load_order_handler.h | 6 +- src/api/helpers/crc.cpp | 7 +- src/api/helpers/crc.h | 5 +- src/api/helpers/git_helper.cpp | 19 ++-- src/api/helpers/git_helper.h | 12 +-- src/api/helpers/version.cpp | 2 +- src/api/helpers/version.h | 5 +- src/api/masterlist.cpp | 12 +-- src/api/masterlist.h | 9 +- src/api/metadata/condition_evaluator.cpp | 50 +++++------ src/api/metadata/condition_evaluator.h | 19 ++-- src/api/metadata/condition_grammar.h | 2 +- src/api/metadata/plugin_metadata.cpp | 2 +- src/api/metadata_list.cpp | 11 +-- src/api/metadata_list.h | 7 +- src/api/plugin.cpp | 26 +++--- src/api/plugin.h | 10 +-- .../api/interface/api_game_operations_test.h | 8 +- .../api/interface/create_game_handle_test.h | 29 +++--- .../api/interface/database_interface_test.h | 54 +++++------ src/tests/api/interface/game_interface_test.h | 4 +- src/tests/api/interface/main.cpp | 1 - .../api/internals/game/game_cache_test.h | 2 +- src/tests/api/internals/game/game_test.h | 12 +-- .../api/internals/helpers/git_helper_test.h | 40 ++++----- .../api/internals/helpers/version_test.h | 2 +- src/tests/api/internals/main.cpp | 82 ++++++++++++++++- src/tests/api/internals/masterlist_test.h | 26 +++--- .../metadata/condition_grammar_test.h | 8 +- src/tests/api/internals/metadata_list_test.h | 26 +++--- src/tests/api/internals/plugin_test.h | 8 +- .../internals/sorting/plugin_sorter_test.h | 12 +-- src/tests/common_game_test_fixture.h | 90 ++++++++++--------- 43 files changed, 388 insertions(+), 304 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8dcb7c5c..dea00609 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: - export CXX="g++-8" CC="gcc-8" # Build Boost. - wget https://raw.githubusercontent.com/WrinklyNinja/ci-scripts/1.5.0/install_boost.py - - python install_boost.py --directory ~ --boost-version 1.67.0 -a 64 -t gcc-8 filesystem locale system thread + - python install_boost.py --directory ~ --boost-version 1.67.0 -a 64 -t gcc-8 locale system # Install packages for generating documentation - pip install --user -r docs/requirements.txt # Add sphinx-build to PATH diff --git a/CMakeLists.txt b/CMakeLists.txt index 87b4f017..11f6fb35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ ELSE () set(RUST_TARGET x86_64-unknown-linux-gnu) ENDIF () -find_package(Boost REQUIRED COMPONENTS filesystem locale system) +find_package(Boost REQUIRED COMPONENTS locale system) ExternalProject_Add(GTest PREFIX "external" @@ -335,7 +335,8 @@ IF (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") icuuc icui18n ssh2 - http_parser) + http_parser + stdc++fs) IF (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set (LOOT_LIBS ${LOOT_LIBS} supc++) diff --git a/src/api/api.cpp b/src/api/api.cpp index 17cf32d3..a8add394 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -24,22 +24,21 @@ #include "loot/api.h" -#include +#include + #include #include "api/game/game.h" #include "api/helpers/logging.h" -namespace fs = boost::filesystem; +namespace fs = std::filesystem; namespace loot { std::string ResolvePath(const std::string& path) { - // NTFS junction links show up as symlinks and directories, but resolving - // them just appends their target path. - if (path.empty() || !fs::is_symlink(path) || fs::is_directory(path)) - return path; + if (fs::is_symlink(path)) + return fs::read_symlink(path).string(); - return fs::read_symlink(path).string(); + return path; } LOOT_API void SetLoggingCallback( @@ -63,7 +62,6 @@ LOOT_API bool IsCompatible(const unsigned int versionMajor, LOOT_API void InitialiseLocale(const std::string& id) { std::locale::global(boost::locale::generator().generate(id)); - boost::filesystem::path::imbue(std::locale()); } LOOT_API std::shared_ptr CreateGameHandle( diff --git a/src/api/api_database.cpp b/src/api/api_database.cpp index db7ac37f..dd5d572b 100644 --- a/src/api/api_database.cpp +++ b/src/api/api_database.cpp @@ -36,7 +36,7 @@ namespace loot { ApiDatabase::ApiDatabase(const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler) : gameCache_(gameCache), @@ -52,7 +52,7 @@ void ApiDatabase::LoadLists(const std::string& masterlistPath, MetadataList userTemp; if (!masterlistPath.empty()) { - if (boost::filesystem::exists(masterlistPath)) { + if (std::filesystem::exists(masterlistPath)) { temp.Load(masterlistPath); } else { throw FileAccessError("The given masterlist path does not exist: " + @@ -61,7 +61,7 @@ void ApiDatabase::LoadLists(const std::string& masterlistPath, } if (!userlistPath.empty()) { - if (boost::filesystem::exists(userlistPath)) { + if (std::filesystem::exists(userlistPath)) { userTemp.Load(userlistPath); } else { throw FileAccessError("The given userlist path does not exist: " + @@ -75,11 +75,11 @@ void ApiDatabase::LoadLists(const std::string& masterlistPath, void ApiDatabase::WriteUserMetadata(const std::string& outputFile, const bool overwrite) const { - if (!boost::filesystem::exists( - boost::filesystem::path(outputFile).parent_path())) + if (!std::filesystem::exists( + std::filesystem::path(outputFile).parent_path())) throw std::invalid_argument("Output directory does not exist."); - if (boost::filesystem::exists(outputFile) && !overwrite) + if (std::filesystem::exists(outputFile) && !overwrite) throw FileAccessError( "Output file exists but overwrite is not set to true."); @@ -93,8 +93,8 @@ void ApiDatabase::WriteUserMetadata(const std::string& outputFile, bool ApiDatabase::UpdateMasterlist(const std::string& masterlistPath, const std::string& remoteURL, const std::string& remoteBranch) { - if (!boost::filesystem::is_directory( - boost::filesystem::path(masterlistPath).parent_path())) + if (!std::filesystem::is_directory( + std::filesystem::path(masterlistPath).parent_path())) throw std::invalid_argument("Given masterlist path \"" + masterlistPath + "\" does not have a valid parent directory."); @@ -250,11 +250,11 @@ void ApiDatabase::DiscardAllUserMetadata() { userlist_.Clear(); } // will only be overwritten if overwrite is true. void ApiDatabase::WriteMinimalList(const std::string& outputFile, const bool overwrite) const { - if (!boost::filesystem::exists( - boost::filesystem::path(outputFile).parent_path())) + if (!std::filesystem::exists( + std::filesystem::path(outputFile).parent_path())) throw std::invalid_argument("Output directory does not exist."); - if (boost::filesystem::exists(outputFile) && !overwrite) + if (std::filesystem::exists(outputFile) && !overwrite) throw FileAccessError( "Output file exists but overwrite is not set to true."); diff --git a/src/api/api_database.h b/src/api/api_database.h index aa1df596..811c8d7a 100644 --- a/src/api/api_database.h +++ b/src/api/api_database.h @@ -40,7 +40,7 @@ namespace loot { struct ApiDatabase : public DatabaseInterface { ApiDatabase(const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler); diff --git a/src/api/game/game.cpp b/src/api/game/game.cpp index 724ab933..391e703e 100644 --- a/src/api/game/game.cpp +++ b/src/api/game/game.cpp @@ -53,12 +53,10 @@ using std::string; using std::thread; using std::vector; -namespace fs = boost::filesystem; - namespace loot { Game::Game(const GameType gameType, - const boost::filesystem::path& gamePath, - const boost::filesystem::path& localDataPath) : + const std::filesystem::path& gamePath, + const std::filesystem::path& localDataPath) : type_(gameType), gamePath_(gamePath), cache_(std::make_shared()), @@ -78,7 +76,7 @@ Game::Game(const GameType gameType, GameType Game::Type() const { return type_; } -boost::filesystem::path Game::DataPath() const { return gamePath_ / "Data"; } +std::filesystem::path Game::DataPath() const { return gamePath_ / "Data"; } std::shared_ptr Game::GetCache() { return cache_; } @@ -246,8 +244,8 @@ void Game::SetLoadOrder(const std::vector& loadOrder) { void Game::CacheArchives() { const auto archiveFileExtension = GetArchiveFileExtension(Type()); - for (boost::filesystem::directory_iterator it(DataPath()); - it != boost::filesystem::directory_iterator(); + for (std::filesystem::directory_iterator it(DataPath()); + it != std::filesystem::directory_iterator(); ++it) { // Check if the path is an archive by checking if replacing its // file extension with the archive extension resolves to the same file. diff --git a/src/api/game/game.h b/src/api/game/game.h index 3ef95a5b..c3592867 100644 --- a/src/api/game/game.h +++ b/src/api/game/game.h @@ -25,10 +25,9 @@ #ifndef LOOT_API_GAME_GAME #define LOOT_API_GAME_GAME +#include #include -#include - #include "api/game/game_cache.h" #include "api/game/load_order_handler.h" #include "loot/game_interface.h" @@ -37,14 +36,14 @@ namespace loot { class Game : public GameInterface { public: Game(const GameType gameType, - const boost::filesystem::path& gamePath, - const boost::filesystem::path& gameLocalDataPath = ""); + const std::filesystem::path& gamePath, + const std::filesystem::path& gameLocalDataPath = ""); // Internal Methods // ////////////////////// GameType Type() const; - boost::filesystem::path DataPath() const; + std::filesystem::path DataPath() const; std::shared_ptr GetCache(); std::shared_ptr GetLoadOrderHandler(); @@ -85,7 +84,7 @@ private: std::shared_ptr database_; const GameType type_; - const boost::filesystem::path gamePath_; + const std::filesystem::path gamePath_; std::string masterFile_; }; diff --git a/src/api/game/game_cache.cpp b/src/api/game/game_cache.cpp index d2bb1d43..5ee07c93 100644 --- a/src/api/game/game_cache.cpp +++ b/src/api/game/game_cache.cpp @@ -117,12 +117,12 @@ void GameCache::AddPlugin(const Plugin&& plugin) { std::make_shared(std::move(plugin))); } -std::set GameCache::GetArchivePaths() const +std::set GameCache::GetArchivePaths() const { return archivePaths_; } -void GameCache::CacheArchivePath(const boost::filesystem::path& path) +void GameCache::CacheArchivePath(const std::filesystem::path& path) { lock_guard lock(mutex_); diff --git a/src/api/game/game_cache.h b/src/api/game/game_cache.h index d9f58316..cf7a3545 100644 --- a/src/api/game/game_cache.h +++ b/src/api/game/game_cache.h @@ -51,8 +51,8 @@ public: const std::string& pluginName) const; void AddPlugin(const Plugin&& plugin); - std::set GetArchivePaths() const; - void CacheArchivePath(const boost::filesystem::path& path); + std::set GetArchivePaths() const; + void CacheArchivePath(const std::filesystem::path& path); void ClearCachedConditions(); void ClearCachedPlugins(); @@ -62,7 +62,7 @@ private: std::unordered_map conditions_; std::unordered_map crcs_; std::unordered_map> plugins_; - std::set archivePaths_; + std::set archivePaths_; mutable std::mutex mutex_; }; diff --git a/src/api/game/load_order_handler.cpp b/src/api/game/load_order_handler.cpp index 094288a0..8d484837 100644 --- a/src/api/game/load_order_handler.cpp +++ b/src/api/game/load_order_handler.cpp @@ -58,8 +58,8 @@ LoadOrderHandler::LoadOrderHandler() : gh_(nullptr) {} LoadOrderHandler::~LoadOrderHandler() { lo_destroy_handle(gh_); } void LoadOrderHandler::Init(const GameType& gameType, - const boost::filesystem::path& gamePath, - const boost::filesystem::path& gameLocalAppData) { + const std::filesystem::path& gamePath, + const std::filesystem::path& gameLocalAppData) { if (gamePath.empty()) { throw std::invalid_argument("Game path is not initialised."); } @@ -138,7 +138,7 @@ std::vector LoadOrderHandler::GetImplicitlyActivePlugins() const { lo_get_implicitly_active_plugins(gh_, &pluginArr, &pluginArrSize); HandleError("get implicitly active plugins", ret); - + std::vector loadOrder(pluginArr, pluginArr + pluginArrSize); lo_free_string_array(pluginArr, pluginArrSize); diff --git a/src/api/game/load_order_handler.h b/src/api/game/load_order_handler.h index f1b38668..58f79559 100644 --- a/src/api/game/load_order_handler.h +++ b/src/api/game/load_order_handler.h @@ -25,11 +25,11 @@ #ifndef LOOT_API_GAME_LOAD_ORDER_HANDLER #define LOOT_API_GAME_LOAD_ORDER_HANDLER +#include #include #include #include -#include #include #include "loot/enum/game_type.h" @@ -41,8 +41,8 @@ public: ~LoadOrderHandler(); void Init(const GameType& game, - const boost::filesystem::path& gamePath, - const boost::filesystem::path& gameLocalAppData = ""); + const std::filesystem::path& gamePath, + const std::filesystem::path& gameLocalAppData = ""); void LoadCurrentState(); diff --git a/src/api/helpers/crc.cpp b/src/api/helpers/crc.cpp index 6e4c36e4..7af5361d 100644 --- a/src/api/helpers/crc.cpp +++ b/src/api/helpers/crc.cpp @@ -24,8 +24,9 @@ #include "api/helpers/crc.h" +#include + #include -#include #include "api/helpers/logging.h" @@ -46,14 +47,14 @@ size_t GetStreamSize(std::istream& stream) { } // Calculate the CRC of the given file for comparison purposes. -uint32_t GetCrc32(const boost::filesystem::path& filename) { +uint32_t GetCrc32(const std::filesystem::path& filename) { try { auto logger = getLogger(); if (logger) { logger->trace("Calculating CRC for: {}", filename.string()); } - boost::filesystem::ifstream ifile(filename, std::ios::binary); + std::ifstream ifile(filename, std::ios::binary); ifile.exceptions(std::ios_base::badbit | std::ios_base::failbit); static const size_t bufferSize = 8192; diff --git a/src/api/helpers/crc.h b/src/api/helpers/crc.h index 643d800f..507f72f0 100644 --- a/src/api/helpers/crc.h +++ b/src/api/helpers/crc.h @@ -26,11 +26,10 @@ #define LOOT_API_HELPERS_CRC #include - -#include +#include namespace loot { -uint32_t GetCrc32(const boost::filesystem::path& filename); +uint32_t GetCrc32(const std::filesystem::path& filename); } #endif diff --git a/src/api/helpers/git_helper.cpp b/src/api/helpers/git_helper.cpp index 6c078d42..1e0524a7 100644 --- a/src/api/helpers/git_helper.cpp +++ b/src/api/helpers/git_helper.cpp @@ -27,13 +27,17 @@ #include #include +#include +#include +#include + #include "api/helpers/logging.h" #include "loot/exception/error_categories.h" #include "loot/exception/git_state_error.h" using std::string; -namespace fs = boost::filesystem; +namespace fs = std::filesystem; namespace loot { GitHelper::GitHelper() : logger_(getLogger()) {} @@ -105,7 +109,7 @@ void GitHelper::InitialiseOptions(const std::string& branch, data_.clone_options.checkout_branch = branch.c_str(); } -void GitHelper::Open(const boost::filesystem::path& repoRoot) { +void GitHelper::Open(const std::filesystem::path& repoRoot) { if (logger_) { logger_->info("Attempting to open Git repository at: {}", repoRoot.string()); @@ -144,7 +148,7 @@ void GitHelper::Call(int error_code) { throw std::system_error(error_code, libgit2_category(), message); } -bool GitHelper::IsRepository(const boost::filesystem::path& path) { +bool GitHelper::IsRepository(const std::filesystem::path& path) { return git_repository_open_ext(NULL, path.string().c_str(), GIT_REPOSITORY_OPEN_NO_SEARCH, @@ -171,7 +175,7 @@ int GitHelper::DiffFileCallback(const git_diff_delta* delta, } // Clones a repository and opens it. -void GitHelper::Clone(const boost::filesystem::path& path, +void GitHelper::Clone(const std::filesystem::path& path, const std::string& url) { if (data_.repo != nullptr) throw GitStateError( @@ -191,7 +195,8 @@ void GitHelper::Clone(const boost::filesystem::path& path, if (logger_) { logger_->trace("Target repo path not empty, cloning into temporary directory."); } - auto directory = "LOOT-" + path.filename().string() + "-" + fs::unique_path().string(); + auto directory = "LOOT-" + path.filename().string() + "-" + + boost::lexical_cast((boost::uuids::random_generator())()); repoPath = fs::temp_directory_path() / directory; // Remove path in case it already exists. @@ -218,7 +223,7 @@ void GitHelper::Clone(const boost::filesystem::path& path, "Target repo path not empty, moving cloned files in."); } - std::vector filenamesToMove; + std::vector filenamesToMove; for (fs::directory_iterator it(repoPath); it != fs::directory_iterator(); ++it) { @@ -570,7 +575,7 @@ std::string GitHelper::GetHeadCommitDate() { return out.str(); } -bool GitHelper::IsFileDifferent(const boost::filesystem::path& repoRoot, +bool GitHelper::IsFileDifferent(const std::filesystem::path& repoRoot, const std::string& filename) { auto logger = getLogger(); diff --git a/src/api/helpers/git_helper.h b/src/api/helpers/git_helper.h index 7f1b5a58..9a242720 100644 --- a/src/api/helpers/git_helper.h +++ b/src/api/helpers/git_helper.h @@ -25,11 +25,11 @@ #ifndef LOOT_API_HELPERS_GIT_HELPER #define LOOT_API_HELPERS_GIT_HELPER +#include #include #include #include -#include namespace loot { class GitHelper { @@ -38,14 +38,14 @@ public: void InitialiseOptions(const std::string& branch, const std::string& filenameToCheckout); - void Open(const boost::filesystem::path& repoRoot); + void Open(const std::filesystem::path& repoRoot); void SetRemoteUrl(const std::string& remote, const std::string& url); - static bool IsRepository(const boost::filesystem::path& path); - static bool IsFileDifferent(const boost::filesystem::path& repoRoot, + static bool IsRepository(const std::filesystem::path& path); + static bool IsFileDifferent(const std::filesystem::path& repoRoot, const std::string& filename); - void Clone(const boost::filesystem::path& path, const std::string& url); + void Clone(const std::filesystem::path& path, const std::string& url); void Fetch(const std::string& remote); void CheckoutNewBranch(const std::string& remote, const std::string& branch); @@ -94,7 +94,7 @@ private: // Removes the read-only flag from some files in git repositories // created by libgit2. - void GrantWritePermissions(const boost::filesystem::path& path); + void GrantWritePermissions(const std::filesystem::path& path); void Call(int error_code); diff --git a/src/api/helpers/version.cpp b/src/api/helpers/version.cpp index f324ecab..a16fdd5c 100644 --- a/src/api/helpers/version.cpp +++ b/src/api/helpers/version.cpp @@ -94,7 +94,7 @@ Version::Version(const std::string& ver) { } } -Version::Version(const boost::filesystem::path& file) { +Version::Version(const std::filesystem::path& file) { #ifdef _WIN32 DWORD dummy = 0; DWORD size = GetFileVersionInfoSize(ToWinWide(file.string()).c_str(), &dummy); diff --git a/src/api/helpers/version.h b/src/api/helpers/version.h index 59832c3f..e721c5dd 100644 --- a/src/api/helpers/version.h +++ b/src/api/helpers/version.h @@ -25,18 +25,17 @@ #ifndef LOOT_API_HELPERS_VERSION #define LOOT_API_HELPERS_VERSION +#include #include #include -#include - namespace loot { // Version class for more robust version comparisons. class Version { public: Version(); Version(const std::string& ver); - Version(const boost::filesystem::path& file); + Version(const std::filesystem::path& file); std::string AsString() const; diff --git a/src/api/masterlist.cpp b/src/api/masterlist.cpp index 9700a082..08a3aa89 100644 --- a/src/api/masterlist.cpp +++ b/src/api/masterlist.cpp @@ -32,10 +32,10 @@ using std::string; -namespace fs = boost::filesystem; +namespace fs = std::filesystem; namespace loot { -MasterlistInfo Masterlist::GetInfo(const boost::filesystem::path& path, +MasterlistInfo Masterlist::GetInfo(const std::filesystem::path& path, bool shortID) { // Compare HEAD and working copy, and get revision info. GitHelper git; @@ -71,7 +71,7 @@ MasterlistInfo Masterlist::GetInfo(const boost::filesystem::path& path, return info; } -bool Masterlist::IsLatest(const boost::filesystem::path& path, +bool Masterlist::IsLatest(const std::filesystem::path& path, const std::string& repoBranch) { if (repoBranch.empty()) throw std::invalid_argument("Repository branch must not be empty."); @@ -96,7 +96,7 @@ bool Masterlist::IsLatest(const boost::filesystem::path& path, git.IsBranchCheckedOut(repoBranch); } -bool Masterlist::Update(const boost::filesystem::path& path, +bool Masterlist::Update(const std::filesystem::path& path, const std::string& repoUrl, const std::string& repoBranch) { GitHelper git; @@ -104,8 +104,8 @@ bool Masterlist::Update(const boost::filesystem::path& path, fs::path repoPath = path.parent_path(); string filename = path.filename().string(); - if (repoUrl.empty() || repoBranch.empty()) - throw std::invalid_argument("Repository URL and branch must not be empty."); + if (path.empty() || repoUrl.empty() || repoBranch.empty()) + throw std::invalid_argument("Repository path, URL and branch must not be empty."); if (logger) { logger->debug("Setting up checkout options."); diff --git a/src/api/masterlist.h b/src/api/masterlist.h index 3bd79d5e..78aa477b 100644 --- a/src/api/masterlist.h +++ b/src/api/masterlist.h @@ -25,24 +25,23 @@ #ifndef LOOT_API_MASTERLIST #define LOOT_API_MASTERLIST +#include #include -#include - #include "api/metadata_list.h" #include "loot/struct/masterlist_info.h" namespace loot { class Masterlist : public MetadataList { public: - bool Update(const boost::filesystem::path& path, + bool Update(const std::filesystem::path& path, const std::string& repoURL, const std::string& repoBranch); - static MasterlistInfo GetInfo(const boost::filesystem::path& path, + static MasterlistInfo GetInfo(const std::filesystem::path& path, bool shortID); - static bool IsLatest(const boost::filesystem::path& path, + static bool IsLatest(const std::filesystem::path& path, const std::string& repoBranch); }; } diff --git a/src/api/metadata/condition_evaluator.cpp b/src/api/metadata/condition_evaluator.cpp index bd5ffea1..30abf344 100644 --- a/src/api/metadata/condition_evaluator.cpp +++ b/src/api/metadata/condition_evaluator.cpp @@ -36,7 +36,7 @@ ConditionEvaluator::ConditionEvaluator() : loadOrderHandler_(nullptr) {} ConditionEvaluator::ConditionEvaluator( const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler) : gameType_(gameType), @@ -163,10 +163,10 @@ bool ConditionEvaluator::fileExists(const std::string& filePath) const { // Not a loaded plugin, check the filesystem. if (hasPluginFileExtension(filePath, gameType_)) - return boost::filesystem::exists(dataPath_ / filePath) || - boost::filesystem::exists(dataPath_ / (filePath + ".ghost")); + return std::filesystem::exists(dataPath_ / filePath) || + std::filesystem::exists(dataPath_ / (filePath + ".ghost")); else - return boost::filesystem::exists(dataPath_ / filePath); + return std::filesystem::exists(dataPath_ / filePath); } bool ConditionEvaluator::regexMatchExists( @@ -261,13 +261,13 @@ bool ConditionEvaluator::compareVersions(const std::string& filePath, (comparator == ">=" && trueVersion >= givenVersion)); } -void ConditionEvaluator::validatePath(const boost::filesystem::path& path) { +void ConditionEvaluator::validatePath(const std::filesystem::path& path) { auto logger = getLogger(); if (logger) { logger->trace("Checking to see if the path \"{}\" is safe.", path.string()); } - boost::filesystem::path temp; + std::filesystem::path temp; for (const auto& component : path) { if (component == ".") continue; @@ -288,14 +288,14 @@ void ConditionEvaluator::validateRegex(const std::string& regexString) { } } -boost::filesystem::path ConditionEvaluator::getRegexParentPath( +std::filesystem::path ConditionEvaluator::getRegexParentPath( const std::string& regexString) { size_t pos = regexString.rfind('/'); if (pos == std::string::npos) - return boost::filesystem::path(); + return std::filesystem::path(); - return boost::filesystem::path(regexString.substr(0, pos)); + return std::filesystem::path(regexString.substr(0, pos)); } std::string ConditionEvaluator::getRegexFilename( @@ -308,7 +308,7 @@ std::string ConditionEvaluator::getRegexFilename( return regexString.substr(pos + 1); } -std::pair ConditionEvaluator::splitRegex( +std::pair ConditionEvaluator::splitRegex( const std::string& regexString) { // Can't support a regex string where all path components may be regex, since // this could lead to massive scanning if an unfortunately-named directory is @@ -318,7 +318,7 @@ std::pair ConditionEvaluator::splitRegex( validateRegex(regexString); std::string filename = getRegexFilename(regexString); - boost::filesystem::path parent = getRegexParentPath(regexString); + std::filesystem::path parent = getRegexParentPath(regexString); validatePath(parent); @@ -330,19 +330,19 @@ std::pair ConditionEvaluator::splitRegex( "\": " + e.what()); } - return std::pair(parent, reg); + return std::pair(parent, reg); } bool ConditionEvaluator::isGameSubdirectory( - const boost::filesystem::path& path) const { - boost::filesystem::path parentPath = dataPath_ / path; + const std::filesystem::path& path) const { + std::filesystem::path parentPath = dataPath_ / path; - return boost::filesystem::exists(parentPath) && - boost::filesystem::is_directory(parentPath); + return std::filesystem::exists(parentPath) && + std::filesystem::is_directory(parentPath); } bool ConditionEvaluator::isRegexMatchInDataDirectory( - const std::pair& pathRegex, + const std::pair& pathRegex, const std::function condition) const { // Now we have a valid parent path and a regex filename. Check that the // parent path exists and is a directory. @@ -356,9 +356,9 @@ bool ConditionEvaluator::isRegexMatchInDataDirectory( } return std::any_of( - boost::filesystem::directory_iterator(dataPath_ / pathRegex.first), - boost::filesystem::directory_iterator(), - [&](const boost::filesystem::directory_entry& entry) { + std::filesystem::directory_iterator(dataPath_ / pathRegex.first), + std::filesystem::directory_iterator(), + [&](const std::filesystem::directory_entry& entry) { const std::string filename = entry.path().filename().string(); return std::regex_match(filename, pathRegex.second) && condition(filename); @@ -366,7 +366,7 @@ bool ConditionEvaluator::isRegexMatchInDataDirectory( } bool ConditionEvaluator::areRegexMatchesInDataDirectory( - const std::pair& pathRegex, + const std::pair& pathRegex, const std::function condition) const { bool foundOneFile = false; @@ -405,7 +405,7 @@ bool ConditionEvaluator::parseCondition(const std::string& condition) const { } Version ConditionEvaluator::getVersion(const std::string& filePath) const { if (filePath == "LOOT") - return Version(boost::filesystem::absolute("LOOT.exe")); + return Version(std::filesystem::absolute("LOOT.exe")); else { // If the file is a plugin, its version needs to be extracted // from its description field. Try getting an entry from the @@ -440,7 +440,7 @@ uint32_t ConditionEvaluator::getCrc(const std::string & file) const { } if (file == "LOOT") { - crc = GetCrc32(boost::filesystem::absolute("LOOT.exe")); + crc = GetCrc32(std::filesystem::absolute("LOOT.exe")); gameCache_->CacheCrc(file, crc); return crc; } @@ -453,11 +453,11 @@ uint32_t ConditionEvaluator::getCrc(const std::string & file) const { // Otherwise calculate it from the file. if (crc == 0) { - if (boost::filesystem::exists(dataPath_ / file)) { + if (std::filesystem::exists(dataPath_ / file)) { crc = GetCrc32(dataPath_ / file); } else if (hasPluginFileExtension(file, gameType_) && - boost::filesystem::exists(dataPath_ / (file + ".ghost"))) { + std::filesystem::exists(dataPath_ / (file + ".ghost"))) { crc = GetCrc32(dataPath_ / (file + ".ghost")); } } diff --git a/src/api/metadata/condition_evaluator.h b/src/api/metadata/condition_evaluator.h index 10c182cb..945d3443 100644 --- a/src/api/metadata/condition_evaluator.h +++ b/src/api/metadata/condition_evaluator.h @@ -25,11 +25,10 @@ #ifndef LOOT_API_METADATA_CONDITION_EVALUATOR #define LOOT_API_METADATA_CONDITION_EVALUATOR +#include #include #include -#include - #include "api/game/game_cache.h" #include "api/game/load_order_handler.h" #include "api/helpers/version.h" @@ -41,7 +40,7 @@ class ConditionEvaluator { public: ConditionEvaluator(); ConditionEvaluator(const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler); @@ -66,24 +65,24 @@ public: const std::string& comparator) const; private: - static void validatePath(const boost::filesystem::path& path); + static void validatePath(const std::filesystem::path& path); static void validateRegex(const std::string& regexString); - static boost::filesystem::path getRegexParentPath( + static std::filesystem::path getRegexParentPath( const std::string& regexString); static std::string getRegexFilename(const std::string& regexString); // Split a regex string into the non-regex filesystem parent path, and the // regex filename. - static std::pair splitRegex( + static std::pair splitRegex( const std::string& regexString); - bool isGameSubdirectory(const boost::filesystem::path& path) const; + bool isGameSubdirectory(const std::filesystem::path& path) const; bool isRegexMatchInDataDirectory( - const std::pair& pathRegex, + const std::pair& pathRegex, const std::function condition) const; bool areRegexMatchesInDataDirectory( - const std::pair& pathRegex, + const std::pair& pathRegex, const std::function condition) const; bool parseCondition(const std::string& condition) const; @@ -95,7 +94,7 @@ private: uint32_t getCrc(const std::string& file) const; const GameType gameType_; - const boost::filesystem::path dataPath_; + const std::filesystem::path dataPath_; const std::shared_ptr gameCache_; const std::shared_ptr loadOrderHandler_; }; diff --git a/src/api/metadata/condition_grammar.h b/src/api/metadata/condition_grammar.h index 10f976f9..05b6224d 100644 --- a/src/api/metadata/condition_grammar.h +++ b/src/api/metadata/condition_grammar.h @@ -34,10 +34,10 @@ #endif #include +#include #include #include -#include #include #include #include diff --git a/src/api/metadata/plugin_metadata.cpp b/src/api/metadata/plugin_metadata.cpp index f93d4eae..89348f83 100644 --- a/src/api/metadata/plugin_metadata.cpp +++ b/src/api/metadata/plugin_metadata.cpp @@ -24,10 +24,10 @@ #include "loot/metadata/plugin_metadata.h" +#include #include #include -#include #include #include "api/game/game.h" diff --git a/src/api/metadata_list.cpp b/src/api/metadata_list.cpp index c765f2f6..1a95ef1c 100644 --- a/src/api/metadata_list.cpp +++ b/src/api/metadata_list.cpp @@ -24,7 +24,8 @@ #include "api/metadata_list.h" -#include +#include +#include #include "api/game/game.h" #include "api/helpers/logging.h" @@ -34,7 +35,7 @@ #include "loot/exception/file_access_error.h" namespace loot { -void MetadataList::Load(const boost::filesystem::path& filepath) { +void MetadataList::Load(const std::filesystem::path& filepath) { Clear(); auto logger = getLogger(); @@ -42,7 +43,7 @@ void MetadataList::Load(const boost::filesystem::path& filepath) { logger->debug("Loading file: {}", filepath.string()); } - boost::filesystem::ifstream in(filepath); + std::ifstream in(filepath); if (!in.good()) throw FileAccessError("Cannot open " + filepath.string()); @@ -79,7 +80,7 @@ void MetadataList::Load(const boost::filesystem::path& filepath) { } } -void MetadataList::Save(const boost::filesystem::path& filepath) const { +void MetadataList::Save(const std::filesystem::path& filepath) const { auto logger = getLogger(); if (logger) { logger->trace("Saving metadata list to: {}", filepath.string()); @@ -107,7 +108,7 @@ void MetadataList::Save(const boost::filesystem::path& filepath) const { emitter << YAML::EndMap; - boost::filesystem::ofstream out(filepath); + std::ofstream out(filepath); if (out.fail()) throw FileAccessError("Couldn't open output file."); diff --git a/src/api/metadata_list.h b/src/api/metadata_list.h index f9d6709b..3aa86948 100644 --- a/src/api/metadata_list.h +++ b/src/api/metadata_list.h @@ -25,13 +25,12 @@ #ifndef LOOT_API_METADATA_LIST #define LOOT_API_METADATA_LIST +#include #include #include #include #include -#include - #include "api/metadata/condition_evaluator.h" #include "loot/metadata/group.h" #include "loot/metadata/plugin_metadata.h" @@ -39,8 +38,8 @@ namespace loot { class MetadataList { public: - void Load(const boost::filesystem::path& filepath); - void Save(const boost::filesystem::path& filepath) const; + void Load(const std::filesystem::path& filepath); + void Save(const std::filesystem::path& filepath) const; void Clear(); std::list Plugins() const; diff --git a/src/api/plugin.cpp b/src/api/plugin.cpp index 3cfeecf3..98d33bdd 100644 --- a/src/api/plugin.cpp +++ b/src/api/plugin.cpp @@ -24,10 +24,10 @@ #include "api/plugin.h" +#include #include #include -#include #include #include "api/game/game.h" @@ -41,7 +41,7 @@ using std::string; namespace loot { Plugin::Plugin(const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler, const std::string& name, @@ -55,11 +55,11 @@ Plugin::Plugin(const GameType gameType, auto logger = getLogger(); try { - boost::filesystem::path filepath = dataPath / name_; + std::filesystem::path filepath = dataPath / name_; // In case the plugin is ghosted. - if (!boost::filesystem::exists(filepath) && - boost::filesystem::exists(filepath.string() + ".ghost")) + if (!std::filesystem::exists(filepath) && + std::filesystem::exists(filepath.string() + ".ghost")) filepath += ".ghost"; Load(filepath, gameType, headerOnly); @@ -221,7 +221,7 @@ size_t Plugin::NumOverrideFormIDs() const { return numOverrideRecords_; } bool Plugin::IsValid(const std::string& filename, const GameType gameType, - const boost::filesystem::path& dataPath) { + const std::filesystem::path& dataPath) { auto logger = getLogger(); if (logger) { logger->trace("Checking to see if \"{}\" is a valid plugin.", filename); @@ -254,12 +254,12 @@ bool Plugin::IsValid(const std::string& filename, } uintmax_t Plugin::GetFileSize(const std::string& filename, - const boost::filesystem::path& dataPath) { - boost::filesystem::path realPath = dataPath / filename; - if (!boost::filesystem::exists(realPath)) + const std::filesystem::path& dataPath) { + std::filesystem::path realPath = dataPath / filename; + if (!std::filesystem::exists(realPath)) realPath += ".ghost"; - return boost::filesystem::file_size(realPath); + return std::filesystem::file_size(realPath); } bool Plugin::operator<(const Plugin& rhs) const { @@ -269,7 +269,7 @@ bool Plugin::operator<(const Plugin& rhs) const { bool Plugin::IsActive() const { return isActive_; } -void Plugin::Load(const boost::filesystem::path& path, +void Plugin::Load(const std::filesystem::path& path, GameType gameType, bool headerOnly) { ::Plugin* plugin; @@ -317,13 +317,13 @@ std::string GetArchiveFileExtension(const GameType gameType) { bool Plugin::LoadsArchive(const std::string& pluginName, const GameType gameType, const std::shared_ptr gameCache, - const boost::filesystem::path& dataPath) { + const std::filesystem::path& dataPath) { // Get whether the plugin loads an archive (BSA/BA2) or not. const string archiveExtension = GetArchiveFileExtension(gameType); if (gameType == GameType::tes5) { // Skyrim plugins only load BSAs that exactly match their basename. - return boost::filesystem::exists( + return std::filesystem::exists( dataPath / (pluginName.substr(0, pluginName.length() - 4) + archiveExtension)); } else if (gameType != GameType::tes4 || diff --git a/src/api/plugin.h b/src/api/plugin.h index 1d0c44e4..cd9d118f 100644 --- a/src/api/plugin.h +++ b/src/api/plugin.h @@ -44,7 +44,7 @@ class GameCache; class Plugin : public PluginInterface { public: Plugin(const GameType gameType, - const boost::filesystem::path& dataPath, + const std::filesystem::path& dataPath, std::shared_ptr gameCache, std::shared_ptr loadOrderHandler, const std::string& name, @@ -71,14 +71,14 @@ public: // Validity checks. static bool IsValid(const std::string& filename, const GameType gameType, - const boost::filesystem::path& dataPath); + const std::filesystem::path& dataPath); static uintmax_t GetFileSize(const std::string& filename, - const boost::filesystem::path& dataPath); + const std::filesystem::path& dataPath); bool operator<(const Plugin& rhs) const; private: - void Load(const boost::filesystem::path& path, + void Load(const std::filesystem::path& path, GameType gameType, bool headerOnly); std::string GetDescription() const; @@ -86,7 +86,7 @@ private: static bool LoadsArchive(const std::string& pluginName, const GameType gameType, const std::shared_ptr gameCache, - const boost::filesystem::path& dataPath); + const std::filesystem::path& dataPath); static unsigned int GetEspluginGameId(GameType gameType); bool isEmpty_; // Does the plugin contain any records other than the TES4 diff --git a/src/tests/api/interface/api_game_operations_test.h b/src/tests/api/interface/api_game_operations_test.h index ca5b8486..e4a28101 100644 --- a/src/tests/api/interface/api_game_operations_test.h +++ b/src/tests/api/interface/api_game_operations_test.h @@ -27,6 +27,8 @@ along with LOOT. If not, see #include "loot/api.h" +#include + #include "tests/common_game_test_fixture.h" namespace loot { @@ -48,7 +50,7 @@ protected: virtual void SetUp() { CommonGameTestFixture::SetUp(); - ASSERT_FALSE(boost::filesystem::exists(masterlistPath)); + ASSERT_FALSE(std::filesystem::exists(masterlistPath)); handle_ = CreateGameHandle( GetParam(), dataPath.parent_path().string(), localPath.string()); @@ -57,7 +59,7 @@ protected: void GenerateMasterlist() { using std::endl; - boost::filesystem::ofstream masterlist(masterlistPath); + std::ofstream masterlist(masterlistPath); masterlist << "bash_tags:" << endl << " - Actors.ACBS" << endl << " - C.Climate" << endl @@ -117,7 +119,7 @@ protected: std::shared_ptr handle_; - const boost::filesystem::path masterlistPath; + const std::filesystem::path masterlistPath; const std::string noteMessage; const std::string warningMessage; diff --git a/src/tests/api/interface/create_game_handle_test.h b/src/tests/api/interface/create_game_handle_test.h index 1d77b435..c54f0ff2 100644 --- a/src/tests/api/interface/create_game_handle_test.h +++ b/src/tests/api/interface/create_game_handle_test.h @@ -43,31 +43,36 @@ protected: localPathJunctionLink(localPath.string() + ".junction") {} void SetUp() { + using std::filesystem::status; + using std::filesystem::file_type; CommonGameTestFixture::SetUp(); - boost::filesystem::create_directory_symlink(dataPath.parent_path(), - gamePathSymlink); - boost::filesystem::create_directory_symlink(localPath, localPathSymlink); + std::filesystem::create_directory_symlink(dataPath.parent_path(), + gamePathSymlink); + ASSERT_EQ(file_type::directory, status(gamePathSymlink).type()); + + std::filesystem::create_directory_symlink(localPath, localPathSymlink); + ASSERT_EQ(file_type::directory, status(localPathSymlink).type()); #ifdef _WIN32 system(("mklink /J \"" + - boost::filesystem::absolute(gamePathJunctionLink).string() + + std::filesystem::absolute(gamePathJunctionLink).string() + "\" \"" + - boost::filesystem::absolute(dataPath).parent_path().string() + "\"") + std::filesystem::absolute(dataPath).parent_path().string() + "\"") .c_str()); system(("mklink /J \"" + - boost::filesystem::absolute(localPathJunctionLink).string() + - "\" \"" + boost::filesystem::absolute(localPath).string() + "\"") + std::filesystem::absolute(localPathJunctionLink).string() + + "\" \"" + std::filesystem::absolute(localPath).string() + "\"") .c_str()); #endif } std::shared_ptr handle_; - const boost::filesystem::path gamePathSymlink; - const boost::filesystem::path localPathSymlink; - const boost::filesystem::path gamePathJunctionLink; - const boost::filesystem::path localPathJunctionLink; + const std::filesystem::path gamePathSymlink; + const std::filesystem::path localPathSymlink; + const std::filesystem::path gamePathJunctionLink; + const std::filesystem::path localPathJunctionLink; }; // Pass an empty first argument, as it's a prefix for the test instantation, @@ -83,7 +88,7 @@ INSTANTIATE_TEST_CASE_P(, TEST_P(CreateGameHandleTest, shouldSucceedIfPassedValidParametersWithRelativePaths) { - using boost::filesystem::relative; + using std::filesystem::relative; EXPECT_NO_THROW(handle_ = CreateGameHandle(GetParam(), relative(dataPath.parent_path()).string(), relative(localPath).string())); diff --git a/src/tests/api/interface/database_interface_test.h b/src/tests/api/interface/database_interface_test.h index 96b82400..4e792eb0 100644 --- a/src/tests/api/interface/database_interface_test.h +++ b/src/tests/api/interface/database_interface_test.h @@ -47,7 +47,7 @@ protected: db_ = handle_->GetDatabase(); - ASSERT_FALSE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_FALSE(std::filesystem::exists(minimalOutputPath_)); } std::string GetExpectedMinimalContent() const { @@ -69,8 +69,8 @@ protected: return expectedContent.str(); } - std::string GetFileContent(const boost::filesystem::path& file) { - boost::filesystem::ifstream stream(file); + std::string GetFileContent(const std::filesystem::path& file) { + std::ifstream stream(file); std::stringstream content; content << stream.rdbuf(); @@ -80,7 +80,7 @@ protected: void GenerateUserlist() { using std::endl; - boost::filesystem::ofstream userlist(userlistPath_); + std::ofstream userlist(userlistPath_); userlist << "bash_tags:" << endl << " - RaceRelations" << endl << " - C.Lighting" << endl @@ -108,8 +108,8 @@ protected: userlist.close(); } - const boost::filesystem::path userlistPath_; - const boost::filesystem::path minimalOutputPath_; + const std::filesystem::path userlistPath_; + const std::filesystem::path minimalOutputPath_; const std::string url_; const std::string branch_; const std::string oldBranch_; @@ -163,7 +163,7 @@ TEST_P( TEST_P(DatabaseInterfaceTest, loadListsShouldSucceedIfTheMasterlistAndUserlistAreBothPresent) { ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_NO_THROW(boost::filesystem::copy(masterlistPath, userlistPath_)); + ASSERT_NO_THROW(std::filesystem::copy(masterlistPath, userlistPath_)); EXPECT_NO_THROW( db_->LoadLists(masterlistPath.string(), userlistPath_.string())); @@ -173,7 +173,7 @@ TEST_P( DatabaseInterfaceTest, writeUserMetadataShouldThrowIfTheFileAlreadyExistsAndTheOverwriteArgumentIsFalse) { ASSERT_NO_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); EXPECT_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), false), FileAccessError); @@ -183,14 +183,14 @@ TEST_P( DatabaseInterfaceTest, writeUserMetadataShouldReturnOkAndWriteToFileIfTheArgumentsAreValidAndTheOverwriteArgumentIsTrue) { EXPECT_NO_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), true)); - EXPECT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + EXPECT_TRUE(std::filesystem::exists(minimalOutputPath_)); } TEST_P( DatabaseInterfaceTest, writeUserMetadataShouldReturnOkIfTheFileAlreadyExistsAndTheOverwriteArgumentIsTrue) { ASSERT_NO_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); EXPECT_NO_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), true)); } @@ -198,11 +198,11 @@ TEST_P( TEST_P(DatabaseInterfaceTest, writeUserMetadataShouldThrowIfPathGivenExistsAndIsReadOnly) { ASSERT_NO_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); - boost::filesystem::permissions(minimalOutputPath_, - boost::filesystem::perms::remove_perms | - boost::filesystem::perms::owner_write); + std::filesystem::permissions(minimalOutputPath_, + std::filesystem::perms::owner_read, + std::filesystem::perm_options::replace); EXPECT_THROW(db_->WriteUserMetadata(minimalOutputPath_.string(), true), FileAccessError); @@ -220,9 +220,9 @@ TEST_P(DatabaseInterfaceTest, TEST_P(DatabaseInterfaceTest, writeUserMetadataShouldShouldWriteUserMetadata) { ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_NO_THROW(boost::filesystem::copy(masterlistPath, userlistPath_)); + ASSERT_NO_THROW(std::filesystem::copy(masterlistPath, userlistPath_)); - boost::filesystem::ofstream masterlist(masterlistPath); + std::ofstream masterlist(masterlistPath); masterlist << "bash_tags:\n []\nglobals:\n []\nplugins:\n []"; masterlist.close(); @@ -237,7 +237,7 @@ TEST_P(DatabaseInterfaceTest, writeUserMetadataShouldShouldWriteUserMetadata) { TEST_P(DatabaseInterfaceTest, updateMasterlistShouldThrowIfTheMasterlistPathGivenIsInvalid) { EXPECT_THROW(db_->UpdateMasterlist(";//\?", url_, branch_), - std::invalid_argument); + std::exception); } TEST_P(DatabaseInterfaceTest, @@ -280,7 +280,7 @@ TEST_P( EXPECT_NO_THROW( updated = db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); EXPECT_TRUE(updated); - EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); + EXPECT_TRUE(std::filesystem::exists(masterlistPath)); } TEST_P( @@ -294,7 +294,7 @@ TEST_P( EXPECT_NO_THROW( updated = db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); EXPECT_FALSE(updated); - EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); + EXPECT_TRUE(std::filesystem::exists(masterlistPath)); } TEST_P(DatabaseInterfaceTest, @@ -794,14 +794,14 @@ TEST_P( TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnOkAndWriteToFileIfArgumentsGivenAreValid) { EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); - EXPECT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + EXPECT_TRUE(std::filesystem::exists(minimalOutputPath_)); } TEST_P( DatabaseInterfaceTest, writeMinimalListShouldThrowIfTheFileAlreadyExistsAndTheOverwriteArgumentIsFalse) { ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); EXPECT_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false), FileAccessError); @@ -811,14 +811,14 @@ TEST_P( DatabaseInterfaceTest, writeMinimalListShouldReturnOkAndWriteToFileIfTheArgumentsAreValidAndTheOverwriteArgumentIsTrue) { EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); - EXPECT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + EXPECT_TRUE(std::filesystem::exists(minimalOutputPath_)); } TEST_P( DatabaseInterfaceTest, writeMinimalListShouldReturnOkIfTheFileAlreadyExistsAndTheOverwriteArgumentIsTrue) { ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); } @@ -826,11 +826,11 @@ TEST_P( TEST_P(DatabaseInterfaceTest, writeMinimalListShouldThrowIfPathGivenExistsAndIsReadOnly) { ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); - ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + ASSERT_TRUE(std::filesystem::exists(minimalOutputPath_)); - boost::filesystem::permissions(minimalOutputPath_, - boost::filesystem::perms::remove_perms | - boost::filesystem::perms::owner_write); + std::filesystem::permissions(minimalOutputPath_, + std::filesystem::perms::owner_read, + std::filesystem::perm_options::replace); EXPECT_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true), FileAccessError); diff --git a/src/tests/api/interface/game_interface_test.h b/src/tests/api/interface/game_interface_test.h index 5465e940..c1298c9d 100644 --- a/src/tests/api/interface/game_interface_test.h +++ b/src/tests/api/interface/game_interface_test.h @@ -74,9 +74,9 @@ TEST_P(GameInterfaceTest, isValidPluginShouldReturnFalseForANonPluginFile) { TEST_P(GameInterfaceTest, isValidPluginShouldReturnFalseForAnEmptyFile) { // Write out an empty file. - boost::filesystem::ofstream out(dataPath / emptyFile); + std::ofstream out(dataPath / emptyFile); out.close(); - ASSERT_TRUE(boost::filesystem::exists(dataPath / emptyFile)); + ASSERT_TRUE(std::filesystem::exists(dataPath / emptyFile)); EXPECT_FALSE(handle_->IsValidPlugin(emptyFile)); } diff --git a/src/tests/api/interface/main.cpp b/src/tests/api/interface/main.cpp index c88900c8..2f9eb09e 100644 --- a/src/tests/api/interface/main.cpp +++ b/src/tests/api/interface/main.cpp @@ -35,7 +35,6 @@ int main(int argc, char **argv) { // Set the locale to get encoding conversions working correctly. std::locale::global(boost::locale::generator().generate("")); - boost::filesystem::path::imbue(std::locale()); loot::InitialiseLocale(""); ::testing::InitGoogleTest(&argc, argv); diff --git a/src/tests/api/internals/game/game_cache_test.h b/src/tests/api/internals/game/game_cache_test.h index 925f268b..02da6108 100644 --- a/src/tests/api/internals/game/game_cache_test.h +++ b/src/tests/api/internals/game/game_cache_test.h @@ -155,7 +155,7 @@ TEST_P(GameCacheTest, cache_.CacheArchivePath(game_.DataPath() / blankEsm); cache_.CacheArchivePath(game_.DataPath() / blankMasterDependentEsm); - auto expected = std::set({ + auto expected = std::set({ game_.DataPath() / blankEsm, game_.DataPath() / blankMasterDependentEsm, }); diff --git a/src/tests/api/internals/game/game_test.h b/src/tests/api/internals/game/game_test.h index 585f6f62..25e308d6 100644 --- a/src/tests/api/internals/game/game_test.h +++ b/src/tests/api/internals/game/game_test.h @@ -36,7 +36,7 @@ protected: GameTest() : blankArchive("Blank" + GetArchiveFileExtension(GetParam())) { - boost::filesystem::ofstream out(dataPath / blankArchive); + std::ofstream out(dataPath / blankArchive); out.close(); } @@ -125,11 +125,11 @@ TEST_P(GameTest, loadPluginsWithANonPluginShouldNotAddItToTheLoadedPlugins) { TEST_P(GameTest, loadPluginsWithAnInvalidPluginShouldNotAddItToTheLoadedPlugins) { - ASSERT_FALSE(boost::filesystem::exists(dataPath / invalidPlugin)); - ASSERT_NO_THROW(boost::filesystem::copy_file(dataPath / blankEsm, + ASSERT_FALSE(std::filesystem::exists(dataPath / invalidPlugin)); + ASSERT_NO_THROW(std::filesystem::copy_file(dataPath / blankEsm, dataPath / invalidPlugin)); - ASSERT_TRUE(boost::filesystem::exists(dataPath / invalidPlugin)); - boost::filesystem::ofstream out(dataPath / invalidPlugin, std::fstream::app); + ASSERT_TRUE(std::filesystem::exists(dataPath / invalidPlugin)); + std::ofstream out(dataPath / invalidPlugin, std::fstream::app); out << "GRUP0"; out.close(); @@ -162,7 +162,7 @@ TEST_P(GameTest, EXPECT_NO_THROW(loadInstalledPlugins(game, false)); - auto expected = std::set({ + auto expected = std::set({ dataPath / blankArchive }); EXPECT_EQ(expected, game.GetCache()->GetArchivePaths()); diff --git a/src/tests/api/internals/helpers/git_helper_test.h b/src/tests/api/internals/helpers/git_helper_test.h index 36e41ec7..19cd1b38 100644 --- a/src/tests/api/internals/helpers/git_helper_test.h +++ b/src/tests/api/internals/helpers/git_helper_test.h @@ -45,32 +45,32 @@ protected: untrackedFile("untracked.txt") {} inline void SetUp() { - using boost::filesystem::exists; + using std::filesystem::exists; - copy(boost::filesystem::absolute("./testing-metadata"), repoRoot); + copy(std::filesystem::absolute("./testing-metadata"), repoRoot); ASSERT_TRUE(exists(repoRoot)); ASSERT_TRUE(exists(repoSubdirectory)); - ASSERT_TRUE(boost::filesystem::exists(repoRoot / unchangedFile)); + ASSERT_TRUE(std::filesystem::exists(repoRoot / unchangedFile)); // Run git reset --hard to ensure there are no changes in the working copy. // The initial checkout can detect changes due to line ending mismatch. - auto currentPath = boost::filesystem::current_path(); - boost::filesystem::current_path(repoRoot); + auto currentPath = std::filesystem::current_path(); + std::filesystem::current_path(repoRoot); system("git reset --hard"); - boost::filesystem::current_path(currentPath); + std::filesystem::current_path(currentPath); // Edit a tracked file - boost::filesystem::ofstream changedOut(repoRoot / changedFile); + std::ofstream changedOut(repoRoot / changedFile); changedOut.close(); ASSERT_TRUE(exists(repoRoot / changedFile)); // Create a new file in the repository - boost::filesystem::ofstream untrackedOut(repoRoot / untrackedFile); + std::ofstream untrackedOut(repoRoot / untrackedFile); untrackedOut.close(); ASSERT_TRUE(exists(repoRoot / untrackedFile)); // Create a new file outside the repository - boost::filesystem::ofstream outOfRepoOut(rootTestPath / untrackedFile); + std::ofstream outOfRepoOut(rootTestPath / untrackedFile); outOfRepoOut.close(); ASSERT_TRUE(exists(rootTestPath / untrackedFile)); } @@ -78,31 +78,31 @@ protected: inline void TearDown() { // Grant write permissions to everything in rootTestPath // in case the test made anything read only. - for (const auto& path : boost::filesystem::recursive_directory_iterator(rootTestPath)) { - boost::filesystem::permissions(path, boost::filesystem::perms::all_all | boost::filesystem::perms::add_perms); + for (const auto& path : std::filesystem::recursive_directory_iterator(rootTestPath)) { + std::filesystem::permissions(path, std::filesystem::perms::all); } - boost::filesystem::remove_all(rootTestPath); + std::filesystem::remove_all(rootTestPath); } GitHelper git_; - const boost::filesystem::path rootTestPath; - const boost::filesystem::path repoRoot; - const boost::filesystem::path repoSubdirectory; + const std::filesystem::path rootTestPath; + const std::filesystem::path repoRoot; + const std::filesystem::path repoSubdirectory; const std::string changedFile; const std::string unchangedFile; const std::string untrackedFile; private: - void copy(const boost::filesystem::path& from, const boost::filesystem::path& to) { - if (boost::filesystem::is_directory(from)) { - boost::filesystem::create_directories(to); - for (auto entry : boost::filesystem::directory_iterator(from)) { + void copy(const std::filesystem::path& from, const std::filesystem::path& to) { + if (std::filesystem::is_directory(from)) { + std::filesystem::create_directories(to); + for (auto entry : std::filesystem::directory_iterator(from)) { copy(entry.path(), to / entry.path().filename()); } } else { - boost::filesystem::copy(from, to); + std::filesystem::copy(from, to); } } }; diff --git a/src/tests/api/internals/helpers/version_test.h b/src/tests/api/internals/helpers/version_test.h index d7e6b83e..c929ce2f 100644 --- a/src/tests/api/internals/helpers/version_test.h +++ b/src/tests/api/internals/helpers/version_test.h @@ -35,7 +35,7 @@ namespace test { #ifdef _WIN32 TEST(Version, shouldExtractVersionFromApiDll) { // Use the API DLL built. - Version version(boost::filesystem::path("loot_api.dll")); + Version version(std::filesystem::path("loot_api.dll")); std::string expected(LootVersion::string() + ".0"); EXPECT_EQ(expected, version.AsString()); } diff --git a/src/tests/api/internals/main.cpp b/src/tests/api/internals/main.cpp index 64007d34..60ea14cc 100644 --- a/src/tests/api/internals/main.cpp +++ b/src/tests/api/internals/main.cpp @@ -44,9 +44,9 @@ #include "tests/api/internals/metadata/plugin_metadata_test.h" #include "tests/api/internals/metadata/tag_test.h" #include "tests/api/internals/metadata_list_test.h" +#include "tests/api/internals/plugin_test.h" #include "tests/api/internals/sorting/group_sort_test.h" #include "tests/api/internals/sorting/plugin_sorter_test.h" -#include "tests/api/internals/plugin_test.h" TEST(ModuloOperator, shouldConformToTheCpp11Standard) { // C++11 defines the modulo operator more strongly @@ -72,10 +72,88 @@ TEST(YamlCpp, shouldSupportMergeKeys) { EXPECT_EQ(1, node["a"].as()); } +#ifdef _WIN32 +TEST(Filesystem, + pathStringConstructorDoesNotConvertCharacterEncodingFromUtf8ToNative) { + std::string utf8 = u8"Andr\u00E9_settings.toml"; + std::u16string utf16 = u"Andr\u00E9_settings.toml"; + + ASSERT_EQ('\xc3', utf8[4]); + ASSERT_EQ('\xa9', utf8[5]); + + std::filesystem::path path(utf8); + + EXPECT_EQ(utf8, path.string()); + EXPECT_NE(utf8, path.u8string()); + EXPECT_NE(utf16, path.u16string()); +} +#endif + +// This relies on the global locale being set up correctly on Windows (see the +// main method). +TEST(Filesystem, + pathStringAndLocaleConstructorConvertsCharacterEncodingFromUtf8ToNative) { + std::string utf8 = u8"Andr\u00E9_settings.toml"; + std::u16string utf16 = u"Andr\u00E9_settings.toml"; + + ASSERT_EQ('\xc3', utf8[4]); + ASSERT_EQ('\xa9', utf8[5]); + + std::filesystem::path path(utf8, std::locale()); + +#ifdef _WIN32 + EXPECT_NE(utf8, path.string()); +#else + EXPECT_EQ(utf8, path.string()); +#endif + + EXPECT_EQ(utf8, path.u8string()); + EXPECT_EQ(utf16, path.u16string()); +} + +TEST(Filesystem, u8pathConvertsCharacterEncodingFromUtf8ToNative) { + std::string utf8 = u8"Andr\u00E9_settings.toml"; + std::u16string utf16 = u"Andr\u00E9_settings.toml"; + + ASSERT_EQ('\xc3', utf8[4]); + ASSERT_EQ('\xa9', utf8[5]); + + std::filesystem::path path = std::filesystem::u8path(utf8); + +#ifdef _WIN32 + EXPECT_NE(utf8, path.string()); +#else + EXPECT_EQ(utf8, path.string()); +#endif + + EXPECT_EQ(utf8, path.u8string()); + EXPECT_EQ(utf16, path.u16string()); +} + +TEST(Filesystem, shouldBeAbleToWriteToAndReadFromAUtf8Path) { + std::string utf8 = u8"Andr\u00E9_settings.toml"; + auto path = std::filesystem::u8path(utf8); + std::string output = u8"Test cont\u00E9nt"; + + std::ofstream out(path); + out << output; + out.close(); + + EXPECT_TRUE(std::filesystem::exists(path)); + + std::string input; + std::ifstream in(path); + std::getline(in, input); + in.close(); + + EXPECT_EQ(output, input); + + std::filesystem::remove(path); +} + int main(int argc, char **argv) { // Set the locale to get encoding conversions working correctly. std::locale::global(boost::locale::generator().generate("")); - boost::filesystem::path::imbue(std::locale()); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/tests/api/internals/masterlist_test.h b/src/tests/api/internals/masterlist_test.h index bb24ac58..e4e061df 100644 --- a/src/tests/api/internals/masterlist_test.h +++ b/src/tests/api/internals/masterlist_test.h @@ -43,19 +43,19 @@ protected: CommonGameTestFixture::SetUp(); auto sourceDirectory = getSourceMetadataFilesPath(); - boost::filesystem::copy(sourceDirectory / "masterlist.yaml", + std::filesystem::copy(sourceDirectory / "masterlist.yaml", metadataFilesPath / "masterlist.yaml"); - ASSERT_TRUE(boost::filesystem::exists(metadataFilesPath / "masterlist.yaml")); + ASSERT_TRUE(std::filesystem::exists(metadataFilesPath / "masterlist.yaml")); - ASSERT_FALSE(boost::filesystem::exists(masterlistPath)); - ASSERT_FALSE(boost::filesystem::exists(localPath / ".git")); + ASSERT_FALSE(std::filesystem::exists(masterlistPath)); + ASSERT_FALSE(std::filesystem::exists(localPath / ".git")); } const std::string repoUrl; const std::string repoBranch; const std::string oldBranch; - const boost::filesystem::path masterlistPath; + const std::filesystem::path masterlistPath; }; // Pass an empty first argument, as it's a prefix for the test instantation, @@ -73,14 +73,14 @@ TEST_P(MasterlistTest, updateShouldThrowIfAnInvalidPathIsGiven) { Masterlist masterlist; EXPECT_THROW(masterlist.Update(";//\?", repoUrl, repoBranch), - boost::filesystem::filesystem_error); + std::system_error); } TEST_P(MasterlistTest, updateShouldThrowIfABlankPathIsGiven) { Masterlist masterlist; EXPECT_THROW(masterlist.Update("", repoUrl, repoBranch), - boost::filesystem::filesystem_error); + std::invalid_argument); } TEST_P(MasterlistTest, updateShouldThrowIfABranchThatDoesNotExistIsGiven) { @@ -130,11 +130,11 @@ TEST_P(MasterlistTest, Masterlist masterlist; ASSERT_TRUE(masterlist.Update(masterlistPath, repoUrl, repoBranch)); - auto testPath = boost::filesystem::current_path(); - boost::filesystem::current_path(masterlistPath.parent_path()); + auto testPath = std::filesystem::current_path(); + std::filesystem::current_path(masterlistPath.parent_path()); system("git config commit.gpgsign false"); system("git commit --amend -m \"changing local history\""); - boost::filesystem::current_path(testPath); + std::filesystem::current_path(testPath); EXPECT_TRUE(masterlist.Update(masterlistPath, repoUrl, repoBranch)); } @@ -146,7 +146,7 @@ TEST_P(MasterlistTest, getInfoShouldThrowIfNoMasterlistExistsAtTheGivenPath) { TEST_P(MasterlistTest, getInfoShouldThrowIfTheGivenPathDoesNotBelongToAGitRepository) { - ASSERT_NO_THROW(boost::filesystem::copy(metadataFilesPath / "masterlist.yaml", + ASSERT_NO_THROW(std::filesystem::copy(metadataFilesPath / "masterlist.yaml", masterlistPath)); Masterlist masterlist; @@ -183,7 +183,7 @@ TEST_P( getInfoShouldAppendSuffixesToReturnedStringsIfTheMasterlistHasBeenEdited) { Masterlist masterlist; ASSERT_TRUE(masterlist.Update(masterlistPath, repoUrl, repoBranch)); - boost::filesystem::ofstream out(masterlistPath); + std::ofstream out(masterlistPath); out.close(); MasterlistInfo info = masterlist.GetInfo(masterlistPath, false); @@ -194,7 +194,7 @@ TEST_P( TEST_P(MasterlistTest, isLatestShouldThrowIfTheGivenPathDoesNotBelongToAGitRepository) { - ASSERT_NO_THROW(boost::filesystem::copy(metadataFilesPath / "masterlist.yaml", + ASSERT_NO_THROW(std::filesystem::copy(metadataFilesPath / "masterlist.yaml", masterlistPath)); EXPECT_THROW(Masterlist::IsLatest(masterlistPath, repoBranch), GitStateError); diff --git a/src/tests/api/internals/metadata/condition_grammar_test.h b/src/tests/api/internals/metadata/condition_grammar_test.h index 26082435..7509a95c 100644 --- a/src/tests/api/internals/metadata/condition_grammar_test.h +++ b/src/tests/api/internals/metadata/condition_grammar_test.h @@ -54,10 +54,10 @@ protected: // Write out an empty resource file. ASSERT_NO_THROW( - boost::filesystem::create_directories(resourcePath.parent_path())); - boost::filesystem::ofstream out(resourcePath); + std::filesystem::create_directories(resourcePath.parent_path())); + std::ofstream out(resourcePath); out.close(); - ASSERT_TRUE(boost::filesystem::exists(resourcePath)); + ASSERT_TRUE(std::filesystem::exists(resourcePath)); } std::string IntToHexString(const uint32_t value) { @@ -83,7 +83,7 @@ protected: game_.LoadPlugins(plugins, headersOnly); } - const boost::filesystem::path resourcePath; + const std::filesystem::path resourcePath; Game game_; ConditionEvaluator evaluator_; diff --git a/src/tests/api/internals/metadata_list_test.h b/src/tests/api/internals/metadata_list_test.h index 9bf8bc1c..9b712fbf 100644 --- a/src/tests/api/internals/metadata_list_test.h +++ b/src/tests/api/internals/metadata_list_test.h @@ -44,8 +44,8 @@ protected: inline virtual void SetUp() { CommonGameTestFixture::SetUp(); - using boost::filesystem::copy; - using boost::filesystem::exists; + using std::filesystem::copy; + using std::filesystem::exists; auto sourceDirectory = getSourceMetadataFilesPath(); @@ -59,21 +59,21 @@ protected: ASSERT_FALSE(exists(missingMetadataPath)); } - void copyInvalidMetadataFile(const boost::filesystem::path& sourceDirectory, const std::string& file) { - boost::filesystem::create_directories(metadataFilesPath / "invalid"); - boost::filesystem::copy(sourceDirectory / "invalid" / file, metadataFilesPath / "invalid" / file); - ASSERT_TRUE(boost::filesystem::exists(metadataFilesPath / "invalid" / file)); + void copyInvalidMetadataFile(const std::filesystem::path& sourceDirectory, const std::string& file) { + std::filesystem::create_directories(metadataFilesPath / "invalid"); + std::filesystem::copy(sourceDirectory / "invalid" / file, metadataFilesPath / "invalid" / file); + ASSERT_TRUE(std::filesystem::exists(metadataFilesPath / "invalid" / file)); } static std::string PluginMetadataToString(const PluginMetadata& metadata) { return metadata.GetName(); } - const boost::filesystem::path metadataPath; - const boost::filesystem::path savedMetadataPath; - const boost::filesystem::path groupMetadataPath; - const boost::filesystem::path missingMetadataPath; - const std::vector invalidMetadataPaths; + const std::filesystem::path metadataPath; + const std::filesystem::path savedMetadataPath; + const std::filesystem::path groupMetadataPath; + const std::filesystem::path missingMetadataPath; + const std::vector invalidMetadataPaths; }; // Pass an empty first argument, as it's a prefix for the test instantation, @@ -145,7 +145,7 @@ TEST_P(MetadataListTest, loadShouldLoadGroups) { TEST_P(MetadataListTest, loadYamlParsingShouldSupportMergeKeys) { using std::endl; - boost::filesystem::ofstream out(metadataPath); + std::ofstream out(metadataPath); out << "common:" << endl << " - &earlier" << endl << " name: earlier" << endl @@ -212,7 +212,7 @@ TEST_P(MetadataListTest, saveShouldWriteTheLoadedMetadataToTheGivenFilePath) { EXPECT_NO_THROW(metadataList.Save(savedMetadataPath)); - EXPECT_TRUE(boost::filesystem::exists(savedMetadataPath)); + EXPECT_TRUE(std::filesystem::exists(savedMetadataPath)); // Check the new file contains the same metadata. EXPECT_NO_THROW(metadataList.Load(savedMetadataPath)); diff --git a/src/tests/api/internals/plugin_test.h b/src/tests/api/internals/plugin_test.h index 8f379bf4..cc064fa4 100644 --- a/src/tests/api/internals/plugin_test.h +++ b/src/tests/api/internals/plugin_test.h @@ -48,18 +48,18 @@ protected: game_.LoadCurrentLoadOrderState(); // Write out an empty file. - boost::filesystem::ofstream out(dataPath / emptyFile); + std::ofstream out(dataPath / emptyFile); out.close(); - ASSERT_TRUE(boost::filesystem::exists(dataPath / emptyFile)); + ASSERT_TRUE(std::filesystem::exists(dataPath / emptyFile)); #ifndef _WIN32 - ASSERT_NO_THROW(boost::filesystem::copy(dataPath / blankEsp, + ASSERT_NO_THROW(std::filesystem::copy(dataPath / blankEsp, dataPath / lowercaseBlankEsp)); #endif if (GetParam() != GameType::fo4 && GetParam() != GameType::tes5se) { ASSERT_NO_THROW( - boost::filesystem::copy(dataPath / blankEsp, dataPath / blankEsl)); + std::filesystem::copy(dataPath / blankEsp, dataPath / blankEsl)); } // Create dummy archive files. diff --git a/src/tests/api/internals/sorting/plugin_sorter_test.h b/src/tests/api/internals/sorting/plugin_sorter_test.h index 49817cdf..0198c580 100644 --- a/src/tests/api/internals/sorting/plugin_sorter_test.h +++ b/src/tests/api/internals/sorting/plugin_sorter_test.h @@ -59,7 +59,7 @@ protected: if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) { plugins.push_back(blankEsl); - if (boost::filesystem::exists(dataPath / blankEslEsp)) { + if (std::filesystem::exists(dataPath / blankEslEsp)) { plugins.push_back(blankEslEsp); } } @@ -72,7 +72,7 @@ protected: void GenerateMasterlist() { using std::endl; - boost::filesystem::ofstream masterlist(masterlistPath_); + std::ofstream masterlist(masterlistPath_); masterlist << "groups:" << endl << " - name: earliest" << endl << " - name: earlier" << endl @@ -109,7 +109,7 @@ protected: using std::endl; if (GetParam() == GameType::fo4) { - boost::filesystem::ofstream ccc(cccPath_); + std::ofstream ccc(cccPath_); ccc << blankDifferentEsm << endl << blankDifferentMasterDependentEsm << endl; @@ -119,8 +119,8 @@ protected: Game game_; const std::string blankEslEsp; - const boost::filesystem::path masterlistPath_; - const boost::filesystem::path cccPath_; + const std::filesystem::path masterlistPath_; + const std::filesystem::path cccPath_; }; // Pass an empty first argument, as it's a prefix for the test instantation, @@ -140,7 +140,7 @@ TEST_P(PluginSorterTest, lightMasterFlaggedEspFilesShouldNotBeTreatedAsMasters) { if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) { ASSERT_NO_THROW( - boost::filesystem::copy(dataPath / blankEsl, dataPath / blankEslEsp)); + std::filesystem::copy(dataPath / blankEsl, dataPath / blankEslEsp)); } ASSERT_NO_THROW(loadInstalledPlugins(game_, false)); diff --git a/src/tests/common_game_test_fixture.h b/src/tests/common_game_test_fixture.h index cf9fb7d5..4345e1ac 100644 --- a/src/tests/common_game_test_fixture.h +++ b/src/tests/common_game_test_fixture.h @@ -25,13 +25,14 @@ along with LOOT. If not, see #ifndef LOOT_TESTS_COMMON_GAME_TEST_FIXTURE #define LOOT_TESTS_COMMON_GAME_TEST_FIXTURE +#include +#include +#include #include #include #include #include -#include -#include #include #include #include @@ -41,11 +42,11 @@ along with LOOT. If not, see namespace loot { namespace test { -boost::filesystem::path getRootTestPath() { +std::filesystem::path getRootTestPath() { auto directoryName = "LOOT-" + boost::lexical_cast( (boost::uuids::random_generator())()); - return boost::filesystem::absolute(boost::filesystem::temp_directory_path() / + return std::filesystem::absolute(std::filesystem::temp_directory_path() / directoryName); } @@ -82,8 +83,8 @@ protected: } void assertInitialState() { - using boost::filesystem::create_directories; - using boost::filesystem::exists; + using std::filesystem::create_directories; + using std::filesystem::exists; create_directories(dataPath); ASSERT_TRUE(exists(dataPath)); @@ -114,21 +115,21 @@ protected: // Make sure the game master file exists. ASSERT_NO_THROW( - boost::filesystem::copy_file(dataPath / blankEsm, dataPath / masterFile)); + std::filesystem::copy_file(dataPath / blankEsm, dataPath / masterFile)); ASSERT_TRUE(exists(dataPath / masterFile)); // Set initial load order and active plugins. setLoadOrder(getInitialLoadOrder()); // Ghost a plugin. - ASSERT_NO_THROW(boost::filesystem::rename( + ASSERT_NO_THROW(std::filesystem::rename( dataPath / blankMasterDependentEsm, dataPath / (blankMasterDependentEsm + ".ghost"))); ASSERT_FALSE(exists(dataPath / blankMasterDependentEsm)); ASSERT_TRUE(exists(dataPath / (blankMasterDependentEsm + ".ghost"))); // Write out an non-empty, non-plugin file. - boost::filesystem::ofstream out(dataPath / nonPluginFile); + std::ofstream out(dataPath / nonPluginFile); out << "This isn't a valid plugin file."; out.close(); ASSERT_TRUE(exists(dataPath / nonPluginFile)); @@ -137,22 +138,22 @@ protected: ASSERT_FALSE(exists(dataPath / missingEsp)); } - void copyPlugin(const boost::filesystem::path& sourceParentPath, const std::string& filename) { - boost::filesystem::copy_file(sourceParentPath / filename, dataPath / filename); - ASSERT_TRUE(boost::filesystem::exists(dataPath / filename)); + void copyPlugin(const std::filesystem::path& sourceParentPath, const std::string& filename) { + std::filesystem::copy_file(sourceParentPath / filename, dataPath / filename); + ASSERT_TRUE(std::filesystem::exists(dataPath / filename)); } void TearDown() { // Grant write permissions to everything in rootTestPath // in case the test made anything read only. - for (const auto& path : boost::filesystem::recursive_directory_iterator(rootTestPath)) { - boost::filesystem::permissions(path, boost::filesystem::perms::all_all | boost::filesystem::perms::add_perms); + for (const auto& path : std::filesystem::recursive_directory_iterator(rootTestPath)) { + std::filesystem::permissions(path, std::filesystem::perms::all); } - boost::filesystem::remove_all(rootTestPath); + std::filesystem::remove_all(rootTestPath); } - std::vector readFileLines(const boost::filesystem::path& file) { - boost::filesystem::ifstream in(file); + std::vector readFileLines(const std::filesystem::path& file) { + std::ifstream in(file); std::vector lines; while (in) { @@ -170,11 +171,11 @@ protected: std::vector getLoadOrder() { std::vector actual; if (isLoadOrderTimestampBased(GetParam())) { - std::map loadOrder; - for (boost::filesystem::directory_iterator it(dataPath); - it != boost::filesystem::directory_iterator(); + std::map loadOrder; + for (std::filesystem::directory_iterator it(dataPath); + it != std::filesystem::directory_iterator(); ++it) { - if (boost::filesystem::is_regular_file(it->status())) { + if (std::filesystem::is_regular_file(it->status())) { std::string filename = it->path().filename().string(); if (filename == nonPluginFile) continue; @@ -182,13 +183,13 @@ protected: filename = it->path().stem().string(); if (boost::ends_with(filename, ".esp") || boost::ends_with(filename, ".esm")) - loadOrder.emplace(boost::filesystem::last_write_time(it->path()), + loadOrder.emplace(std::filesystem::last_write_time(it->path()), filename); } } for (const auto& plugin : loadOrder) actual.push_back(plugin.second); } else if (GetParam() == GameType::tes5) { - boost::filesystem::ifstream in(localPath / "loadorder.txt"); + std::ifstream in(localPath / "loadorder.txt"); while (in) { std::string line; std::getline(in, line); @@ -230,16 +231,16 @@ protected: } private: - const boost::filesystem::path rootTestPath; + const std::filesystem::path rootTestPath; protected: const std::string french; const std::string german; - const boost::filesystem::path missingPath; - const boost::filesystem::path dataPath; - const boost::filesystem::path localPath; - const boost::filesystem::path metadataFilesPath; + const std::filesystem::path missingPath; + const std::filesystem::path dataPath; + const std::filesystem::path localPath; + const std::filesystem::path metadataFilesPath; const std::string masterFile; const std::string missingEsp; @@ -259,19 +260,19 @@ protected: const uint32_t blankEsmCrc; - static boost::filesystem::path getSourceMetadataFilesPath() { - return boost::filesystem::absolute("./testing-metadata"); + static std::filesystem::path getSourceMetadataFilesPath() { + return std::filesystem::absolute("./testing-metadata"); } private: - boost::filesystem::path getSourcePluginsPath() const { - using boost::filesystem::absolute; + std::filesystem::path getSourcePluginsPath() const { + using std::filesystem::absolute; if (GetParam() == GameType::tes4) - return "./Oblivion/Data"; + return absolute("./Oblivion/Data"); else if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) - return "./SkyrimSE/Data"; + return absolute("./SkyrimSE/Data"); else - return "./Skyrim/Data"; + return absolute("./Skyrim/Data"); } inline std::string getMasterFile() const { @@ -296,7 +297,7 @@ private: void setLoadOrder( const std::vector>& loadOrder) const { - boost::filesystem::ofstream out(localPath / "plugins.txt"); + std::ofstream out(localPath / "plugins.txt"); for (const auto& plugin : loadOrder) { if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) { if (plugin.second) @@ -308,21 +309,22 @@ private: } if (isLoadOrderTimestampBased(GetParam())) { - time_t modificationTime = time(NULL); // Current time. + std::filesystem::file_time_type modificationTime = + std::filesystem::file_time_type::clock::now(); for (const auto& plugin : loadOrder) { - if (boost::filesystem::exists( - dataPath / boost::filesystem::path(plugin.first + ".ghost"))) { - boost::filesystem::last_write_time( - dataPath / boost::filesystem::path(plugin.first + ".ghost"), + if (std::filesystem::exists( + dataPath / std::filesystem::path(plugin.first + ".ghost"))) { + std::filesystem::last_write_time( + dataPath / std::filesystem::path(plugin.first + ".ghost"), modificationTime); } else { - boost::filesystem::last_write_time(dataPath / plugin.first, + std::filesystem::last_write_time(dataPath / plugin.first, modificationTime); } - modificationTime += 60; + modificationTime += std::chrono::seconds(60); } } else if (GetParam() == GameType::tes5) { - boost::filesystem::ofstream out(localPath / "loadorder.txt"); + std::ofstream out(localPath / "loadorder.txt"); for (const auto& plugin : loadOrder) out << plugin.first << std::endl; } }