Merge pull request #556 from loot/c++-test-improvements

C++ test improvements
This commit is contained in:
Oliver Hamlet
2016-04-02 12:59:05 +01:00
79 changed files with 7534 additions and 6691 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ before_script:
- cmake .. -DPROJECT_STATIC_RUNTIME=OFF -DBUILD_SHARED_LIBS=OFF
script:
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && npm test || false'
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm test; fi
- make tests && ./tests
before_deploy:
+43 -28
View File
@@ -215,34 +215,49 @@ set (LOOT_TESTS_SRC ${LOOT_SRC}
"${CMAKE_SOURCE_DIR}/src/gui/loot_state.cpp"
"${CMAKE_SOURCE_DIR}/src/tests/main.cpp")
set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h"
set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/base_game_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/printers.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/api_game_operations_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_apply_load_order_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_create_db_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_db_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_eval_lists_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_get_dirty_info_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_get_masterlist_revision_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_get_plugin_messages_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_get_plugin_tags_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_get_tag_map_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_load_lists_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_sort_plugins_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_update_masterlist_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/loot_write_minimal_list_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/test_api.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/test_loot_db.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/test_game.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/test_game_cache.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/test_game_settings.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/test_load_order_handler.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_git_helper.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_helpers.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_language.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_version.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_yaml_set_helpers.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_condition_grammar.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_conditional_metadata.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_file.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_location.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_message.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_message_content.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_plugin_dirty_info.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/test_tag.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/plugin/test_plugin.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_metadata_list.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_masterlist.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_plugin_sorter.h"
"${CMAKE_SOURCE_DIR}/src/tests/gui/test_loot_settings.h"
"${CMAKE_SOURCE_DIR}/src/tests/gui/test_loot_state.h")
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_cache_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_settings_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/game/load_order_handler_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/git_helper_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/helpers_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/language_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/version_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/yaml_set_helpers_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/condition_grammar_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/conditional_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/file_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/location_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/message_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/message_content_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/plugin_dirty_info_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/plugin_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/tag_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/plugin/plugin_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/masterlist_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata_list_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/plugin_sorter_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/gui/loot_settings_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/gui/loot_state_test.h")
source_group("Header Files\\backend" FILES ${LOOT_HEADERS})
source_group("Header Files\\gui" FILES ${LOOT_GUI_HEADERS})
@@ -289,8 +304,8 @@ ENDIF ()
# GCC and MinGW settings.
IF (CMAKE_COMPILER_IS_GNUCXX)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=c++11")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++11")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=c++14")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++14")
IF (PROJECT_STATIC_RUNTIME)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
-1
View File
@@ -277,7 +277,6 @@ extern "C"
*************************************************************************/
/**@{*/
LOOT_API extern const unsigned int loot_lang_any; /**< Tells the API to select messages of any language. */
LOOT_API extern const unsigned int loot_lang_english; /**< Tells the API to preferentially select English messages. */
LOOT_API extern const unsigned int loot_lang_spanish; /**< Tells the API to preferentially select Spanish messages */
LOOT_API extern const unsigned int loot_lang_russian; /**< Tells the API to preferentially select Russian messages. */
+2 -4
View File
@@ -69,7 +69,6 @@ const unsigned int loot_message_warn = loot::Message::warn;
const unsigned int loot_message_error = loot::Message::error;
// LOOT message languages.
const unsigned int loot_lang_any = loot::Language::any;
const unsigned int loot_lang_english = loot::Language::english;
const unsigned int loot_lang_spanish = loot::Language::spanish;
const unsigned int loot_lang_russian = loot::Language::russian;
@@ -283,8 +282,7 @@ LOOT_API unsigned int loot_load_lists(loot_db * const db, const char * const mas
LOOT_API unsigned int loot_eval_lists(loot_db * const db, const unsigned int language) {
if (db == nullptr)
return c_error(loot_error_invalid_args, "Null pointer passed.");
if (language != loot_lang_any
&& language != loot_lang_english
if (language != loot_lang_english
&& language != loot_lang_spanish
&& language != loot_lang_russian
&& language != loot_lang_french
@@ -336,7 +334,7 @@ LOOT_API unsigned int loot_sort_plugins(loot_db * const db,
//Sort plugins into their load order.
loot::PluginSorter sorter;
db->setPluginNames(sorter.Sort(*db, loot_lang_any));
db->setPluginNames(sorter.Sort(*db, loot::Language::english));
}
catch (loot::error &e) {
return c_error(e);
+1 -1
View File
@@ -92,7 +92,7 @@ void loot_db::setPluginMessages(const std::list<loot::Message>& pluginMessages)
size_t i = 0;
for (const auto& message : pluginMessages) {
pluginMessageStrings[i] = message.ChooseContent(loot::Language::any).Str();
pluginMessageStrings[i] = message.ChooseContent(loot::Language::english).Str();
cPluginMessages[i].type = message.Type();
cPluginMessages[i].message = pluginMessageStrings[i].c_str();
+3 -4
View File
@@ -316,15 +316,14 @@ namespace loot {
return revision;
}
bool IsFileDifferent(const boost::filesystem::path& repoRoot, const std::string& filename) {
GitHelper git;
if (!git.IsRepository(repoRoot)) {
bool GitHelper::IsFileDifferent(const boost::filesystem::path& repoRoot, const std::string& filename) {
if (!IsRepository(repoRoot)) {
BOOST_LOG_TRIVIAL(info) << "Unknown masterlist revision: Git repository missing.";
throw error(error::ok, lc::translate("Unknown: Git repository missing"));
}
BOOST_LOG_TRIVIAL(debug) << "Existing repository found, attempting to open it.";
GitHelper git;
git.Call(git_repository_open(&git.repo, repoRoot.string().c_str()));
// Perform a git diff, then iterate the deltas to see if one exists for the masterlist.
+2 -2
View File
@@ -43,6 +43,8 @@ namespace loot {
static bool IsRepository(const boost::filesystem::path& path);
static bool IsFileDifferent(const boost::filesystem::path& repoRoot, const std::string& filename);
// Clones a repository and opens it. Sets 'repo'.
void Clone(const boost::filesystem::path& path, const std::string& url);
@@ -85,7 +87,5 @@ namespace loot {
// created by libgit2.
static void FixRepoPermissions(const boost::filesystem::path& path);
};
bool IsFileDifferent(const boost::filesystem::path& repoRoot, const std::string& filename);
}
#endif
-1
View File
@@ -25,7 +25,6 @@
#include "language.h"
namespace loot {
const unsigned int Language::any = 0;
const unsigned int Language::english = 1;
const unsigned int Language::spanish = 2;
const unsigned int Language::russian = 3;
-1
View File
@@ -39,7 +39,6 @@ namespace loot {
std::string Name() const;
std::string Locale() const;
static const unsigned int any; // This shouldn't be used as a selectable language, just for when picking any string in a message.
static const unsigned int english;
static const unsigned int spanish;
static const unsigned int russian;
+2 -2
View File
@@ -77,7 +77,7 @@ namespace loot {
info.date = out.str();
BOOST_LOG_TRIVIAL(trace) << "Diffing masterlist HEAD and working copy.";
if (IsFileDifferent(path.parent_path(), path.filename().string())) {
if (GitHelper::IsFileDifferent(path.parent_path(), path.filename().string())) {
info.revision += string(" ") + lc::translate("(edited)").str();
info.date += string(" ") + lc::translate("(edited)").str();
}
@@ -203,7 +203,7 @@ namespace loot {
// must be performed and the checked-out file parsed.
if (!updateBranchHead) {
BOOST_LOG_TRIVIAL(trace) << "Local and remote branch heads are equal.";
if (!IsFileDifferent(repoPath, filename)) {
if (!GitHelper::IsFileDifferent(repoPath, filename)) {
BOOST_LOG_TRIVIAL(info) << "Local branch and masterlist file are already up to date.";
return false;
}
-2
View File
@@ -31,8 +31,6 @@ using namespace std;
namespace loot {
Location::Location() {}
Location::Location(const std::string& url) : _url(url) {}
Location::Location(const std::string& url, const std::string& name) : _url(url), _name(name) {}
bool Location::operator < (const Location& rhs) const {
+1 -2
View File
@@ -33,8 +33,7 @@ namespace loot {
class Location {
public:
Location();
Location(const std::string& url);
Location(const std::string& url, const std::string& name);
Location(const std::string& url, const std::string& name = "");
bool operator < (const Location& rhs) const;
bool operator == (const Location& rhs) const;
+13 -2
View File
@@ -24,6 +24,7 @@
#include "message.h"
#include "../helpers/language.h"
#include "../error.h"
#include <boost/log/trivial.hpp>
@@ -42,7 +43,17 @@ namespace loot {
}
Message::Message(const unsigned int type, const std::vector<MessageContent>& content,
const std::string& condition) : _type(type), _content(content), ConditionalMetadata(condition) {}
const std::string& condition) : _type(type), _content(content), ConditionalMetadata(condition) {
if (content.size() > 1) {
bool englishStringExists = false;
for (const auto &mc : content) {
if (mc.Language() == loot::Language::english)
englishStringExists = true;
}
if (!englishStringExists)
throw loot::error(error::invalid_args, "bad conversion: multilingual messages must contain an English content string");
}
}
bool Message::operator < (const Message& rhs) const {
if (!_content.empty() && !rhs.Content().empty())
@@ -68,7 +79,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(trace) << "Choosing message content.";
if (_content.empty())
return MessageContent();
else if (_content.size() == 1 || language == Language::any)
else if (_content.size() == 1)
return _content[0];
else {
MessageContent english;
+87 -47
View File
@@ -50,7 +50,8 @@ namespace loot {
if (plugin.HasNameOnly())
return;
//For 'enabled' and 'priority' metadata, use the given plugin's values, but if the 'priority' user value is not explicit, ignore it.
// For 'enabled' and 'priority' metadata, use the given plugin's values,
// but if the 'priority' user value is not explicit, ignore it.
enabled = plugin.Enabled();
if (plugin.IsPriorityExplicit()) {
Priority(plugin.Priority());
@@ -58,29 +59,24 @@ namespace loot {
_isPriorityExplicit = true;
}
//Merge the following. If any files in the source already exist in the destination, they will be skipped. Files have display strings and condition strings which aren't considered when comparing them, so will be lost if the plugin being merged in has additional data in these strings.
std::set<File> files = plugin.LoadAfter();
loadAfter.insert(files.begin(), files.end());
// Merge the following. If any files in the source already exist in the
// destination, they will be skipped. Files have display strings and
// condition strings which aren't considered when comparing them, so
// will be lost if the plugin being merged in has additional data in
// these strings.
loadAfter.insert(begin(plugin.loadAfter), end(plugin.loadAfter));
requirements.insert(begin(plugin.requirements), end(plugin.requirements));
incompatibilities.insert(begin(plugin.incompatibilities), end(plugin.incompatibilities));
files = plugin.Reqs();
requirements.insert(files.begin(), files.end());
// Merge Bash Tags too. Conditions are ignored during comparison, but
// if a tag is added and removed, both instances will be in the set.
tags.insert(begin(plugin.tags), end(plugin.tags));
files = plugin.Incs();
incompatibilities.insert(files.begin(), files.end());
// Messages are in an ordered list, and should be fully merged.
messages.insert(end(messages), begin(plugin.messages), end(plugin.messages));
//Merge Bash Tags too. Conditions are ignored during comparison, but if a tag is added and removed, both instances will be in the set.
std::set<Tag> bashTags = plugin.Tags();
tags.insert(bashTags.begin(), bashTags.end());
//Messages are in an ordered list, and should be fully merged.
std::list<Message> pMessages = plugin.Messages();
messages.insert(messages.end(), pMessages.begin(), pMessages.end());
set<PluginDirtyInfo> dirtyInfo = plugin.DirtyInfo();
_dirtyInfo.insert(dirtyInfo.begin(), dirtyInfo.end());
set<Location> locations = plugin.Locations();
_locations.insert(locations.begin(), locations.end());
_dirtyInfo.insert(begin(plugin._dirtyInfo), end(plugin._dirtyInfo));
_locations.insert(begin(plugin._locations), end(plugin._locations));
return;
}
@@ -96,19 +92,28 @@ namespace loot {
}
//Compare this plugin against the given plugin.
set<File> files = plugin.LoadAfter();
set<File> filesDiff;
set_symmetric_difference(loadAfter.begin(), loadAfter.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_symmetric_difference(begin(loadAfter),
end(loadAfter),
begin(plugin.loadAfter),
end(plugin.loadAfter),
inserter(filesDiff, begin(filesDiff)));
p.LoadAfter(filesDiff);
filesDiff.clear();
files = plugin.Reqs();
set_symmetric_difference(requirements.begin(), requirements.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_symmetric_difference(begin(requirements),
end(requirements),
begin(plugin.requirements),
end(plugin.requirements),
inserter(filesDiff, begin(filesDiff)));
p.Reqs(filesDiff);
filesDiff.clear();
files = plugin.Incs();
set_symmetric_difference(incompatibilities.begin(), incompatibilities.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_symmetric_difference(begin(incompatibilities),
end(incompatibilities),
begin(plugin.incompatibilities),
end(plugin.incompatibilities),
inserter(filesDiff, begin(filesDiff)));
p.Incs(filesDiff);
list<Message> msgs1 = plugin.Messages();
@@ -116,22 +121,35 @@ namespace loot {
msgs1.sort();
msgs2.sort();
list<Message> mDiff;
set_symmetric_difference(msgs2.begin(), msgs2.end(), msgs1.begin(), msgs1.end(), inserter(mDiff, mDiff.begin()));
set_symmetric_difference(begin(msgs2),
end(msgs2),
begin(msgs1),
end(msgs1),
inserter(mDiff, begin(mDiff)));
p.Messages(mDiff);
set<Tag> bashTags = plugin.Tags();
set<Tag> tagDiff;
set_symmetric_difference(tags.begin(), tags.end(), bashTags.begin(), bashTags.end(), inserter(tagDiff, tagDiff.begin()));
set_symmetric_difference(begin(tags),
end(tags),
begin(plugin.tags),
end(plugin.tags),
inserter(tagDiff, begin(tagDiff)));
p.Tags(tagDiff);
set<PluginDirtyInfo> dirtyInfo = plugin.DirtyInfo();
set<PluginDirtyInfo> dirtDiff;
set_symmetric_difference(_dirtyInfo.begin(), _dirtyInfo.end(), dirtyInfo.begin(), dirtyInfo.end(), inserter(dirtDiff, dirtDiff.begin()));
set_symmetric_difference(begin(_dirtyInfo),
end(_dirtyInfo),
begin(plugin._dirtyInfo),
end(plugin._dirtyInfo),
inserter(dirtDiff, begin(dirtDiff)));
p.DirtyInfo(dirtDiff);
set<Location> locations = plugin.Locations();
set<Location> locationsDiff;
set_symmetric_difference(_locations.begin(), _locations.end(), locations.begin(), locations.end(), inserter(locationsDiff, locationsDiff.begin()));
set_symmetric_difference(begin(_locations),
end(_locations),
begin(plugin._locations),
end(plugin._locations),
inserter(locationsDiff, begin(locationsDiff)));
p.Locations(locationsDiff);
return p;
@@ -142,19 +160,28 @@ namespace loot {
PluginMetadata p(*this);
//Compare this plugin against the given plugin.
set<File> files = plugin.LoadAfter();
set<File> filesDiff;
set_difference(loadAfter.begin(), loadAfter.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_difference(begin(loadAfter),
end(loadAfter),
begin(plugin.loadAfter),
end(plugin.loadAfter),
inserter(filesDiff, begin(filesDiff)));
p.LoadAfter(filesDiff);
filesDiff.clear();
files = plugin.Reqs();
set_difference(requirements.begin(), requirements.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_difference(begin(requirements),
end(requirements),
begin(plugin.requirements),
end(plugin.requirements),
inserter(filesDiff, begin(filesDiff)));
p.Reqs(filesDiff);
filesDiff.clear();
files = plugin.Incs();
set_difference(incompatibilities.begin(), incompatibilities.end(), files.begin(), files.end(), inserter(filesDiff, filesDiff.begin()));
set_difference(begin(incompatibilities),
end(incompatibilities),
begin(plugin.incompatibilities),
end(plugin.incompatibilities),
inserter(filesDiff, begin(filesDiff)));
p.Incs(filesDiff);
list<Message> msgs1 = plugin.Messages();
@@ -162,22 +189,35 @@ namespace loot {
msgs1.sort();
msgs2.sort();
list<Message> mDiff;
set_difference(msgs2.begin(), msgs2.end(), msgs1.begin(), msgs1.end(), inserter(mDiff, mDiff.begin()));
set_difference(begin(msgs2),
end(msgs2),
begin(msgs1),
end(msgs1),
inserter(mDiff, begin(mDiff)));
p.Messages(mDiff);
set<Tag> bashTags = plugin.Tags();
set<Tag> tagDiff;
set_difference(tags.begin(), tags.end(), bashTags.begin(), bashTags.end(), inserter(tagDiff, tagDiff.begin()));
set_difference(begin(tags),
end(tags),
begin(plugin.tags),
end(plugin.tags),
inserter(tagDiff, begin(tagDiff)));
p.Tags(tagDiff);
set<PluginDirtyInfo> dirtyInfo = plugin.DirtyInfo();
set<PluginDirtyInfo> dirtDiff;
set_difference(_dirtyInfo.begin(), _dirtyInfo.end(), dirtyInfo.begin(), dirtyInfo.end(), inserter(dirtDiff, dirtDiff.begin()));
set_difference(begin(_dirtyInfo),
end(_dirtyInfo),
begin(plugin._dirtyInfo),
end(plugin._dirtyInfo),
inserter(dirtDiff, begin(dirtDiff)));
p.DirtyInfo(dirtDiff);
set<Location> locations = plugin.Locations();
set<Location> locationsDiff;
set_difference(_locations.begin(), _locations.end(), locations.begin(), locations.end(), inserter(locationsDiff, locationsDiff.begin()));
set_difference(begin(_locations),
end(_locations),
begin(plugin._locations),
end(plugin._locations),
inserter(locationsDiff, begin(locationsDiff)));
p.Locations(locationsDiff);
return p;
+8 -2
View File
@@ -92,15 +92,21 @@ namespace loot {
_isActive = game.IsPluginActive(Name());
// Get whether the plugin loads an archive (BSA/BA2) or not.
string archiveExtension;
if (game.Id() == Game::fo4)
archiveExtension = ".ba2";
else
archiveExtension = ".bsa";
if (game.Id() == Game::tes5 || game.Id() == Game::fo4) {
// Skyrim and Fallout 4 plugins only load archives that exactly match their basename.
_loadsArchive = boost::filesystem::exists(game.DataPath() / (Name().substr(0, Name().length() - 3) + "bsa"));
_loadsArchive = boost::filesystem::exists(game.DataPath() / (Name().substr(0, Name().length() - 4) + archiveExtension));
}
else if (game.Id() != Game::tes4 || boost::iends_with(Name(), ".esp")) {
//Oblivion .esp files and FO3, FNV plugins can load BSAs which begin with the plugin basename.
string basename = Name().substr(0, Name().length() - 4);
for (boost::filesystem::directory_iterator it(game.DataPath()); it != boost::filesystem::directory_iterator(); ++it) {
if (it->path().extension().string() == ".bsa" && boost::istarts_with(it->path().filename().string(), basename)) {
if (boost::iequals(it->path().extension().string(), archiveExtension) && boost::istarts_with(it->path().filename().string(), basename)) {
_loadsArchive = true;
break;
}
+118
View File
@@ -0,0 +1,118 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2013-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
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_API_GAME_OPERATIONS_TEST
#define LOOT_TEST_API_GAME_OPERATIONS_TEST
#include "../base_game_test.h"
namespace loot {
namespace test {
class ApiGameOperationsTest : public BaseGameTest {
protected:
ApiGameOperationsTest() :
db(nullptr),
masterlistPath(localPath / "masterlist.yaml"),
noteMessage("Do not clean ITM records, they are intentional and required for the mod to function."),
warningMessage("Check you are using v2+. If not, Update. v1 has a severe bug with the Mystic Emporium disappearing."),
errorMessage("Obsolete. Remove this and install Enhanced Weather.") {}
inline virtual void SetUp() {
BaseGameTest::SetUp();
ASSERT_FALSE(boost::filesystem::exists(masterlistPath));
ASSERT_EQ(loot_ok, loot_create_db(&db, GetParam(), dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
inline virtual void TearDown() {
BaseGameTest::TearDown();
ASSERT_NO_THROW(loot_destroy_db(db));
// The masterlist may have been created during the test, so delete it.
ASSERT_NO_THROW(boost::filesystem::remove(masterlistPath));
}
inline void generateMasterlist() {
using std::endl;
boost::filesystem::ofstream masterlist(masterlistPath);
masterlist
<< "plugins:" << endl
<< " - name: " << blankEsm << endl
<< " after:" << endl
<< " - " << masterFile << endl
<< " msg:" << endl
<< " - type: say" << endl
<< " content: '" << noteMessage << "'" << endl
<< " tag:" << endl
<< " - Actors.ACBS" << endl
<< " - Actors.AIData" << endl
<< " - '-C.Water'" << endl
<< " - name: " << blankDifferentEsm << endl
<< " after:" << endl
<< " - " << blankMasterDependentEsm << endl
<< " msg:" << endl
<< " - type: warn" << endl
<< " content: '" << warningMessage << "'" << endl
<< " dirty:" << endl
<< " - crc: 0x7d22f9df" << endl
<< " util: TES4Edit" << endl
<< " udr: 4" << endl
<< " - name: " << blankDifferentEsp << endl
<< " after:" << endl
<< " - " << blankPluginDependentEsp << endl
<< " msg:" << endl
<< " - type: error" << endl
<< " content: '" << errorMessage << "'" << endl
<< " - name: " << blankEsp << endl
<< " after:" << endl
<< " - " << blankDifferentMasterDependentEsp << endl
<< " - name: " << blankDifferentMasterDependentEsp << endl
<< " after:" << endl
<< " - " << blankMasterDependentEsp << endl
<< " msg:" << endl
<< " - type: say" << endl
<< " content: '" << noteMessage << "'" << endl
<< " - type: warn" << endl
<< " content: '" << warningMessage << "'" << endl
<< " - type: error" << endl
<< " content: '" << errorMessage << "'" << endl;
masterlist.close();
}
loot_db * db;
const boost::filesystem::path masterlistPath;
const std::string noteMessage;
const std::string warningMessage;
const std::string errorMessage;
};
}
}
#endif
@@ -0,0 +1,77 @@
/* 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
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_LOOT_APPLY_LOAD_ORDER
#define LOOT_TEST_LOOT_APPLY_LOAD_ORDER
#include "../include/loot/api.h"
#include "api_game_operations_test.h"
namespace loot {
namespace test {
class loot_apply_load_order_test : public ApiGameOperationsTest {};
// 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_CASE_P(,
loot_apply_load_order_test,
::testing::Values(
loot_game_tes4,
loot_game_tes5,
loot_game_fo3,
loot_game_fonv,
loot_game_fo4));
TEST_P(loot_apply_load_order_test, shouldReturnAnInvalidArgsIfTheDbOrLoadOrderPointersAreNull) {
const char * loadOrder[1] = {
masterFile.c_str(),
};
size_t numPlugins = 0;
EXPECT_EQ(loot_error_invalid_args, loot_apply_load_order(NULL, loadOrder, numPlugins));
EXPECT_EQ(loot_error_invalid_args, loot_apply_load_order(db, NULL, numPlugins));
}
TEST_P(loot_apply_load_order_test, shouldReturnOkIfLoadOrderGivenIsNotEmpty) {
const char * loadOrder[11] = {
masterFile.c_str(),
blankEsm.c_str(),
blankMasterDependentEsm.c_str(),
blankDifferentEsm.c_str(),
blankDifferentMasterDependentEsm.c_str(),
blankMasterDependentEsp.c_str(),
blankDifferentMasterDependentEsp.c_str(),
blankEsp.c_str(),
blankPluginDependentEsp.c_str(),
blankDifferentEsp.c_str(),
blankDifferentPluginDependentEsp.c_str(),
};
size_t numPlugins = 11;
EXPECT_EQ(loot_ok, loot_apply_load_order(db, loadOrder, numPlugins));
}
}
}
#endif
+97
View File
@@ -0,0 +1,97 @@
/* 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
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_LOOT_CREATE_DB
#define LOOT_TEST_LOOT_CREATE_DB
#include "../include/loot/api.h"
#include "tests/base_game_test.h"
#include <climits>
namespace loot {
namespace test {
class loot_create_db_test : public BaseGameTest {
protected:
loot_create_db_test() :
db(nullptr) {}
inline virtual void TearDown() {
BaseGameTest::TearDown();
ASSERT_NO_THROW(loot_destroy_db(db));
}
loot_db * db;
};
// 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_CASE_P(,
loot_create_db_test,
::testing::Values(
loot_game_tes4,
loot_game_tes5,
loot_game_fo3,
loot_game_fonv,
loot_game_fo4));
TEST_P(loot_create_db_test, shouldSucceedIfPassedValidParametersWithRelativePaths) {
EXPECT_EQ(loot_ok, loot_create_db(&db, GetParam(), dataPath.parent_path().string().c_str(), localPath.string().c_str()));
EXPECT_NE(nullptr, db);
}
TEST_P(loot_create_db_test, shouldSucceedIfPassedValidParametersWithAbsolutePaths) {
boost::filesystem::path game = boost::filesystem::current_path() / dataPath.parent_path();
boost::filesystem::path local = boost::filesystem::current_path() / localPath;
EXPECT_EQ(loot_ok, loot_create_db(&db, GetParam(), game.string().c_str(), local.string().c_str()));
EXPECT_NE(nullptr, db);
}
TEST_P(loot_create_db_test, shouldReturnAnInvalidArgsErrorIfPassedANullPointer) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(NULL, GetParam(), dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
TEST_P(loot_create_db_test, shouldReturnAnInvalidArgsErrorIfPassedAnInvalidGameType) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, UINT_MAX, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
TEST_P(loot_create_db_test, shouldReturnAnInvalidArgsErrorIfPassedAGamePathThatDoesNotExist) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, GetParam(), missingPath.string().c_str(), localPath.string().c_str()));
}
TEST_P(loot_create_db_test, shouldReturnAnInvalidArgsErrorIfPassedALocalPathThatDoesNotExist) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, GetParam(), dataPath.parent_path().string().c_str(), missingPath.string().c_str()));
}
#ifdef _WIN32
TEST_P(loot_create_db_test, shouldReturnOkIfPassedANullLocalPathPointer) {
EXPECT_EQ(loot_ok, loot_create_db(&db, GetParam(), dataPath.parent_path().string().c_str(), NULL));
}
#endif
}
}
#endif
@@ -27,30 +27,52 @@ along with LOOT. If not, see
#include "api/loot_db.h"
#include "backend/game/game_settings.h"
#include "tests/fixtures.h"
#include "tests/base_game_test.h"
namespace loot {
namespace test {
class loot_db_test : public SkyrimTest {
class loot_db_test : public BaseGameTest {
protected:
virtual void SetUp() {
SkyrimTest::SetUp();
loot_db_test() :
db(nullptr) {}
db = new loot_db(Game::tes5, dataPath.parent_path().string().c_str(), localPath.string().c_str());
virtual void SetUp() {
BaseGameTest::SetUp();
db = new loot_db(GetParam(), dataPath.parent_path().string().c_str(), localPath.string().c_str());
}
inline virtual void TearDown() {
BaseGameTest::TearDown();
delete db;
}
loot_db * db;
};
TEST_F(loot_db_test, settingRevisionIdStringShouldCopyIt) {
// 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_CASE_P(,
loot_db_test,
::testing::Values(
loot_game_tes4,
loot_game_tes5,
loot_game_fo3,
loot_game_fonv,
loot_game_fo4));
TEST_P(loot_db_test, settingRevisionIdStringShouldCopyIt) {
db->setRevisionIdString("id");
EXPECT_STREQ("id", db->getRevisionIdString());
}
TEST_F(loot_db_test, settingRevisionDateStringShouldCopyIt) {
TEST_P(loot_db_test, settingRevisionDateStringShouldCopyIt) {
db->setRevisionDateString("date");
EXPECT_STREQ("date", db->getRevisionDateString());
}
TEST_F(loot_db_test, settingPluginNamesShouldCopyThem) {
TEST_P(loot_db_test, settingPluginNamesShouldCopyThem) {
db->setPluginNames(std::vector<PluginMetadata>({
PluginMetadata("Blank.esm"),
PluginMetadata("Blank.esp"),
@@ -61,7 +83,7 @@ namespace loot {
EXPECT_STREQ("Blank.esp", db->getPluginNames()[1]);
}
TEST_F(loot_db_test, settingPluginNamesTwiceShouldOverwriteTheFirstDataSet) {
TEST_P(loot_db_test, settingPluginNamesTwiceShouldOverwriteTheFirstDataSet) {
db->setPluginNames(std::vector<PluginMetadata>({
PluginMetadata("Blank.esm"),
PluginMetadata("Blank.esp"),
@@ -76,7 +98,7 @@ namespace loot {
EXPECT_STREQ("Blank - Different.esp", db->getPluginNames()[1]);
}
TEST_F(loot_db_test, addingNewBashTagsToTheMapShouldAppendThem) {
TEST_P(loot_db_test, addingNewBashTagsToTheMapShouldAppendThem) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -87,7 +109,7 @@ namespace loot {
EXPECT_STREQ("Relev", db->getBashTagMap()[1]);
}
TEST_F(loot_db_test, addingAnExistingBashTagToTheMapShouldNotDuplicateIt) {
TEST_P(loot_db_test, addingAnExistingBashTagToTheMapShouldNotDuplicateIt) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -99,11 +121,11 @@ namespace loot {
EXPECT_STREQ("Relev", db->getBashTagMap()[1]);
}
TEST_F(loot_db_test, gettingABashTagsUidForATagThatIsNotInTheMapShouldThrow) {
TEST_P(loot_db_test, gettingABashTagsUidForATagThatIsNotInTheMapShouldThrow) {
EXPECT_ANY_THROW(db->getBashTagUid("Relev"));
}
TEST_F(loot_db_test, gettingABashTagsUidShouldReturnItsTagMapIndex) {
TEST_P(loot_db_test, gettingABashTagsUidShouldReturnItsTagMapIndex) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -112,11 +134,11 @@ namespace loot {
EXPECT_EQ(1, db->getBashTagUid("Relev"));
}
TEST_F(loot_db_test, clearingAnEmptyBashTagMapShouldDoNothing) {
TEST_P(loot_db_test, clearingAnEmptyBashTagMapShouldDoNothing) {
EXPECT_NO_THROW(db->clearBashTagMap());
}
TEST_F(loot_db_test, clearingABashTagMapShouldEmptyIt) {
TEST_P(loot_db_test, clearingABashTagMapShouldEmptyIt) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -126,7 +148,7 @@ namespace loot {
EXPECT_TRUE(db->getBashTagMap().empty());
}
TEST_F(loot_db_test, clearingABashTagMapShouldAffectExistingReferences) {
TEST_P(loot_db_test, clearingABashTagMapShouldAffectExistingReferences) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -137,13 +159,13 @@ namespace loot {
EXPECT_TRUE(bashTagMap.empty());
}
TEST_F(loot_db_test, settingAddedTagsWithNoTagMapShouldThrow) {
TEST_P(loot_db_test, settingAddedTagsWithNoTagMapShouldThrow) {
EXPECT_ANY_THROW(db->setAddedTags({
"Relev",
}));
}
TEST_F(loot_db_test, gettingSetAddedTagsShouldReturnTheirUids) {
TEST_P(loot_db_test, gettingSetAddedTagsShouldReturnTheirUids) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -158,13 +180,13 @@ namespace loot {
}), db->getAddedTagIds());
}
TEST_F(loot_db_test, settingRemovedTagsWithNoTagMapShouldThrow) {
TEST_P(loot_db_test, settingRemovedTagsWithNoTagMapShouldThrow) {
EXPECT_ANY_THROW(db->setRemovedTags({
"Relev",
}));
}
TEST_F(loot_db_test, gettingSetRemovedTagsShouldReturnTheirUids) {
TEST_P(loot_db_test, gettingSetRemovedTagsShouldReturnTheirUids) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
@@ -179,7 +201,7 @@ namespace loot {
}), db->getRemovedTagIds());
}
TEST_F(loot_db_test, settingPluginMessagesShouldCopyThem) {
TEST_P(loot_db_test, settingPluginMessagesShouldCopyThem) {
db->setPluginMessages(std::list<Message>({
Message(Message::warn, "Test 1"),
Message(Message::error, "Test 2"),
@@ -192,7 +214,7 @@ namespace loot {
EXPECT_STREQ("Test 2", db->getPluginMessages()[1].message);
}
TEST_F(loot_db_test, settingPluginMessagesTwiceShouldOverwriteTheFirstDataSet) {
TEST_P(loot_db_test, settingPluginMessagesTwiceShouldOverwriteTheFirstDataSet) {
db->setPluginMessages(std::list<Message>({
Message(Message::warn, "Test 1"),
Message(Message::error, "Test 2"),
@@ -212,7 +234,7 @@ namespace loot {
EXPECT_STREQ("Test 5", db->getPluginMessages()[2].message);
}
TEST_F(loot_db_test, clearingArraysShouldEmptyPluginNamesTagIdsAndMessages) {
TEST_P(loot_db_test, clearingArraysShouldEmptyPluginNamesTagIdsAndMessages) {
db->setPluginMessages(std::list<Message>({
Message(Message::warn, "Test 1"),
Message(Message::error, "Test 2"),
@@ -247,7 +269,7 @@ namespace loot {
EXPECT_TRUE(db->getRemovedTagIds().empty());
}
TEST_F(loot_db_test, clearingArraysShouldNotEmptyBashTagMap) {
TEST_P(loot_db_test, clearingArraysShouldNotEmptyBashTagMap) {
db->addBashTagsToMap({
"C.Climate",
"Relev",
+87
View File
@@ -0,0 +1,87 @@
/* 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
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_LOOT_EVAL_LISTS
#define LOOT_TEST_LOOT_EVAL_LISTS
#include "../include/loot/api.h"
#include "api_game_operations_test.h"
namespace loot {
namespace test {
class loot_eval_lists_test : public ApiGameOperationsTest {};
// 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_CASE_P(,
loot_eval_lists_test,
::testing::Values(
loot_game_tes4,
loot_game_tes5,
loot_game_fo3,
loot_game_fonv,
loot_game_fo4));
TEST_P(loot_eval_lists_test, shouldReturnAnInvalidArgsErrorIfPassedANullPointer) {
EXPECT_EQ(loot_error_invalid_args, loot_eval_lists(NULL, loot_lang_english));
}
TEST_P(loot_eval_lists_test, shouldReturnAnInvalidArgsErrorIfPassedAnInvalidLanguageCode) {
EXPECT_EQ(loot_error_invalid_args, loot_eval_lists(db, UINT_MAX));
}
TEST_P(loot_eval_lists_test, shouldReturnOkForAllLanguagesWithNoListsLoaded) {
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_english));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_english));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_spanish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_russian));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_french));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_chinese));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_polish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_brazilian_portuguese));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_finnish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_german));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_danish));
}
TEST_P(loot_eval_lists_test, shouldReturnOKForAllLanguagesWithAMasterlistLoaded) {
ASSERT_NO_THROW(generateMasterlist());
ASSERT_EQ(loot_ok, loot_load_lists(db, masterlistPath.string().c_str(), NULL));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_english));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_english));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_spanish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_russian));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_french));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_chinese));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_polish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_brazilian_portuguese));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_finnish));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_german));
EXPECT_EQ(loot_ok, loot_eval_lists(db, loot_lang_danish));
}
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More