Remove all Git-related functionality

LOOT no longer uses Git to keep its copies of the masterlists up to
date, so this functionality is no longer needed. The removed API items
are:

- UpdateFile()
- GetFileRevision()
- IsLatestFile()
- libgit2_category()
- GitStateError
This commit is contained in:
Oliver Hamlet
2022-01-23 20:41:54 +00:00
parent fa3c4d5fef
commit 95980860e5
20 changed files with 10 additions and 2576 deletions
-4
View File
@@ -118,8 +118,6 @@ jobs:
- name: Run tests
run: |
cd build
git config --global user.email "github@github-actions"
git config --global user.name "GitHub"
./libloot_internals_tests
./libloot_tests
@@ -200,8 +198,6 @@ jobs:
- name: Run tests
run: |
cd build/${{ env.MSVC_CONFIG }}
git config --global user.email "github@github-actions"
git config --global user.name "GitHub"
.\libloot_internals_tests.exe
.\libloot_tests.exe
-2
View File
@@ -94,8 +94,6 @@ jobs:
- name: Run tests
run: |
cd build
git config --global user.email "github@github-actions"
git config --global user.name "GitHub"
./libloot_internals_tests
./libloot_tests
+6 -27
View File
@@ -81,22 +81,6 @@ ELSE ()
set (ESPLUGIN_LIBRARIES ${ESPLUGIN_LIBRARIES} dl)
ENDIF ()
IF (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(LIBGIT2_BUILD_COMMAND ${CMAKE_COMMAND} --build . --target git2 --config $(CONFIGURATION))
ELSE ()
set(LIBGIT2_BUILD_COMMAND ${CMAKE_COMMAND} --build . --target git2)
ENDIF()
ExternalProject_Add(libgit2
PREFIX "external"
URL "https://github.com/libgit2/libgit2/archive/v1.3.0.tar.gz"
CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_CLAR=OFF -DUSE_SSH=OFF -DSTATIC_CRT=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=${CMAKE_POSITION_INDEPENDENT_CODE} -DREGEX_BACKEND=builtin
BUILD_COMMAND ${LIBGIT2_BUILD_COMMAND}
INSTALL_COMMAND "")
ExternalProject_Get_Property(libgit2 SOURCE_DIR BINARY_DIR)
set(LIBGIT2_INCLUDE_DIRS "${SOURCE_DIR}/include")
set(LIBGIT2_LIBRARIES "${BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}git2${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Add(libloadorder
PREFIX "external"
URL "https://github.com/Ortham/libloadorder/archive/13.0.0.tar.gz"
@@ -206,7 +190,6 @@ set (LIBLOOT_SRC "${CMAKE_BINARY_DIR}/generated/loot_version.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_graph.cpp"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sorting_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/crc.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/git.cpp"
"${CMAKE_SOURCE_DIR}/src/api/helpers/text.cpp"
"${CMAKE_SOURCE_DIR}/src/api/vertex.cpp"
"${CMAKE_SOURCE_DIR}/src/api/resource.rc")
@@ -218,7 +201,6 @@ set (LIBLOOT_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/condition_syntax_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/file_access_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/git_state_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/undefined_group_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/edge_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h"
@@ -260,7 +242,6 @@ set (LIBLOOT_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sort.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_graph.h"
"${CMAKE_SOURCE_DIR}/src/api/sorting/plugin_sorting_data.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/git.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/collections.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/crc.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/logging.h"
@@ -271,7 +252,6 @@ set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/tests/api/internals/main.cpp")
set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_cache_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/load_order_handler_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/git_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/crc_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/text_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/helpers/yaml_set_helpers_test.h"
@@ -299,7 +279,6 @@ set(LIBLOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/tests/api/interface/main.cpp")
set(LIBLOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/api/interface/api_game_operations_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/create_game_handle_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/database_interface_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/file_versioning_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/game_interface_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/is_compatible_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/common_game_test_fixture.h")
@@ -316,7 +295,6 @@ source_group("Source Files\\tests" FILES ${LIBLOOT_TESTS_SRC})
include_directories ("${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include"
${LIBLOADORDER_INCLUDE_DIRS}
${LIBGIT2_INCLUDE_DIRS}
${ESPLUGIN_INCLUDE_DIRS}
${LCI_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
@@ -366,7 +344,8 @@ IF (MSVC)
shlwapi
winhttp
crypt32
Rpcrt4)
Rpcrt4
bcrypt)
ENDIF ()
@@ -376,13 +355,13 @@ ENDIF ()
# Build tests.
add_executable (libloot_internals_tests ${LIBLOOT_SRC} ${LIBLOOT_HEADERS} ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS})
add_dependencies (libloot_internals_tests esplugin libgit2 libloadorder loot-condition-interpreter spdlog yaml-cpp GTest testing-metadata testing-plugins)
target_link_libraries(libloot_internals_tests ${LIBGIT2_LIBRARIES} ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${LCI_LIBRARIES} ${YAML_CPP_LIBRARIES} ${GTEST_LIBRARIES} ${ICU_LIBRARIES})
add_dependencies (libloot_internals_tests esplugin libloadorder loot-condition-interpreter spdlog yaml-cpp GTest testing-metadata testing-plugins)
target_link_libraries(libloot_internals_tests ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${LCI_LIBRARIES} ${YAML_CPP_LIBRARIES} ${GTEST_LIBRARIES} ${ICU_LIBRARIES})
# Build API.
add_library (loot ${LIBLOOT_SRC} ${LIBLOOT_HEADERS})
add_dependencies (loot esplugin libgit2 libloadorder loot-condition-interpreter spdlog yaml-cpp)
target_link_libraries(loot ${LIBGIT2_LIBRARIES} ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${LCI_LIBRARIES} ${YAML_CPP_LIBRARIES} ${ICU_LIBRARIES})
add_dependencies (loot esplugin libloadorder loot-condition-interpreter spdlog yaml-cpp)
target_link_libraries(loot ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${LCI_LIBRARIES} ${YAML_CPP_LIBRARIES} ${ICU_LIBRARIES})
# Build API tests.
add_executable (libloot_tests ${LIBLOOT_TESTS_SRC} ${LIBLOOT_TESTS_HEADERS})
+1 -2
View File
@@ -3,14 +3,13 @@ Credits
*******
libloot is written by `Ortham`_ in C++ and makes use of the `Boost`_,
`esplugin`_, `libgit2`_, `libloadorder`_, `loot-condition-interpreter`_,
`esplugin`_, `libloadorder`_, `loot-condition-interpreter`_,
`spdlog`_ and `yaml-cpp`_ libraries. The copyright licenses for all of these and
libloot itself in :doc:`../licenses/texts`.
.. _Ortham: https://github.com/Ortham
.. _Boost: http://www.boost.org/
.. _esplugin: https://github.com/Ortham/esplugin
.. _libgit2: https://github.com/libgit2/libgit2
.. _libloadorder: https://github.com/Ortham/libloadorder
.. _loot-condition-interpreter: https://github.com/loot/loot-condition-interpreter
.. _spdlog: https://github.com/gabime/spdlog
-3
View File
@@ -78,9 +78,6 @@ data from the filesystem:
Evaluating conditions may also involve filesystem read access.
:cpp:any:`UpdateFile()` may involve network communication if given the URL of a
remote server.
:cpp:any:`GameInterface::SortPlugins()` is expensive, as it involves loading
all the content of all the plugins, apart from the game's main master file, which is skipped as an optimisation (it doesn't depend on anything else and is much bigger than any other plugin, so is unnecessary and slow to load).
-11
View File
@@ -33,12 +33,6 @@ Functions
.. doxygenfunction:: loot::CreateGameHandle
.. doxygenfunction:: loot::UpdateFile
.. doxygenfunction:: loot::GetFileRevision
.. doxygenfunction:: loot::IsLatestFile
Interfaces
==========
@@ -96,9 +90,6 @@ Exceptions
.. doxygenclass:: loot::CyclicInteractionError
:members:
.. doxygenclass:: loot::GitStateError
:members:
.. doxygenclass:: loot::ConditionSyntaxError
:members:
@@ -115,5 +106,3 @@ LOOT uses error category objects to identify errors with codes that originate in
lower-level libraries.
.. doxygenfunction:: loot::libloadorder_category
.. doxygenfunction:: loot::libgit2_category
File diff suppressed because it is too large Load Diff
-8
View File
@@ -12,14 +12,6 @@ Copyright License Texts
.. include:: Boost Software License v1.0.txt
:literal:
`libgit2`_
==========
.. _libgit2: https://github.com/libgit2/libgit2
.. include:: GNU GPL v2 (libgit2).txt
:literal:
libloot, `esplugin`_ & `Libloadorder`_
======================================
-69
View File
@@ -37,7 +37,6 @@
#include "loot/exception/cyclic_interaction_error.h"
#include "loot/exception/error_categories.h"
#include "loot/exception/file_access_error.h"
#include "loot/exception/git_state_error.h"
#include "loot/exception/undefined_group_error.h"
#include "loot/game_interface.h"
#include "loot/loot_version.h"
@@ -110,74 +109,6 @@ LOOT_API std::shared_ptr<GameInterface> CreateGameHandle(
const GameType game,
const std::filesystem::path& game_path,
const std::filesystem::path& game_local_path = "");
/**@}*/
/**********************************************************************/ /**
* @name File Versioning Functions
*************************************************************************/
/**@{*/
/**
* @brief Update the given masterlist or masterlist prelude file.
* @details Uses Git to update the given file using a given remote.
* If the file doesn't exist, this will create it. This
* function also initialises a Git repository in the given
* file's parent folder.
*
* If a Git repository is already present, it will be used to
* perform a diff-only update, but if for any reason a
* fast-forward merge update is not possible, the existing
* repository will be deleted and a new repository cloned from
* the given remote.
* @param file_path
* The relative or absolute path to the file that should be
* updated. The filename must match the filename of the file in the
* given remote repository, otherwise it will not be updated
* correctly. The file must be present in the repository's root
* directory.
* @param remote_url
* The URL of the remote from which to fetch updates. This can also be
* a relative or absolute path to a local repository.
* @param remote_branch
* The branch of the remote from which to apply updates.
* @returns `true` if the file was updated. `false` if no update was
* necessary, ie. it was already up-to-date.
*/
LOOT_API bool UpdateFile(const std::filesystem::path& file_path,
const std::string& remote_url,
const std::string& remote_branch);
/**
* @brief Get the given masterlist or masterlist prelude file's revision.
* @details Getting a file's revision is only possible if it is found
* in the root of a local Git repository.
* @param file_path
* The relative or absolute path to the file that should be queried.
* @param get_short_id
* If `true`, the shortest unique hexadecimal revision hash that is at
* least 7 characters long will be outputted. Otherwise, the full 40
* character hash will be outputted.
* @returns The revision data.
*/
LOOT_API FileRevision GetFileRevision(const std::filesystem::path& file_path,
const bool get_short_id);
/**
* Check if the given masterlist or masterlist prelude file is the latest
* available for a given branch.
* @param file_path
* The relative or absolute path to the file for which the latest
* revision should be obtained. It needs to be in the root of a local
* Git repository.
* @param branch
* The branch to check against.
* @return True if the file's current revision matches its latest revision
* for the given branch, and false otherwise.
*/
LOOT_API bool IsLatestFile(const std::filesystem::path& file_path,
const std::string& branch);
}
#endif
@@ -36,13 +36,6 @@ namespace loot {
derived from std::error_category.
*/
LOOT_API const std::error_category& libloadorder_category();
/** @brief Get the error category that can be used to identify system_error
* exceptions that are due to libgit2 errors.
* @returns A reference to the static object of unspecified runtime type,
derived from std::error_category.
*/
LOOT_API const std::error_category& libgit2_category();
}
#endif
-41
View File
@@ -1,41 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_EXCEPTION_GIT_STATE_ERROR
#define LOOT_EXCEPTION_GIT_STATE_ERROR
#include <stdexcept>
namespace loot {
/**
* @brief An exception class thrown if an error occurs when performing
* an operation on a Git repository due to invalid state.
*/
class GitStateError : public std::logic_error {
public:
using std::logic_error::logic_error;
};
}
#endif
-23
View File
@@ -28,7 +28,6 @@
#include "api/game/game.h"
#include "api/helpers/logging.h"
#include "api/helpers/git.h"
namespace fs = std::filesystem;
@@ -98,26 +97,4 @@ LOOT_API std::shared_ptr<GameInterface> CreateGameHandle(
return std::make_shared<Game>(game, resolvedGamePath, resolvedGameLocalPath);
}
bool UpdateFile(const std::filesystem::path& masterlistPath,
const std::string& remoteURL,
const std::string& remoteBranch) {
if (!std::filesystem::is_directory(masterlistPath.parent_path()))
throw std::invalid_argument("The path \"" + masterlistPath.u8string() +
"\" does not have a valid parent directory.");
return git::UpdateFile(masterlistPath, remoteURL, remoteBranch);
}
FileRevision GetFileRevision(
const std::filesystem::path& masterlistPath,
const bool getShortID) {
return git::GetVersionInfo(masterlistPath, getShortID);
}
bool IsLatestFile(
const std::filesystem::path& masterlist_path,
const std::string& branch) {
return git::IsLatest(masterlist_path, branch);
}
}
-16
View File
@@ -38,26 +38,10 @@ class libloadorder_category : public std::error_category {
return code.category().name() == name();
}
};
class libgit2_category : public std::error_category {
virtual const char* name() const noexcept { return "libgit2"; }
virtual std::string message(int ev) const { return "libgit2 error"; }
virtual bool equivalent(const std::error_code& code, int condition) const
noexcept {
return code.category().name() == name();
}
};
}
LOOT_API const std::error_category& libloadorder_category() {
static detail::libloadorder_category instance;
return instance;
}
LOOT_API const std::error_category& libgit2_category() {
static detail::libgit2_category instance;
return instance;
}
}
File diff suppressed because it is too large Load Diff
-118
View File
@@ -1,118 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_API_HELPERS_GIT
#define LOOT_API_HELPERS_GIT
#include <git2.h>
#include <spdlog/spdlog.h>
#include <filesystem>
#include <string>
#include "loot/struct/file_revision.h"
namespace loot {
namespace git {
// The given path must be to a file in the root of a Git repository.
bool UpdateFile(const std::filesystem::path& path,
const std::string& repoURL,
const std::string& repoBranch);
// The given path must be to a file in the root of a Git repository.
FileRevision GetVersionInfo(const std::filesystem::path& path, bool shortID);
// The given path must be to a file in the root of a Git repository.
bool IsLatest(const std::filesystem::path& path, const std::string& repoBranch);
}
class GitHelper {
public:
void InitialiseOptions(const std::string& branch,
const std::string& filenameToCheckout);
void Open(const std::filesystem::path& repoRoot);
void SetRemoteUrl(const std::string& remote, const std::string& url);
static bool IsRepository(const std::filesystem::path& path);
static bool IsFileDifferent(const std::filesystem::path& repoRoot,
const std::string& filename);
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);
// Deletes the branch, detaching HEAD if it's currently set to the branch.
void DeleteBranch(const std::string& branch);
bool BranchExists(const std::string& branch);
bool IsBranchUpToDate(const std::string& branch);
bool IsBranchCheckedOut(const std::string& branch);
std::string GetHeadCommitId(bool shortId);
std::string GetHeadCommitDate();
private:
struct DiffPayload {
bool fileFound;
const char* fileToFind;
};
struct GitData {
GitData();
~GitData();
git_repository* repo;
git_remote* remote;
git_config* config;
git_object* object;
git_commit* commit;
git_reference* reference;
git_reference* reference2;
git_blob* blob;
git_annotated_commit* annotated_commit;
git_tree* tree;
git_diff* diff;
git_buf buffer;
git_checkout_options checkout_options;
git_clone_options clone_options;
};
static int DiffFileCallback(const git_diff_delta* delta,
float progress,
void* payload);
// Removes the read-only flag from some files in git repositories
// created by libgit2.
void GrantWritePermissions(const std::filesystem::path& path);
void Call(int error_code);
const git_oid* GetCommitId(git_reference* reference);
GitData data_;
};
}
#endif
+3 -3
View File
@@ -23,9 +23,8 @@
*/
#include "api/helpers/text.h"
#include <regex>
#include <boost/algorithm/string.hpp>
#include <regex>
#ifdef _WIN32
#include "windows.h"
@@ -72,7 +71,8 @@ const std::vector<regex> versionRegexes({
});
// As defined by <https://github.github.com/gfm/#ascii-punctuation-character>.
const regex asciiPunctuationCharacters("([!\"#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~])");
const regex asciiPunctuationCharacters(
"([!\"#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~])");
std::string EscapeMarkdownASCIIPunctuation(const std::string& text) {
return std::regex_replace(text, asciiPunctuationCharacters, "\\$1");
@@ -1,196 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TESTS_API_INTERFACE_FILE_VERSIONING_TEST
#define LOOT_TESTS_API_INTERFACE_FILE_VERSIONING_TEST
#include "loot/api.h"
#include "tests/api/interface/api_game_operations_test.h"
namespace loot {
namespace test {
class FileVersioningTest : public ApiGameOperationsTest {
protected:
FileVersioningTest() :
url_("./testing-metadata.git"),
branch_("master"),
oldBranch_("old-branch") {}
const std::string url_;
const std::string branch_;
const std::string oldBranch_;
};
// Pass an empty first argument, as it's a prefix for the test instantation,
// but we only have the one so no prefix is necessary.
INSTANTIATE_TEST_SUITE_P(,
FileVersioningTest,
::testing::Values(GameType::tes4,
GameType::tes5,
GameType::fo3,
GameType::fonv,
GameType::fo4,
GameType::tes5se));
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheMasterlistPathGivenIsInvalid) {
EXPECT_THROW(UpdateFile("//\?", url_, branch_), std::exception);
}
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheMasterlistPathGivenIsEmpty) {
EXPECT_THROW(UpdateFile("", url_, branch_), std::invalid_argument);
}
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheRepositoryUrlGivenCannotBeFound) {
EXPECT_THROW(UpdateFile(
masterlistPath,
"https://github.com/loot/oblivion-does-not-exist.git",
branch_),
std::system_error);
}
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheRepositoryUrlGivenIsEmpty) {
EXPECT_THROW(UpdateFile(masterlistPath, "", branch_),
std::invalid_argument);
}
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheRepositoryBranchGivenCannotBeFound) {
EXPECT_THROW(UpdateFile(masterlistPath, url_, "missing-branch"),
std::system_error);
}
TEST_P(FileVersioningTest,
updateFileShouldThrowIfTheRepositoryBranchGivenIsEmpty) {
EXPECT_THROW(UpdateFile(masterlistPath, url_, ""),
std::invalid_argument);
}
TEST_P(
FileVersioningTest,
updateFileShouldSucceedIfPassedValidParametersAndOutputTrueIfTheMasterlistWasUpdated) {
bool updated = false;
EXPECT_NO_THROW(updated =
UpdateFile(masterlistPath, url_, branch_));
EXPECT_TRUE(updated);
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_P(
FileVersioningTest,
updateFileShouldSucceedIfCalledRepeatedlyButOnlyOutputTrueForTheFirstCall) {
bool updated = false;
EXPECT_NO_THROW(updated =
UpdateFile(masterlistPath, url_, branch_));
EXPECT_TRUE(updated);
EXPECT_NO_THROW(updated =
UpdateFile(masterlistPath, url_, branch_));
EXPECT_FALSE(updated);
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_P(FileVersioningTest,
getFileRevisionShouldThrowIfNoMasterlistIsPresent) {
FileRevision revision;
EXPECT_THROW(revision = GetFileRevision(masterlistPath, false),
FileAccessError);
EXPECT_TRUE(revision.id.empty());
EXPECT_TRUE(revision.date.empty());
EXPECT_FALSE(revision.is_modified);
}
TEST_P(
FileVersioningTest,
getFileRevisionShouldThrowIfANonVersionControlledMasterlistIsPresent) {
ASSERT_NO_THROW(GenerateMasterlist());
FileRevision revision;
EXPECT_THROW(revision = GetFileRevision(masterlistPath, false),
GitStateError);
EXPECT_TRUE(revision.id.empty());
EXPECT_TRUE(revision.date.empty());
EXPECT_FALSE(revision.is_modified);
}
TEST_P(
FileVersioningTest,
getFileRevisionShouldOutputLongStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsFalse) {
ASSERT_NO_THROW(UpdateFile(masterlistPath, url_, branch_));
FileRevision revision;
EXPECT_NO_THROW(revision = GetFileRevision(masterlistPath, false));
EXPECT_EQ(40, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_FALSE(revision.is_modified);
}
TEST_P(
FileVersioningTest,
getFileRevisionShouldOutputShortStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsTrue) {
ASSERT_NO_THROW(UpdateFile(masterlistPath, url_, branch_));
FileRevision revision;
EXPECT_NO_THROW(revision = GetFileRevision(masterlistPath, false));
EXPECT_GE(size_t(40), revision.id.length());
EXPECT_LE(size_t(7), revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_FALSE(revision.is_modified);
}
TEST_P(
FileVersioningTest,
getFileRevisionShouldSucceedIfAnEditedVersionControlledMasterlistIsPresent) {
ASSERT_NO_THROW(UpdateFile(masterlistPath, url_, branch_));
ASSERT_NO_THROW(GenerateMasterlist());
FileRevision revision;
EXPECT_NO_THROW(revision = GetFileRevision(masterlistPath, false));
EXPECT_EQ(40, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_TRUE(revision.is_modified);
}
TEST_P(
FileVersioningTest,
isLatestFileShouldReturnFalseIfTheCurrentRevisionIsNotTheLatestRevisionInTheGivenBranch) {
ASSERT_NO_THROW(UpdateFile(masterlistPath, url_, oldBranch_));
EXPECT_FALSE(IsLatestFile(masterlistPath, branch_));
}
TEST_P(
FileVersioningTest,
isLatestFileShouldReturnTrueIfTheCurrentRevisionIsTheLatestRevisioninTheGivenBranch) {
ASSERT_NO_THROW(UpdateFile(masterlistPath, url_, branch_));
EXPECT_TRUE(IsLatestFile(masterlistPath, branch_));
}
}
}
#endif
-1
View File
@@ -27,7 +27,6 @@
#include "loot/api.h"
#include "tests/api/interface/create_game_handle_test.h"
#include "tests/api/interface/database_interface_test.h"
#include "tests/api/interface/file_versioning_test.h"
#include "tests/api/interface/game_interface_test.h"
#include "tests/api/interface/is_compatible_test.h"
-377
View File
@@ -1,377 +0,0 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TESTS_API_INTERNALS_HELPERS_GIT_TEST
#define LOOT_TESTS_API_INTERNALS_HELPERS_GIT_TEST
#include "api/helpers/git.h"
#include <gtest/gtest.h>
#include "loot/exception/git_state_error.h"
#include "tests/common_game_test_fixture.h"
namespace loot {
namespace test {
class GitHelperTest : public ::testing::Test {
protected:
GitHelperTest() :
rootTestPath(getRootTestPath()),
repoRoot(rootTestPath / "testing-metadata"),
repoSubdirectory(repoRoot / "invalid"),
changedFile("LICENSE"),
unchangedFile("README.md"),
untrackedFile("untracked.txt") {}
inline void SetUp() {
using std::filesystem::exists;
copy(std::filesystem::absolute("./testing-metadata"), repoRoot);
ASSERT_TRUE(exists(repoRoot));
ASSERT_TRUE(exists(repoSubdirectory));
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 = std::filesystem::current_path();
std::filesystem::current_path(repoRoot);
system("git reset --hard");
std::filesystem::current_path(currentPath);
// Edit a tracked file
std::ofstream changedOut(repoRoot / changedFile);
changedOut.close();
ASSERT_TRUE(exists(repoRoot / changedFile));
// Create a new file in the repository
std::ofstream untrackedOut(repoRoot / untrackedFile);
untrackedOut.close();
ASSERT_TRUE(exists(repoRoot / untrackedFile));
// Create a new file outside the repository
std::ofstream outOfRepoOut(rootTestPath / untrackedFile);
outOfRepoOut.close();
ASSERT_TRUE(exists(rootTestPath / untrackedFile));
}
inline void TearDown() {
// Grant write permissions to everything in rootTestPath
// in case the test made anything read only.
for (const auto& path : std::filesystem::recursive_directory_iterator(rootTestPath)) {
std::filesystem::permissions(path, std::filesystem::perms::all);
}
std::filesystem::remove_all(rootTestPath);
}
GitHelper git_;
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 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 {
std::filesystem::copy(from, to);
}
}
};
TEST_F(GitHelperTest, destructorShouldCallLibgit2CleanupFunction) {
ASSERT_EQ(2, git_libgit2_init());
GitHelper* gitPointer = new GitHelper();
ASSERT_EQ(4, git_libgit2_init());
delete gitPointer;
EXPECT_EQ(2, git_libgit2_shutdown());
}
TEST_F(GitHelperTest, isRepositoryShouldReturnTrueForARepositoryRoot) {
EXPECT_TRUE(GitHelper::IsRepository(repoRoot));
}
TEST_F(GitHelperTest, isRepositoryShouldReturnFalseForRepositorySubdirectory) {
EXPECT_FALSE(GitHelper::IsRepository(repoSubdirectory));
}
TEST_F(GitHelperTest, isFileDifferentShouldThrowIfGivenANonRepositoryPath) {
EXPECT_THROW(GitHelper::IsFileDifferent(rootTestPath, untrackedFile),
GitStateError);
}
TEST_F(GitHelperTest, isFileDifferentShouldReturnFalseForAnUntrackedFile) {
// New files not in the index are not tracked by Git, so aren't considered
// different.
EXPECT_FALSE(GitHelper::IsFileDifferent(repoRoot, untrackedFile));
}
TEST_F(GitHelperTest,
isFileDifferentShouldReturnFalseForAnUnchangedTrackedFile) {
EXPECT_FALSE(GitHelper::IsFileDifferent(repoRoot, unchangedFile));
}
TEST_F(GitHelperTest,
isFileDifferentShouldReturnTrueForAChangedTrackedFile) {
EXPECT_TRUE(GitHelper::IsFileDifferent(repoRoot, changedFile));
}
class GitTest : public ::testing::Test {
protected:
GitTest() :
repoBranch("master"),
oldBranch("old-branch"),
remoteRepoPath("./testing-metadata.git"),
rootTestPath(getRootTestPath()),
metadataFilesPath(rootTestPath / "metadata"),
masterlistPath(rootTestPath / "masterlist.yaml"),
nonAsciiMasterlistPath(
rootTestPath / std::filesystem::u8path(u8"masterl\u00EDst.yaml")) {}
void SetUp() {
create_directories(metadataFilesPath);
ASSERT_TRUE(exists(metadataFilesPath));
auto sourceDirectory = std::filesystem::absolute("./testing-metadata");
std::filesystem::copy(sourceDirectory / "masterlist.yaml",
metadataFilesPath / "masterlist.yaml");
ASSERT_TRUE(std::filesystem::exists(metadataFilesPath / "masterlist.yaml"));
ASSERT_FALSE(std::filesystem::exists(masterlistPath));
ASSERT_FALSE(std::filesystem::exists(nonAsciiMasterlistPath));
ASSERT_FALSE(std::filesystem::exists(rootTestPath / ".git"));
}
void TearDown() {
// Grant write permissions to everything in rootTestPath
// in case the test made anything read only.
for (const auto& path :
std::filesystem::recursive_directory_iterator(rootTestPath)) {
std::filesystem::permissions(path, std::filesystem::perms::all);
}
std::filesystem::remove_all(rootTestPath);
}
void runRepoCommand(const std::string& command) {
auto testPath = std::filesystem::current_path();
std::filesystem::current_path(masterlistPath.parent_path());
system(command.c_str());
std::filesystem::current_path(testPath);
}
const std::string remoteRepoPath;
const std::string repoBranch;
const std::string oldBranch;
const std::filesystem::path rootTestPath;
const std::filesystem::path metadataFilesPath;
const std::filesystem::path masterlistPath;
const std::filesystem::path nonAsciiMasterlistPath;
};
TEST_F(GitTest, updateFileShouldThrowIfAnInvalidPathIsGiven) {
EXPECT_THROW(git::UpdateFile("//\?", remoteRepoPath, repoBranch),
std::system_error);
}
TEST_F(GitTest, updateFileShouldThrowIfABlankPathIsGiven) {
EXPECT_THROW(git::UpdateFile("", remoteRepoPath, repoBranch),
std::invalid_argument);
}
TEST_F(GitTest, updateFileShouldThrowIfABranchThatDoesNotExistIsGiven) {
EXPECT_THROW(git::UpdateFile(masterlistPath, remoteRepoPath, "missing-branch"),
std::system_error);
}
TEST_F(GitTest, updateFileShouldThrowIfABlankBranchIsGiven) {
EXPECT_THROW(git::UpdateFile(masterlistPath, remoteRepoPath, ""),
std::invalid_argument);
}
TEST_F(GitTest, updateFileShouldThrowIfAUrlThatDoesNotExistIsGiven) {
EXPECT_THROW(git::UpdateFile(masterlistPath,
"https://github.com/loot/does-not-exist.git",
repoBranch),
std::system_error);
}
TEST_F(GitTest, updateFileShouldThrowIfABlankUrlIsGiven) {
EXPECT_THROW(git::UpdateFile(masterlistPath, "", repoBranch),
std::invalid_argument);
}
TEST_F(GitTest, updateFileShouldBeAbleToCloneAGitHubRepository) {
EXPECT_NO_THROW(
git::UpdateFile(masterlistPath,
"https://github.com/loot/testing-metadata.git",
repoBranch));
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_F(GitTest, updateFileShouldBeAbleToCloneALocalRepository) {
EXPECT_NO_THROW(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_F(GitTest, updateFileShouldReturnTrueIfNoMasterlistExists) {
EXPECT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_F(GitTest, updateFileShouldReturnFalseIfAnUpToDateMasterlistExists) {
EXPECT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_FALSE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_F(
GitTest,
updateFileShouldReturnFalseIfAnUpToDateMasterlistWithANonAsciiFilenameExists) {
EXPECT_TRUE(git::UpdateFile(nonAsciiMasterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(nonAsciiMasterlistPath));
EXPECT_FALSE(git::UpdateFile(nonAsciiMasterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(nonAsciiMasterlistPath));
}
TEST_F(GitTest,
updateFileShouldDiscardLocalHistoryIfRemoteHistoryIsDifferent) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
runRepoCommand("git config commit.gpgsign false");
runRepoCommand("git commit --amend -m \"changing local history\"");
EXPECT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(std::filesystem::exists(masterlistPath));
}
TEST_F(GitTest, getVersionInfoShouldThrowIfNoMasterlistExistsAtTheGivenPath) {
EXPECT_THROW(git::GetVersionInfo(masterlistPath, false), FileAccessError);
}
TEST_F(GitTest,
getVersionInfoShouldThrowIfTheGivenPathDoesNotBelongToAGitRepository) {
ASSERT_NO_THROW(std::filesystem::copy(metadataFilesPath / "masterlist.yaml",
masterlistPath));
EXPECT_THROW(git::GetVersionInfo(masterlistPath, false), GitStateError);
}
TEST_F(
GitTest,
getVersionInfoShouldReturnRevisionAndDateStringsOfTheCorrectLengthsWhenRequestingALongId) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
FileRevision revision = git::GetVersionInfo(masterlistPath, false);
EXPECT_EQ(40, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_FALSE(revision.is_modified);
}
TEST_F(
GitTest,
getVersionInfoShouldReturnRevisionAndDateStringsOfTheCorrectLengthsWhenRequestingAShortId) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
FileRevision revision = git::GetVersionInfo(masterlistPath, true);
EXPECT_GE((unsigned)40, revision.id.length());
EXPECT_LE((unsigned)7, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_FALSE(revision.is_modified);
}
TEST_F(
GitTest,
getVersionInfoShouldAppendSuffixesToReturnedStringsIfTheMasterlistHasBeenEdited) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
std::ofstream out(masterlistPath);
out.close();
FileRevision revision = git::GetVersionInfo(masterlistPath, false);
EXPECT_EQ(40, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_TRUE(revision.is_modified);
}
TEST_F(GitTest,
getVersionInfoShouldDetectWhenAMasterlistWithANonAsciiFilenameHasBeenEdited) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
auto nonAsciiPath = masterlistPath.parent_path() /
std::filesystem::u8path(u8"non\u00C1scii.yaml");
std::filesystem::copy_file(masterlistPath, nonAsciiPath);
runRepoCommand("git add " + nonAsciiPath.string());
std::ofstream out(nonAsciiPath);
out.close();
FileRevision revision = git::GetVersionInfo(nonAsciiPath, false);
EXPECT_EQ(40, revision.id.length());
EXPECT_EQ(10, revision.date.length());
EXPECT_TRUE(revision.is_modified);
}
TEST_F(GitTest,
isLatestShouldThrowIfTheGivenPathDoesNotBelongToAGitRepository) {
ASSERT_NO_THROW(std::filesystem::copy(metadataFilesPath / "masterlist.yaml",
masterlistPath));
EXPECT_THROW(git::IsLatest(masterlistPath, repoBranch), GitStateError);
}
TEST_F(GitTest, isLatestShouldThrowIfTheGivenBranchIsAnEmptyString) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_THROW(git::IsLatest(masterlistPath, ""), std::invalid_argument);
}
TEST_F(
GitTest,
isLatestShouldReturnFalseIfTheCurrentRevisionIsNotTheLatestRevisionInTheGivenBranch) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, oldBranch));
EXPECT_FALSE(git::IsLatest(masterlistPath, repoBranch));
}
TEST_F(
GitTest,
isLatestShouldReturnTrueIfTheCurrentRevisionIsTheLatestRevisioninTheGivenBranch) {
ASSERT_TRUE(git::UpdateFile(masterlistPath, remoteRepoPath, repoBranch));
EXPECT_TRUE(git::IsLatest(masterlistPath, repoBranch));
}
}
}
#endif
-1
View File
@@ -26,7 +26,6 @@
#include "tests/api/internals/game/game_test.h"
#include "tests/api/internals/game/load_order_handler_test.h"
#include "tests/api/internals/helpers/crc_test.h"
#include "tests/api/internals/helpers/git_test.h"
#include "tests/api/internals/helpers/text_test.h"
#include "tests/api/internals/helpers/yaml_set_helpers_test.h"
#include "tests/api/internals/metadata/condition_evaluator_test.h"