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; } }