diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c7d0c4e..163892f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,21 +224,29 @@ set (LOOT_GUI_HEADERS "${CMAKE_SOURCE_DIR}/src/gui/loot_handler.h" "${CMAKE_SOURCE_DIR}/src/gui/query_handler.h" "${CMAKE_SOURCE_DIR}/src/gui/resource.h") -set (LOOT_API_SRC "${CMAKE_SOURCE_DIR}/src/api/api.cpp" - "${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp") +set (LOOT_API_SRC "${CMAKE_BINARY_DIR}/generated/loot_version.cpp" + "${CMAKE_SOURCE_DIR}/src/api/api.cpp" + "${CMAKE_SOURCE_DIR}/src/api/api_database.cpp") set (LOOT_API_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h" - "${CMAKE_SOURCE_DIR}/src/api/loot_db.h") + "${CMAKE_SOURCE_DIR}/include/loot/database_interface.h" + "${CMAKE_SOURCE_DIR}/include/loot/game_type.h" + "${CMAKE_SOURCE_DIR}/include/loot/language_code.h" + "${CMAKE_SOURCE_DIR}/include/loot/loot_version.h" + "${CMAKE_SOURCE_DIR}/include/loot/masterlist_info.h" + "${CMAKE_SOURCE_DIR}/include/loot/message_type.h" + "${CMAKE_SOURCE_DIR}/include/loot/plugin_cleanliness.h" + "${CMAKE_SOURCE_DIR}/include/loot/plugin_message.h" + "${CMAKE_SOURCE_DIR}/include/loot/plugin_tags.h" + "${CMAKE_SOURCE_DIR}/src/api/api_database.h") set (LOOT_VALIDATOR_SRC "${CMAKE_SOURCE_DIR}/src/validator/main.cpp") -set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/backend/main.cpp") +set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/tests/backend/main.cpp") set (LOOT_TESTS_HEADERS # Testing this here rather than as part of the API tests # because it tests internal code and requires internal # linking. - "${CMAKE_SOURCE_DIR}/src/tests/api/loot_db_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_paths_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_settings_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_state_test.h" @@ -272,19 +280,9 @@ set (LOOT_TESTS_HEADERS # Testing this here rather than as part of the API tests set(LOOT_API_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/tests/api/main.cpp") set(LOOT_API_TESTS_HEADERS "${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_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/create_database_test.h" + "${CMAKE_SOURCE_DIR}/src/tests/api/database_interface_test.h" + "${CMAKE_SOURCE_DIR}/src/tests/api/is_compatible_test.h" "${CMAKE_SOURCE_DIR}/src/tests/common_game_test_fixture.h") source_group("Header Files\\backend" FILES ${LOOT_HEADERS}) diff --git a/include/loot/api.h b/include/loot/api.h index 49042298..19567456 100644 --- a/include/loot/api.h +++ b/include/loot/api.h @@ -158,30 +158,21 @@ * calling loot_cleanup(). */ -#ifndef LOOT_LOOT_API -#define LOOT_LOOT_API +#ifndef LOOT_API_H +#define LOOT_API_H -#include +#include +#include -#if defined(_MSC_VER) -/* MSVC doesn't support C99, so do the stdbool.h definitions ourselves. - START OF stdbool.h DEFINITIONS. */ -# ifndef __cplusplus -# define bool _Bool -# define true 1 -# define false 0 -# endif -# define __bool_true_false_are_defined 1 -/* END OF stdbool.h DEFINITIONS. */ -#else -# include -#endif +#include "loot/database_interface.h" +#include "loot/game_type.h" +#include "loot/loot_version.h" /* set up dll import/export decorators when compiling the dll on windows, ensure LOOT_EXPORT is defined. clients that use this header do not need to define anything to import the symbols properly. */ -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) # ifdef LOOT_STATIC # define LOOT_API # elif defined LOOT_EXPORT @@ -193,521 +184,59 @@ # define LOOT_API #endif -#ifdef __cplusplus -extern "C" -{ -#endif +namespace loot { +/**@}*/ +/**********************************************************************//** + * @name Version Functions + *************************************************************************/ +/**@{*/ - /**********************************************************************//** - * Types - *************************************************************************/ +/** + * @brief Checks for API compatibility. + * @details Checks whether the loaded API is compatible with the given + * version of the API, abstracting API stability policy away from + * clients. The version numbering used is major.minor.patch. + * @param versionMajor + * The major version number to check. + * @param versionMinor + * The minor version number to check. + * @param versionPatch + * The patch version number to check. + * @returns True if the API versions are compatible, false otherwise. + */ +LOOT_API bool IsCompatible(const unsigned int versionMajor, + const unsigned int versionMinor, + const unsigned int versionPatch); - /** - * @brief A structure that holds all game-specific data used by the API. - * @details Used to keep each game's data independent. Abstracts the - * definition of the API's internal state while still providing - * type safety across the library. Multiple handles can also be - * made for each game, though it should be kept in mind that the - * API is not thread-safe. - */ - typedef struct loot_db loot_db; +/**@}*/ +/**********************************************************************//** + * @name Lifecycle Management Functions + *************************************************************************/ +/**@{*/ - /** - * @brief A structure that holds the type of a message and the message - * string itself. - */ - typedef struct { - /** - * @var type - * The type of the message, specified using one of the message - * type codes. - * @var message - * The message string, which may be formatted using - * [GitHub Flavored Markdown] - * (https://help.github.com/articles/github-flavored-markdown). - */ - unsigned int type; - const char * message; - } loot_message; - - /**********************************************************************//** - * @name Return Codes - * @brief Error codes signify an issue that caused a function to exit - * prematurely. If a function exits prematurely, a reversal of any - * changes made during its execution is attempted before it exits. - *************************************************************************/ - /**@{*/ - - LOOT_API extern const unsigned int loot_ok; /**< The function completed successfully. */ - LOOT_API extern const unsigned int loot_error_liblo_error; /**< There was an error in performing a load order operation. */ - LOOT_API extern const unsigned int loot_error_file_write_fail; /**< A file could not be written to. */ - LOOT_API extern const unsigned int loot_error_parse_fail; /**< There was an error parsing the file. */ - LOOT_API extern const unsigned int loot_error_condition_eval_fail; /**< There was an error evaluating the conditionals in a metadata file. */ - LOOT_API extern const unsigned int loot_error_regex_eval_fail; /**< There was an error evaluating the regular expressions in a metadata file. */ - LOOT_API extern const unsigned int loot_error_no_mem; /**< The API was unable to allocate the required memory. */ - LOOT_API extern const unsigned int loot_error_invalid_args; /**< Invalid arguments were given for the function. */ - LOOT_API extern const unsigned int loot_error_no_tag_map; /**< No Bash Tag map has been generated yet. */ - LOOT_API extern const unsigned int loot_error_path_not_found; /**< A file or folder path could not be found. */ - LOOT_API extern const unsigned int loot_error_no_game_detected; /**< The given game could not be found. */ - LOOT_API extern const unsigned int loot_error_git_error; /**< An error occurred while performing a git operation (updating or getting the masterlist version). */ - LOOT_API extern const unsigned int loot_error_windows_error; /**< An error occurred during a call to the Windows API. */ - LOOT_API extern const unsigned int loot_error_sorting_error; /**< An error occurred while sorting plugins. */ - - /** - * @brief Matches the value of the highest-numbered return code. - * @details Provided in case clients wish to incorporate additional return - * codes in their implementation and desire some method of - * avoiding value conflicts. - */ - LOOT_API extern const unsigned int loot_return_max; - - /**@}*/ - /**********************************************************************//** - * @name Game Codes - * @brief Used with loot_create_db(). - *************************************************************************/ - /**@{*/ - - LOOT_API extern const unsigned int loot_game_tes4; /**< Game code for The Elder Scrolls IV: Oblivion. */ - LOOT_API extern const unsigned int loot_game_tes5; /**< Game code for The Elder Scrolls V: Skyrim. */ - LOOT_API extern const unsigned int loot_game_fo3; /**< Game code for Fallout 3. */ - LOOT_API extern const unsigned int loot_game_fonv; /**< Game code for Fallout: New Vegas. */ - LOOT_API extern const unsigned int loot_game_fo4; /**< Game code for Fallout: New Vegas. */ - - /**@}*/ - /**********************************************************************//** - * @name Message Type Codes - * @brief Used with the loot_message structure. - *************************************************************************/ - /**@{*/ - - LOOT_API extern const unsigned int loot_message_say; /**< Denotes a generic note-type message. */ - LOOT_API extern const unsigned int loot_message_warn; /**< Denotes a warning message. */ - LOOT_API extern const unsigned int loot_message_error; /**< Denotes an error message. */ - - /**@}*/ - /**********************************************************************//** - * @name Message Language Codes - * @brief Used with loot_eval_lists(). - *************************************************************************/ - /**@{*/ - - 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. */ - LOOT_API extern const unsigned int loot_lang_french; /**< Tells the API to preferentially select French messages. */ - LOOT_API extern const unsigned int loot_lang_chinese; /**< Tells the API to preferentially select Chinese messages. */ - LOOT_API extern const unsigned int loot_lang_polish; /**< Tells the API to preferentially select Polish messages. */ - LOOT_API extern const unsigned int loot_lang_brazilian_portuguese; /**< Tells the API to preferentially select Brazilian Portuguese messages. */ - LOOT_API extern const unsigned int loot_lang_finnish; /**< Tells the API to preferentially select Finnish messages. */ - LOOT_API extern const unsigned int loot_lang_german; /**< Tells the API to preferentially select German messages. */ - LOOT_API extern const unsigned int loot_lang_danish; /**< Tells the API to preferentially select Danish messages. */ - LOOT_API extern const unsigned int loot_lang_korean; /**< Tells the API to preferentially select Korean messages. */ - - /**@}*/ - /**********************************************************************//** - * @name Plugin Cleanliness Codes - * @brief Used with loot_get_dirty_info(). - *************************************************************************/ - /**@{*/ - - LOOT_API extern const unsigned int loot_needs_cleaning_no; /**< Denotes that the plugin queried does not need cleaning. */ - LOOT_API extern const unsigned int loot_needs_cleaning_yes; /**< Denotes that the plugin queried needs cleaning. */ - LOOT_API extern const unsigned int loot_needs_cleaning_unknown; /**< Denotes that the API is unable to determine whether or not the plugin queried needs cleaning. */ - - /**@}*/ - /**********************************************************************//** - * @name Error Handling Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Returns the message for the last error or warning encountered. - * @details Outputs a string giving the a message containing the details - * of the last error or warning encountered by a function. Each - * time this function is called, the memory for the previous - * message is freed, so only one error message is available at - * any one time. - * @param message - * A pointer to the error details string outputted by the function. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_error_message(const char ** const message); - - /**@}*/ - /**********************************************************************//** - * @name Version Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Checks for API compatibility. - * @details Checks whether the loaded API is compatible with the given - * version of the API, abstracting API stability policy away from - * clients. The version numbering used is major.minor.patch. - * @param versionMajor - * The major version number to check. - * @param versionMinor - * The minor version number to check. - * @param versionPatch - * The patch version number to check. - * @returns True if the API versions are compatible, false otherwise. - */ - LOOT_API bool loot_is_compatible(const unsigned int versionMajor, - const unsigned int versionMinor, - const unsigned int versionPatch); - - /** - * @brief Gets the API version. - * @details Outputs the major, minor and patch version numbers for the - * loaded API. The version numbering used is major.minor.patch. - * @param versionMajor - * A pointer to the major version number. - * @param versionMinor - * A pointer to the minor version number. - * @param versionPatch - * A pointer to the patch version number. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_version(unsigned int * const versionMajor, - unsigned int * const versionMinor, - unsigned int * const versionPatch); - - /** - * @brief Get the Git revision of the code from which the binary was - * built. - * @param revision - * A pointer to the shortened Git revision ID string. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_build_id(const char ** const revision); - - /**@}*/ - /**********************************************************************//** - * @name Lifecycle Management Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Initialise a new database handle. - * @details Creates a handle for a database, which is then used by all - * database functions. - * @param db - * A pointer to the handle that is created by the function. - * @param clientGame - * A game code for which to create the handle. - * @param gamePath - * The relative or absolute path to the game folder, or `NULL`. - * If `NULL`, the API will attempt to detect the data path of the - * specified game. - * @param gameLocalPath - * The relative or absolute path to the game's folder in - * `%LOCALAPPDATA%`, or `NULL`. If `NULL`, the API will attempt to - * look up the path that `%LOCALAPPDATA%` corresponds to. This - * parameter is provided so that systems lacking that environmental - * variable (eg. Linux) can still use the API. - * @returns A return code. - */ - LOOT_API unsigned int loot_create_db(loot_db ** const db, - const unsigned int clientGame, - const char * const gamePath, - const char * const gameLocalPath); - - /** - * @brief Destroy an existing database handle. - * @details Destroys the given database handle, freeing up memory - * allocated during its use, excluding any memory allocated to - * error messages. - * @param db - * The database handle to destroy. - */ - LOOT_API void loot_destroy_db(loot_db * const db); - - /**@}*/ - /**********************************************************************//** - * @name Database Loading Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Loads the masterlist and userlist from the paths specified. - * @details Can be called multiple times, each time replacing the - * previously-loaded data. - * @param db - * The database the function acts on. - * @param masterlistPath - * A string containing the relative or absolute path to the masterlist - * file that should be loaded. - * @param userlistPath - * A string containing the relative or absolute path to the userlist - * file that should be loaded, or `NULL`. If `NULL`, no userlist will - * be loaded. - * @returns A return code. - */ - LOOT_API unsigned int loot_load_lists(loot_db * const db, - const char * const masterlistPath, - const char * const userlistPath); - - /** - * @brief Evaluates all conditions and regular expression metadata - * entries. - * @details Repeated calls re-evaluate the metadata from scratch. This - * function affects the output of all the database access - * functions. - * @param db - * The database the function acts on. - * @param language - * The language code that is used for message language comparisons. - * @returns A return code. - */ - LOOT_API unsigned int loot_eval_lists(loot_db * const db, - const unsigned int language); - - /**********************************************************************//** - * @name LOOT Functionality Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Calculates a new load order for the game's installed plugins - * (including inactive plugins) and outputs the sorted order. - * @details Pulls metadata from the masterlist and userlist if they are - * loaded, and reads the contents of each plugin. No changes are - * applied to the load order used by the game. This function does - * not load or evaluate the masterlist or userlist. - * @param db - * The database the function acts on. - * @param sortedPlugins - * A pointer to an array of plugin filenames in their sorted load - * order. - * @param numPlugins - * A pointer to the size of the outputted array. - * @returns A return code. - */ - LOOT_API unsigned int loot_sort_plugins(loot_db * const db, - const char * const ** const sortedPlugins, - size_t * const numPlugins); - - /** - * @brief Applies the given load order. - * @param db - * The database the function acts on. - * @param loadOrder - * An array of plugin filenames in the load order to be set. - * @param numPlugins - * The size of the inputted array. - * @returns A return code. - */ - LOOT_API unsigned int loot_apply_load_order(loot_db * const db, - const char * const * const loadOrder, - const size_t numPlugins); - - /** - * @brief Update the given masterlist. - * @details Uses Git to update the given masterlist to a given remote. - * If the masterlist doesn't exist, this will create it. This - * function also initialises a Git repository in the given - * masterlist's parent folder. If the masterlist was not already - * up-to-date, it will be re-loaded, but not re-evaluated. - * - * 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 db - * The database the function acts on. - * @param masterlistPath - * A string containing the relative or absolute path to the masterlist - * file that should be updated. The filename must match the filename - * of the masterlist file in the given remote repository, otherwise it - * will not be updated correctly. Although LOOT itself expects this - * filename to be "masterlist.yaml", the API does not check for any - * specific filename. - * @param remoteURL - * The URL of the remote from which to fetch updates. This can also be - * a relative or absolute path to a local repository. - * @param remoteBranch - * The branch of the remote from which to apply updates. LOOT's - * official masterlists are versioned using separate branches for each - * new version of the masterlist syntax, so if you're using them, - * check their repositories to see which is the latest release branch. - * @param updated - * `true` if the masterlist was updated. `false` if no update was - * necessary, ie. it was already up-to-date. If `true`, the masterlist - * will have been re-loaded, but will need to be re-evaluated - * separately. - * @returns A return code. - */ - LOOT_API unsigned int loot_update_masterlist(loot_db * const db, - const char * const masterlistPath, - const char * const remoteURL, - const char * const remoteBranch, - bool * const updated); - - /** - * @brief Get the given masterlist's revision. - * @details Getting a masterlist's revision is only possible if it is - * found inside a local Git repository. - * @param db - * The database the function acts on. - * @param masterlistPath - * A string containing the relative or absolute path to the masterlist - * file that should be queried. - * @param getShortID - * 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. - * @param revisionID - * A pointer to a string containing the outputted revision hash for - * the masterlist. If the masterlist doesn't exist, or there is no Git - * repository at its location, this will be `NULL`. - * @param revisionDate - * A pointer to a string containing the ISO 8601 formatted revision - * date, ie. YYYY-MM-DD. If the masterlist doesn't exist, or there is - * no Git repository at its location, this will be `NULL`. - * @param isModified - * A pointer to a boolean that is `true` if the masterlist has been - * edited since the outputted revision, or `false` if it is at exactly - * the revision given. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_masterlist_revision(loot_db * const db, - const char * const masterlistPath, - const bool getShortID, - const char ** const revisionID, - const char ** const revisionDate, - bool * const isModified); - - /**@}*/ - /**********************************************************************//** - * @name Database Access Functions - *************************************************************************/ - /**@{*/ - - /** - * @brief Outputs an array of the Bash Tags that are suggested in the - * database. - * @details This function must be called prior to calling - * loot_get_plugin_tags() to ensure that the latter can return - * the Tags using the correct array indicies. - * @param db - * The database the function acts on. - * @param tagMap - * A pointer to the outputted array of Bash Tags. The array functions - * as a map where the indicies are the keys, allowing the API to use - * them as UIDs for Bash Tags instead of passing their names as - * strings every time loot_get_plugin_tags() is called. If no Bash - * Tags are suggested, this will be `NULL`. - * @param numTags - * A pointer to the size of the outputted array. If no Bash Tags are - * suggested, this will be `0`. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_tag_map(loot_db * const db, - const char * const ** const tagMap, - size_t * const numTags); - - /** - * @brief Outputs the Bash Tags suggested for addition and removal by the - * database for the given plugin. - * @details loot_get_tag_map() must be called before this to ensure that - * the Bash Tag UIDs outputted by this function can be matched up - * to name strings. - * @param db - * The database the function acts on. - * @param plugin - * The filename of the plugin to look up Bash Tag suggestions for. - * @param tags_added - * A pointer to the outputted array of UIDs of the Bash Tags suggested - * for addition to the specified plugin. `NULL` if no Bash Tag - * additions are suggested. - * @param numTags_added - * A pointer to the size of the tags_added array. `0` if `tags_added` - * is `NULL`. - * @param tags_removed - * A pointer to the outputted array of UIDs of the Bash Tags suggested - * for removal from the specified plugin. `NULL` if no Bash Tag - * removals are suggested. - * @param numTags_removed - * A pointer to the size of the `tags_removed` array. `0` if - * `tags_removed` is `null`. - * @param userlistModified - * `true` if the Bash Tag suggestions were modified by the data in the - * userlist, `false` otherwise. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_plugin_tags(loot_db * const db, - const char * const plugin, - const unsigned int ** const tags_added, - size_t * const numTags_added, - const unsigned int ** const tags_removed, - size_t * const numTags_removed, - bool * const userlistModified); - - /** - * @brief Outputs the messages associated with the given plugin in the - * database. - * @param db - * The database the function acts on. - * @param plugin - * The filename of the plugin to look up messages for. - * @param messages - * A pointer to the outputted array of messages associated with the - * specified plugin, given as loot_message structures. `NULL` if the - * plugin has no messages associated with it. - * @param numMessages - * A pointer to the size of the outputted array. If no messages are - * outputted, this will be `0`. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_plugin_messages(loot_db * const db, - const char * const plugin, - const loot_message ** const messages, - size_t * const numMessages); - - /** - * @brief Determines the database's knowledge of a plugin's dirtiness. - * @details Outputs whether the plugin should be cleaned or not, or if - * no data is available. The mechanism used to determine that - * a plugin should not be cleaned is not very reliable, and is - * likely to fail if `loot_eval_lists()` was called with a - * language other than English. As such, some plugins that should - * not be cleaned may have the `loot_needs_cleaning_unknown` - * code outputted. - * @param db - * The database the function acts on. - * @param plugin - * The plugin to look up dirty status information for. - * @param needsCleaning - * A pointer to a plugin cleanliness code. - * @returns A return code. - */ - LOOT_API unsigned int loot_get_dirty_info(loot_db * const db, - const char * const plugin, - unsigned int * const needsCleaning); - - /** - * @brief Writes a minimal metadata file that only contains plugins with - * Bash Tag suggestions and/or dirty info, plus the suggestions and - * info themselves. - * @param db - * The database the function acts on. - * @param outputFile - * The path to which the file shall be written. - * @param overwrite - * If `false` and `outputFile` already exists, no data will be - * written. Otherwise, data will be written. - * @returns A return code. - */ - LOOT_API unsigned int loot_write_minimal_list(loot_db * const db, - const char * const outputFile, - const bool overwrite); - - /**@}*/ - -#ifdef __cplusplus +/** + * @brief Initialise a new database handle. + * @details Creates a handle for a database, which is then used by all + * database functions. + * @param db + * A pointer to the handle that is created by the function. + * @param clientGame + * A game code for which to create the handle. + * @param gamePath + * The relative or absolute path to the game folder, or `NULL`. + * If `NULL`, the API will attempt to detect the data path of the + * specified game. + * @param gameLocalPath + * The relative or absolute path to the game's folder in + * `%LOCALAPPDATA%`, or `NULL`. If `NULL`, the API will attempt to + * look up the path that `%LOCALAPPDATA%` corresponds to. This + * parameter is provided so that systems lacking that environmental + * variable (eg. Linux) can still use the API. + * @returns A return code. + */ +LOOT_API std::shared_ptr CreateDatabase(const GameType game, + const std::string& game_path, + const std::string& game_local_path); } -#endif #endif diff --git a/include/loot/database_interface.h b/include/loot/database_interface.h new file mode 100644 index 00000000..37cf1fa8 --- /dev/null +++ b/include/loot/database_interface.h @@ -0,0 +1,270 @@ +/* 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 + . + */ +#ifndef LOOT_DATABASE_INTERFACE +#define LOOT_DATABASE_INTERFACE + +#include +#include + +#include "loot/language_code.h" +#include "loot/masterlist_info.h" +#include "loot/plugin_cleanliness.h" +#include "loot/plugin_message.h" +#include "loot/plugin_tags.h" + +namespace loot { +class DatabaseInterface { +public: + /**********************************************************************//** + * @name Database Loading Functions + *************************************************************************/ + /**@{*/ + + /** + * @brief Loads the masterlist and userlist from the paths specified. + * @details Can be called multiple times, each time replacing the + * previously-loaded data. + * @param masterlist_path + * A string containing the relative or absolute path to the masterlist + * file that should be loaded. + * @param userlist_path + * A string containing the relative or absolute path to the userlist + * file that should be loaded, or `NULL`. If `NULL`, no userlist will + * be loaded. + */ + virtual void LoadLists(const std::string& masterlist_path, + const std::string& userlist_path) = 0; + + /** + * @brief Evaluates all conditions and regular expression metadata + * entries. + * @details Repeated calls re-evaluate the metadata from scratch. This + * function affects the output of all the database access + * functions. + * @param language + * The language code that is used for message language comparisons. + */ + virtual void EvalLists(const LanguageCode language) = 0; + + /**********************************************************************//** + * @name LOOT Functionality Functions + *************************************************************************/ + /**@{*/ + + /** + * @brief Calculates a new load order for the game's installed plugins + * (including inactive plugins) and outputs the sorted order. + * @details Pulls metadata from the masterlist and userlist if they are + * loaded, and reads the contents of each plugin. No changes are + * applied to the load order used by the game. This function does + * not load or evaluate the masterlist or userlist. + * @param db + * The database the function acts on. + * @param sortedPlugins + * A pointer to an array of plugin filenames in their sorted load + * order. + * @param numPlugins + * A pointer to the size of the outputted array. + * @returns A return code. + */ + virtual std::vector SortPlugins() = 0; + + /** + * @brief Applies the given load order. + * @param db + * The database the function acts on. + * @param loadOrder + * An array of plugin filenames in the load order to be set. + * @param numPlugins + * The size of the inputted array. + * @returns A return code. + */ + virtual void ApplyLoadOrder(const std::vector& loadOrder) = 0; + + /** + * @brief Update the given masterlist. + * @details Uses Git to update the given masterlist to a given remote. + * If the masterlist doesn't exist, this will create it. This + * function also initialises a Git repository in the given + * masterlist's parent folder. If the masterlist was not already + * up-to-date, it will be re-loaded, but not re-evaluated. + * + * 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 db + * The database the function acts on. + * @param masterlistPath + * A string containing the relative or absolute path to the masterlist + * file that should be updated. The filename must match the filename + * of the masterlist file in the given remote repository, otherwise it + * will not be updated correctly. Although LOOT itself expects this + * filename to be "masterlist.yaml", the API does not check for any + * specific filename. + * @param remoteURL + * The URL of the remote from which to fetch updates. This can also be + * a relative or absolute path to a local repository. + * @param remoteBranch + * The branch of the remote from which to apply updates. LOOT's + * official masterlists are versioned using separate branches for each + * new version of the masterlist syntax, so if you're using them, + * check their repositories to see which is the latest release branch. + * @param updated + * `true` if the masterlist was updated. `false` if no update was + * necessary, ie. it was already up-to-date. If `true`, the masterlist + * will have been re-loaded, but will need to be re-evaluated + * separately. + * @returns A return code. + */ + virtual bool UpdateMasterlist(const std::string& masterlist_path, + const std::string& remote_url, + const std::string& remote_branch) = 0; + + /** + * @brief Get the given masterlist's revision. + * @details Getting a masterlist's revision is only possible if it is + * found inside a local Git repository. + * @param db + * The database the function acts on. + * @param masterlistPath + * A string containing the relative or absolute path to the masterlist + * file that should be queried. + * @param getShortID + * 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. + * @param revisionID + * A pointer to a string containing the outputted revision hash for + * the masterlist. If the masterlist doesn't exist, or there is no Git + * repository at its location, this will be `NULL`. + * @param revisionDate + * A pointer to a string containing the ISO 8601 formatted revision + * date, ie. YYYY-MM-DD. If the masterlist doesn't exist, or there is + * no Git repository at its location, this will be `NULL`. + * @param isModified + * A pointer to a boolean that is `true` if the masterlist has been + * edited since the outputted revision, or `false` if it is at exactly + * the revision given. + * @returns A return code. + */ + virtual MasterlistInfo GetMasterlistRevision(const std::string& masterlist_path, + const bool get_short_id) = 0; + + /**@}*/ + /**********************************************************************//** + * @name Database Access Functions + *************************************************************************/ + /**@{*/ + + /** + * @brief Outputs the Bash Tags suggested for addition and removal by the + * database for the given plugin. + * @details loot_get_tag_map() must be called before this to ensure that + * the Bash Tag UIDs outputted by this function can be matched up + * to name strings. + * @param db + * The database the function acts on. + * @param plugin + * The filename of the plugin to look up Bash Tag suggestions for. + * @param tags_added + * A pointer to the outputted array of UIDs of the Bash Tags suggested + * for addition to the specified plugin. `NULL` if no Bash Tag + * additions are suggested. + * @param numTags_added + * A pointer to the size of the tags_added array. `0` if `tags_added` + * is `NULL`. + * @param tags_removed + * A pointer to the outputted array of UIDs of the Bash Tags suggested + * for removal from the specified plugin. `NULL` if no Bash Tag + * removals are suggested. + * @param numTags_removed + * A pointer to the size of the `tags_removed` array. `0` if + * `tags_removed` is `null`. + * @param userlistModified + * `true` if the Bash Tag suggestions were modified by the data in the + * userlist, `false` otherwise. + * @returns A return code. + */ + virtual PluginTags GetPluginTags(const std::string& plugin) = 0; + + /** + * @brief Outputs the messages associated with the given plugin in the + * database. + * @param db + * The database the function acts on. + * @param plugin + * The filename of the plugin to look up messages for. + * @param messages + * A pointer to the outputted array of messages associated with the + * specified plugin, given as loot_message structures. `NULL` if the + * plugin has no messages associated with it. + * @param numMessages + * A pointer to the size of the outputted array. If no messages are + * outputted, this will be `0`. + * @returns A return code. + */ + virtual std::vector GetPluginMessages(const std::string& plugin) = 0; + + /** + * @brief Determines the database's knowledge of a plugin's dirtiness. + * @details Outputs whether the plugin should be cleaned or not, or if + * no data is available. The mechanism used to determine that + * a plugin should not be cleaned is not very reliable, and is + * likely to fail if `loot_eval_lists()` was called with a + * language other than English. As such, some plugins that should + * not be cleaned may have the `loot_needs_cleaning_unknown` + * code outputted. + * @param db + * The database the function acts on. + * @param plugin + * The plugin to look up dirty status information for. + * @param needsCleaning + * A pointer to a plugin cleanliness code. + * @returns A return code. + */ + virtual PluginCleanliness GetPluginCleanliness(const std::string& plugin) = 0; + + /** + * @brief Writes a minimal metadata file that only contains plugins with + * Bash Tag suggestions and/or dirty info, plus the suggestions and + * info themselves. + * @param db + * The database the function acts on. + * @param outputFile + * The path to which the file shall be written. + * @param overwrite + * If `false` and `outputFile` already exists, no data will be + * written. Otherwise, data will be written. + * @returns A return code. + */ + virtual void WriteMinimalList(const std::string& outputFile, + const bool overwrite) = 0; + + /**@}*/ +}; +} + +#endif diff --git a/include/loot/masterlist_info.h b/include/loot/masterlist_info.h new file mode 100644 index 00000000..5a88b6f9 --- /dev/null +++ b/include/loot/masterlist_info.h @@ -0,0 +1,37 @@ +/* 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 + . + */ +#ifndef LOOT_MASTERLIST_INFO +#define LOOT_MASTERLIST_INFO + +#include + +namespace loot { +struct MasterlistInfo { + std::string revision_id; + std::string revision_date; + bool is_modified; +}; +} + +#endif diff --git a/include/loot/plugin_cleanliness.h b/include/loot/plugin_cleanliness.h new file mode 100644 index 00000000..14534bc6 --- /dev/null +++ b/include/loot/plugin_cleanliness.h @@ -0,0 +1,36 @@ +/* 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 + . + */ +#ifndef LOOT_PLUGIN_CLEANLINESS +#define LOOT_PLUGIN_CLEANLINESS + +namespace loot { +enum struct PluginCleanliness : unsigned int { + clean, + dirty, + do_not_clean, + unknown, +}; +} + +#endif diff --git a/include/loot/plugin_message.h b/include/loot/plugin_message.h new file mode 100644 index 00000000..fffe8bd0 --- /dev/null +++ b/include/loot/plugin_message.h @@ -0,0 +1,50 @@ +/* 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 + . + */ +#ifndef LOOT_PLUGIN_MESSAGE +#define LOOT_PLUGIN_MESSAGE + +#include "loot/message_type.h" + +namespace loot { +/** + * @brief A structure that holds the type of a message and the message + * string itself. + */ +class PluginMessage { +public: + /** + * @var type + * The type of the message, specified using one of the message + * type codes. + * @var text + * The message string, which may be formatted using + * [GitHub Flavored Markdown] + * (https://help.github.com/articles/github-flavored-markdown). + */ + MessageType type; + std::string text; +}; +} + +#endif diff --git a/include/loot/plugin_tags.h b/include/loot/plugin_tags.h new file mode 100644 index 00000000..2e34c80f --- /dev/null +++ b/include/loot/plugin_tags.h @@ -0,0 +1,38 @@ +/* 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 + . + */ +#ifndef LOOT_PLUGIN_TAGS +#define LOOT_PLUGIN_TAGS + +#include +#include + +namespace loot { +struct PluginTags { + std::set added; + std::set removed; + bool userlist_modified; +}; +} + +#endif diff --git a/src/api/api.cpp b/src/api/api.cpp index a93816c5..140e50bc 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -24,624 +24,36 @@ #include "loot/api.h" -#include -#include -#include -#include - -#include #include -#include #include -#include -#include "api/loot_db.h" +#include "api/api_database.h" #include "backend/error.h" #include "backend/app/loot_paths.h" -#include "backend/app/loot_version.h" -#include "backend/plugin/plugin_sorter.h" -using loot::Error; -using loot::GameType; -using loot::MessageType; -using loot::Language; - -const unsigned int loot_ok = Error::asUnsignedInt(Error::Code::ok); -const unsigned int loot_error_liblo_error = Error::asUnsignedInt(Error::Code::liblo_error); -const unsigned int loot_error_file_write_fail = Error::asUnsignedInt(Error::Code::path_write_fail); -const unsigned int loot_error_parse_fail = Error::asUnsignedInt(Error::Code::path_read_fail); -const unsigned int loot_error_condition_eval_fail = Error::asUnsignedInt(Error::Code::condition_eval_fail); -const unsigned int loot_error_regex_eval_fail = Error::asUnsignedInt(Error::Code::regex_eval_fail); -const unsigned int loot_error_no_mem = Error::asUnsignedInt(Error::Code::no_mem); -const unsigned int loot_error_invalid_args = Error::asUnsignedInt(Error::Code::invalid_args); -const unsigned int loot_error_no_tag_map = Error::asUnsignedInt(Error::Code::no_tag_map); -const unsigned int loot_error_path_not_found = Error::asUnsignedInt(Error::Code::path_not_found); -const unsigned int loot_error_no_game_detected = Error::asUnsignedInt(Error::Code::no_game_detected); -const unsigned int loot_error_git_error = Error::asUnsignedInt(Error::Code::git_error); -const unsigned int loot_error_windows_error = Error::asUnsignedInt(Error::Code::windows_error); -const unsigned int loot_error_sorting_error = Error::asUnsignedInt(Error::Code::sorting_error); -const unsigned int loot_return_max = loot_error_sorting_error; - -// The following are the games identifiers used by the API. -const unsigned int loot_game_tes4 = static_cast(GameType::tes4); -const unsigned int loot_game_tes5 = static_cast(GameType::tes5); -const unsigned int loot_game_fo3 = static_cast(GameType::fo3); -const unsigned int loot_game_fonv = static_cast(GameType::fonv); -const unsigned int loot_game_fo4 = static_cast(GameType::fo4); - -const unsigned int loot_message_say = static_cast(MessageType::say); -const unsigned int loot_message_warn = static_cast(MessageType::warn); -const unsigned int loot_message_error = static_cast(MessageType::error); - -// LOOT message languages. -const unsigned int loot_lang_english = static_cast(Language::Code::english); -const unsigned int loot_lang_spanish = static_cast(Language::Code::spanish); -const unsigned int loot_lang_russian = static_cast(Language::Code::russian); -const unsigned int loot_lang_french = static_cast(Language::Code::french); -const unsigned int loot_lang_chinese = static_cast(Language::Code::chinese); -const unsigned int loot_lang_polish = static_cast(Language::Code::polish); -const unsigned int loot_lang_brazilian_portuguese = static_cast(Language::Code::brazilian_portuguese); -const unsigned int loot_lang_finnish = static_cast(Language::Code::finnish); -const unsigned int loot_lang_german = static_cast(Language::Code::german); -const unsigned int loot_lang_danish = static_cast(Language::Code::danish); -const unsigned int loot_lang_korean = static_cast(Language::Code::korean); - -// LOOT cleanliness codes. -const unsigned int loot_needs_cleaning_no = 0; -const unsigned int loot_needs_cleaning_yes = 1; -const unsigned int loot_needs_cleaning_unknown = 2; - -std::string extMessageStr; - -unsigned int c_error(const Error& e) { - extMessageStr = e.what(); - return e.codeAsUnsignedInt(); -} - -unsigned int c_error(const unsigned int code, const std::string& what) { - return c_error(Error(Error::Code(code), what.c_str())); -} - -////////////////////////////// -// Error Handling Functions -////////////////////////////// - -// Outputs a string giving the details of the last time an error or -// warning return code was returned by a function. The string exists -// until this function is called again or until CleanUpAPI is called. -LOOT_API unsigned int loot_get_error_message(const char ** const message) { - if (message == nullptr) - return c_error(loot_error_invalid_args, "Null message pointer passed."); - - *message = extMessageStr.c_str(); - - return loot_ok; -} - -////////////////////////////// -// Version Functions -////////////////////////////// - -// Returns whether this version of LOOT supports the API from the given -// LOOT version. Abstracts LOOT API stability policy away from clients. -LOOT_API bool loot_is_compatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) { +namespace loot { +LOOT_API bool IsCompatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) { if (versionMajor > 0) return versionMajor == loot::LootVersion::major; else return versionMinor == loot::LootVersion::minor; } -// Returns the version string for this version of LOOT. -// The string exists until this function is called again or until -// CleanUpAPI is called. -LOOT_API unsigned int loot_get_version(unsigned int * const versionMajor, unsigned int * const versionMinor, unsigned int * const versionPatch) { - if (versionMajor == nullptr || versionMinor == nullptr || versionPatch == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - *versionMajor = loot::LootVersion::major; - *versionMinor = loot::LootVersion::minor; - *versionPatch = loot::LootVersion::patch; - - return loot_ok; -} - -LOOT_API unsigned int loot_get_build_id(const char ** const revision) { - if (revision == nullptr) - return c_error(loot_error_invalid_args, "Null message pointer passed."); - - *revision = loot::LootVersion::revision.c_str(); - - return loot_ok; -} - -//////////////////////////////////// -// Lifecycle Management Functions -//////////////////////////////////// - -// Explicitly manage database lifetime. Allows clients to free memory when -// they want/need to. clientGame sets the game the DB is for, and dataPath -// is the path to that game's Data folder, and is case-sensitive if the -// underlying filesystem is case-sensitive. This function also checks that -// plugins.txt and loadorder.txt (if they both exist) are in sync. If -// dataPath == nullptr then the API will attempt to detect the data path of -// the specified game. -LOOT_API unsigned int loot_create_db(loot_db ** const db, - const unsigned int clientGame, - const char * const gamePath, - const char * const gameLocalPath) { - if (db == nullptr - || (clientGame != loot_game_tes4 - && clientGame != loot_game_tes5 - && clientGame != loot_game_fo3 - && clientGame != loot_game_fonv - && clientGame != loot_game_fo4)) - return c_error(loot_error_invalid_args, "Null pointer passed."); - +LOOT_API std::shared_ptr CreateDatabase(const GameType game, + const std::string& gamePath, + const std::string& gameLocalPath) { loot::LootPaths::initialise(); //Disable logging or else stdout will get overrun. boost::log::core::get()->set_logging_enabled(false); - std::string game_path = ""; - if (gamePath != nullptr) - game_path = gamePath; + // Check for valid paths. + if (!gamePath.empty() && !boost::filesystem::is_directory(gamePath)) + throw loot::Error(Error::Code::invalid_args, "Given game path \"" + std::string(gamePath) + "\" is not a valid directory."); - boost::filesystem::path game_local_path = ""; - if (gameLocalPath != nullptr) - game_local_path = gameLocalPath; -#ifndef _WIN32 - else - return c_error(loot_error_invalid_args, "A local data path must be supplied on non-Windows platforms."); -#endif + if (!gameLocalPath.empty() && !boost::filesystem::is_directory(gameLocalPath)) + throw loot::Error(Error::Code::invalid_args, "Given local data path \"" + std::string(gameLocalPath) + "\" is not a valid directory."); - try { - // Check for valid paths. - if (gamePath != nullptr && !boost::filesystem::is_directory(gamePath)) - return c_error(loot_error_invalid_args, "Given game path \"" + std::string(gamePath) + "\" is not a valid directory."); - - if (gameLocalPath != nullptr && !boost::filesystem::is_directory(gameLocalPath)) - return c_error(loot_error_invalid_args, "Given local data path \"" + std::string(gameLocalPath) + "\" is not a valid directory."); - - *db = new loot_db(clientGame, game_path, game_local_path); - } catch (Error& e) { - return c_error(e); - } catch (std::bad_alloc& e) { - return c_error(loot_error_no_mem, e.what()); - } catch (std::exception& e) { - return c_error(loot_error_invalid_args, e.what()); - } - - return loot_ok; + return std::make_shared(game, gamePath, gameLocalPath); } - -// Destroys the given DB, freeing any memory allocated as part of its use. -LOOT_API void loot_destroy_db(loot_db * const db) { - delete db; -} - -/////////////////////////////////// -// Database Loading Functions -/////////////////////////////////// - -// Loads the masterlist and userlist from the paths specified. -// Can be called multiple times. On error, the database is unchanged. -// Paths are case-sensitive if the underlying filesystem is case-sensitive. -// masterlistPath and userlistPath are files. -LOOT_API unsigned int loot_load_lists(loot_db * const db, const char * const masterlistPath, - const char * const userlistPath) { - if (db == nullptr || masterlistPath == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - loot::Masterlist temp; - loot::MetadataList userTemp; - - try { - if (boost::filesystem::exists(masterlistPath)) { - temp.Load(masterlistPath); - } else { - return c_error(loot_error_path_not_found, std::string("The given masterlist path does not exist: ") + masterlistPath); - } - } catch (std::exception& e) { - return c_error(loot_error_parse_fail, e.what()); - } - - try { - if (userlistPath != nullptr) { - if (boost::filesystem::exists(userlistPath)) { - userTemp.Load(userlistPath); - } else { - return c_error(loot_error_path_not_found, std::string("The given userlist path does not exist: ") + userlistPath); - } - } - } catch (YAML::Exception& e) { - return c_error(loot_error_parse_fail, e.what()); - } - - //Also free memory. - db->clearBashTagMap(); - db->clearArrays(); - - db->GetMasterlist() = temp; - db->getUnevaluatedMasterlist() = temp; - db->GetUserlist() = userTemp; - db->getUnevaluatedUserlist() = userTemp; - - return loot_ok; -} - -// Evaluates all conditional lines and regex mods the loaded masterlist. -// This exists so that Load() doesn't need to be called whenever the mods -// installed are changed. Evaluation does not take place unless this function -// is called. Repeated calls re-evaluate the masterlist from scratch each time, -// ignoring the results of any previous evaluations. Paths are case-sensitive -// if the underlying filesystem is case-sensitive. -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_english - && language != loot_lang_spanish - && language != loot_lang_russian - && language != loot_lang_french - && language != loot_lang_chinese - && language != loot_lang_polish - && language != loot_lang_brazilian_portuguese - && language != loot_lang_finnish - && language != loot_lang_german - && language != loot_lang_danish) - return c_error(loot_error_invalid_args, "Invalid language code given."); - -// Clear caches before evaluating conditions. - db->ClearCachedConditions(); - - loot::Masterlist temp = db->getUnevaluatedMasterlist(); - loot::MetadataList userTemp = db->getUnevaluatedUserlist(); - try { - // Refresh active plugins before evaluating conditions. - temp.EvalAllConditions(*db, Language(Language::Code(language)).GetCode()); - userTemp.EvalAllConditions(*db, Language(Language::Code(language)).GetCode()); - } catch (loot::Error& e) { - return c_error(e); - } - db->GetMasterlist() = temp; - db->GetUserlist() = userTemp; - - return loot_ok; -} - -//////////////////////////////////// -// LOOT Functionality Functions -//////////////////////////////////// - -LOOT_API unsigned int loot_sort_plugins(loot_db * const db, - const char * const ** const sortedPlugins, - size_t * const numPlugins) { - if (db == nullptr || sortedPlugins == nullptr || numPlugins == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - -//Initialise output. - *numPlugins = 0; - *sortedPlugins = nullptr; - - try { - // Always reload all the plugins. - db->LoadPlugins(false); - - //Sort plugins into their load order. - loot::PluginSorter sorter; - - db->setPluginNames(sorter.Sort(*db, loot::Language::Code::english)); - } catch (Error &e) { - return c_error(e); - } catch (std::bad_alloc& e) { - return c_error(loot_error_no_mem, e.what()); - } - - if (db->getPluginNames().empty()) - return loot_ok; - - *numPlugins = db->getPluginNames().size(); - *sortedPlugins = &db->getPluginNames()[0]; - - return loot_ok; -} - -LOOT_API unsigned int loot_apply_load_order(loot_db * const db, - const char * const * const loadOrder, - const size_t numPlugins) { - if (db == nullptr || loadOrder == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - try { - db->SetLoadOrder(loadOrder, numPlugins); - } catch (Error &e) { - return c_error(e); - } - - return loot_ok; -} - -LOOT_API unsigned int loot_update_masterlist(loot_db * const db, - const char * const masterlistPath, - const char * const remoteURL, - const char * const remoteBranch, - bool * const updated) { - if (db == nullptr || masterlistPath == nullptr || remoteURL == nullptr || remoteBranch == nullptr || updated == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - if (!boost::filesystem::is_directory(boost::filesystem::path(masterlistPath).parent_path())) - return c_error(loot_error_invalid_args, "Given masterlist path \"" + std::string(masterlistPath) + "\" does not have a valid parent directory."); - - *updated = false; - - try { - loot::Masterlist masterlist; - *updated = masterlist.Update(masterlistPath, remoteURL, remoteBranch); - } catch (Error &e) { - return c_error(e); - } - - return loot_ok; -} - -LOOT_API unsigned int loot_get_masterlist_revision(loot_db * const db, - const char * const masterlistPath, - const bool getShortID, - const char ** const revisionID, - const char ** const revisionDate, - bool * const isModified) { - if (db == nullptr || masterlistPath == nullptr || revisionID == nullptr || revisionDate == nullptr || isModified == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - *revisionID = nullptr; - *revisionDate = nullptr; - *isModified = false; - - bool edited = false; - try { - loot::Masterlist::Info info = loot::Masterlist::GetInfo(masterlistPath, getShortID); - std::string id = info.revision; - std::string date = info.date; - - if (boost::ends_with(id, " (edited)")) { - id = id.substr(0, id.length() - 9); - date = date.substr(0, date.length() - 9); - edited = true; - } - - db->setRevisionIdString(id); - db->setRevisionDateString(date); - } catch (Error &e) { - if (e.code() == Error::Code::ok) - return loot_ok; - else - return c_error(e); - } catch (std::bad_alloc& e) { - return c_error(loot_error_no_mem, e.what()); - } - - *revisionID = db->getRevisionIdString(); - *revisionDate = db->getRevisionDateString(); - *isModified = edited; - - return loot_ok; -} - -////////////////////////// -// DB Access Functions -////////////////////////// - -// Returns an array of the Bash Tags encounterred when loading the masterlist -// and userlist, and the number of tags in the returned array. The array and -// its contents are static and should not be freed by the client. -LOOT_API unsigned int loot_get_tag_map(loot_db * const db, const char * const ** const tagMap, size_t * const numTags) { - if (db == nullptr || tagMap == nullptr || numTags == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - -//Clear existing array allocation. - db->clearBashTagMap(); - - //Initialise output. - *tagMap = nullptr; - *numTags = 0; - - std::set allTags; - - for (const auto &plugin : db->GetMasterlist().Plugins()) { - for (const auto &tag : plugin.Tags()) { - allTags.insert(tag.Name()); - } - } - for (const auto &plugin : db->GetUserlist().Plugins()) { - for (const auto &tag : plugin.Tags()) { - allTags.insert(tag.Name()); - } - } - - if (allTags.empty()) - return loot_ok; - - try { - db->addBashTagsToMap(allTags); - } catch (std::bad_alloc& e) { - return c_error(loot_error_no_mem, e.what()); - } - - *tagMap = &db->getBashTagMap()[0]; - *numTags = db->getBashTagMap().size(); - - return loot_ok; -} - -// Returns arrays of Bash Tag UIDs for Bash Tags suggested for addition and removal -// by LOOT's masterlist and userlist, and the number of tags in each array. -// The returned arrays are valid until the db is destroyed or until the Load -// function is called. The arrays should not be freed by the client. modName is -// case-insensitive. If no Tags are found for an array, the array pointer (*tagIds) -// will be nullptr. The userlistModified bool is true if the userlist contains Bash Tag -// suggestion message additions. -LOOT_API unsigned int loot_get_plugin_tags(loot_db * const db, const char * const plugin, - const unsigned int ** const tagIds_added, - size_t * const numTags_added, - const unsigned int ** const tagIds_removed, - size_t * const numTags_removed, - bool * const userlistModified) { - if (db == nullptr || plugin == nullptr || tagIds_added == nullptr || numTags_added == nullptr || tagIds_removed == nullptr || numTags_removed == nullptr || userlistModified == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - if (db->getBashTagMap().empty()) { - return c_error(loot_error_no_tag_map, "No Bash Tag map has been previously generated."); - } - - //Initialise output. - *tagIds_added = nullptr; - *tagIds_removed = nullptr; - *userlistModified = false; - *numTags_added = 0; - *numTags_removed = 0; - - std::set tagsAdded, tagsRemoved; - loot::PluginMetadata p = db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)); - for (const auto &tag : p.Tags()) { - if (tag.IsAddition()) - tagsAdded.insert(tag.Name()); - else - tagsRemoved.insert(tag.Name()); - } - - p = db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)); - *userlistModified = !p.Tags().empty(); - for (const auto &tag : p.Tags()) { - *userlistModified = true; - if (tag.IsAddition()) - tagsAdded.insert(tag.Name()); - else - tagsRemoved.insert(tag.Name()); - } - - try { - db->setAddedTags(tagsAdded); - db->setRemovedTags(tagsRemoved); - } catch (Error& e) { - return c_error(e); - } - - //Set outputs. - *numTags_added = db->getAddedTagIds().size(); - *numTags_removed = db->getRemovedTagIds().size(); - - if (db->getAddedTagIds().empty()) - *tagIds_added = nullptr; - else - *tagIds_added = reinterpret_cast(&db->getAddedTagIds()[0]); - - if (db->getRemovedTagIds().empty()) - *tagIds_removed = nullptr; - else - *tagIds_removed = reinterpret_cast(&db->getRemovedTagIds()[0]); - - return loot_ok; -} - -// Returns the messages attached to the given plugin. Messages are valid until Load, -// loot_destroy_db or loot_get_plugin_messages are next called. plugin is case-insensitive. -// If no messages are attached, *messages will be nullptr and numMessages will equal 0. -LOOT_API unsigned int loot_get_plugin_messages(loot_db * const db, const char * const plugin, - const loot_message ** const messages, - size_t * const numMessages) { - if (db == nullptr || plugin == nullptr || messages == nullptr || numMessages == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - -//Initialise output. - *messages = nullptr; - *numMessages = 0; - - loot::PluginMetadata p = db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)); - std::list pluginMessages(p.Messages()); - - p = db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)); - std::list temp(p.Messages()); - pluginMessages.insert(pluginMessages.end(), temp.begin(), temp.end()); - - if (pluginMessages.empty()) - return loot_ok; - - db->setPluginMessages(pluginMessages); - - *messages = &db->getPluginMessages()[0]; - *numMessages = db->getPluginMessages().size(); - - return loot_ok; -} - -LOOT_API unsigned int loot_get_dirty_info(loot_db * const db, const char * const plugin, unsigned int * const needsCleaning) { - if (db == nullptr || plugin == nullptr || needsCleaning == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - *needsCleaning = loot_needs_cleaning_unknown; - - // Is there any dirty info? Testing for applicability happens in loot_eval_lists(). - if (!db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty() - || !db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty()) { - *needsCleaning = loot_needs_cleaning_yes; - } - - // Is there a message beginning with the substring "Do not clean."? - // This isn't a very reliable system, because if the lists have been evaluated in some language - // other than English, the strings will be in different languages (and the API can't tell what they'd be) - // and the strings may be non-standard and begin with something other than "Do not clean." anyway. - std::list messages(db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)).Messages()); - - std::list temp(db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)).Messages()); - messages.insert(messages.end(), temp.begin(), temp.end()); - - for (const auto& message : messages) { - if (boost::starts_with(message.GetText(), "Do not clean")) { - *needsCleaning = loot_needs_cleaning_no; - break; - } - } - - return loot_ok; -} - -// Writes a minimal masterlist that only contains mods that have Bash Tag suggestions, -// and/or dirty messages, plus the Tag suggestions and/or messages themselves and their -// conditions, in order to create the Wrye Bash taglist. outputFile is the path to use -// for output. If outputFile already exists, it will only be overwritten if overwrite is true. -LOOT_API unsigned int loot_write_minimal_list(loot_db * const db, const char * const outputFile, const bool overwrite) { - if (db == nullptr || outputFile == nullptr) - return c_error(loot_error_invalid_args, "Null pointer passed."); - - if (!boost::filesystem::exists(boost::filesystem::path(outputFile).parent_path())) - return c_error(loot_error_invalid_args, "Output directory does not exist."); - - if (boost::filesystem::exists(outputFile) && !overwrite) - return c_error(loot_error_file_write_fail, "Output file exists but overwrite is not set to true."); - - loot::Masterlist temp = db->GetMasterlist(); - std::unordered_set minimalPlugins; - for (const auto &plugin : temp.Plugins()) { - loot::PluginMetadata p(plugin.Name()); - p.Tags(plugin.Tags()); - p.DirtyInfo(plugin.DirtyInfo()); - minimalPlugins.insert(p); - } - - YAML::Emitter yout; - yout.SetIndent(2); - yout << YAML::BeginMap - << YAML::Key << "plugins" << YAML::Value << minimalPlugins - << YAML::EndMap; - - boost::filesystem::path p(outputFile); - try { - boost::filesystem::ofstream out(p); - if (out.fail()) - return c_error(loot_error_file_write_fail, "Couldn't open output file."); - out << yout.c_str(); - out.close(); - } catch (std::exception& e) { - return c_error(loot_error_file_write_fail, e.what()); - } - - return loot_ok; } diff --git a/src/api/api_database.cpp b/src/api/api_database.cpp new file mode 100644 index 00000000..58d6cc13 --- /dev/null +++ b/src/api/api_database.cpp @@ -0,0 +1,255 @@ +/* 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 + . + */ + +#include "api/api_database.h" + +#include +#include + +#include "backend/error.h" +#include "backend/game/game.h" +#include "backend/plugin/plugin_sorter.h" + +namespace loot { +ApiDatabase::ApiDatabase(const GameType game, const std::string& gamePath, const std::string& gameLocalDataPath) + : game_(Game(GameType(game))) { + game_.SetGamePath(gamePath); + game_.Init(false, gameLocalDataPath); +} + +/////////////////////////////////// +// Database Loading Functions +/////////////////////////////////// + +void ApiDatabase::LoadLists(const std::string& masterlistPath, + const std::string& userlistPath) { + Masterlist temp; + MetadataList userTemp; + + if (boost::filesystem::exists(masterlistPath)) { + temp.Load(masterlistPath); + } else { + throw Error(Error::Code::path_not_found, std::string("The given masterlist path does not exist: ") + masterlistPath); + } + + if (!userlistPath.empty()) { + if (boost::filesystem::exists(userlistPath)) { + userTemp.Load(userlistPath); + } else { + throw Error(Error::Code::path_not_found, std::string("The given userlist path does not exist: ") + userlistPath); + } + } + + game_.GetMasterlist() = temp; + unevaluatedMasterlist_ = temp; + game_.GetUserlist() = userTemp; + unevaluatedUserlist_ = userTemp; +} + +void ApiDatabase::EvalLists(const LanguageCode language) { + // Clear caches before evaluating conditions. + game_.ClearCachedConditions(); + + Masterlist temp = unevaluatedMasterlist_; + MetadataList userTemp = unevaluatedUserlist_; + + // Refresh active plugins before evaluating conditions. + temp.EvalAllConditions(game_, Language(LanguageCode(language)).GetCode()); + userTemp.EvalAllConditions(game_, Language(LanguageCode(language)).GetCode()); + + game_.GetMasterlist() = temp; + game_.GetUserlist() = userTemp; +} + +//////////////////////////////////// +// LOOT Functionality Functions +//////////////////////////////////// + +std::vector ApiDatabase::SortPlugins() { + // Always reload all the plugins. + game_.LoadPlugins(false); + + //Sort plugins into their load order. + PluginSorter sorter; + auto list = sorter.Sort(game_, LanguageCode::english); + + std::vector loadOrder(list.size()); + std::transform(begin(list), end(list), begin(loadOrder), [](const Plugin& plugin) { + return plugin.Name(); + }); + + return loadOrder; +} + +void ApiDatabase::ApplyLoadOrder(const std::vector& loadOrder) { + game_.SetLoadOrder(loadOrder); +} + +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())) + throw Error(Error::Code::invalid_args, "Given masterlist path \"" + std::string(masterlistPath) + "\" does not have a valid parent directory."); + + Masterlist masterlist; + return masterlist.Update(masterlistPath, remoteURL, remoteBranch); +} + +MasterlistInfo ApiDatabase::GetMasterlistRevision(const std::string& masterlistPath, + const bool getShortID) { + MasterlistInfo apiMasterlistInfo; + apiMasterlistInfo.is_modified = false; + try { + Masterlist::Info info = Masterlist::GetInfo(masterlistPath, getShortID); + + if (boost::ends_with(info.revision, " (edited)")) { + apiMasterlistInfo.revision_id = info.revision.substr(0, info.revision.length() - 9); + apiMasterlistInfo.revision_date = info.date.substr(0, info.date.length() - 9); + apiMasterlistInfo.is_modified = true; + } else { + apiMasterlistInfo.revision_id = info.revision; + apiMasterlistInfo.revision_date = info.date; + apiMasterlistInfo.is_modified = false; + } + } catch (Error &e) { + if (e.code() != Error::Code::ok) + throw; + } + + return apiMasterlistInfo; +} + +////////////////////////// +// DB Access Functions +////////////////////////// + +PluginTags ApiDatabase::GetPluginTags(const std::string& plugin) { + PluginTags tags; + + PluginMetadata pluginMetadata = game_.GetMasterlist().FindPlugin(PluginMetadata(plugin)); + for (const auto &tag : pluginMetadata.Tags()) { + if (tag.IsAddition()) + tags.added.insert(tag.Name()); + else + tags.removed.insert(tag.Name()); + } + + pluginMetadata = game_.GetUserlist().FindPlugin(PluginMetadata(plugin)); + tags.userlist_modified = !pluginMetadata.Tags().empty(); + for (const auto &tag : pluginMetadata.Tags()) { + if (tag.IsAddition()) + tags.added.insert(tag.Name()); + else + tags.removed.insert(tag.Name()); + } + + return tags; +} + +std::vector ApiDatabase::GetPluginMessages(const std::string& plugin) { + std::vector messages; + + PluginMetadata pluginMetadata = game_.GetMasterlist().FindPlugin(PluginMetadata(plugin)); + for (const auto& message : pluginMetadata.Messages()) { + PluginMessage pluginMessage; + pluginMessage.type = message.GetType(); + pluginMessage.text = message.GetText(); + messages.push_back(pluginMessage); + } + + pluginMetadata = game_.GetUserlist().FindPlugin(PluginMetadata(plugin)); + for (const auto& message : pluginMetadata.Messages()) { + PluginMessage pluginMessage; + pluginMessage.type = message.GetType(); + pluginMessage.text = message.GetText(); + messages.push_back(pluginMessage); + } + + return messages; +} + +PluginCleanliness ApiDatabase::GetPluginCleanliness(const std::string& plugin) { + // Is there any dirty info? Testing for applicability happens in loot_eval_lists(). + if (!game_.GetMasterlist().FindPlugin(PluginMetadata(plugin)).DirtyInfo().empty() + || !game_.GetUserlist().FindPlugin(PluginMetadata(plugin)).DirtyInfo().empty()) { + return PluginCleanliness::dirty; + } + + // Is there a message beginning with the substring "Do not clean."? + // This isn't a very reliable system, because if the lists have been evaluated in some language + // other than English, the strings will be in different languages (and the API can't tell what they'd be) + // and the strings may be non-standard and begin with something other than "Do not clean." anyway. + std::list messages(game_.GetMasterlist().FindPlugin(PluginMetadata(plugin)).Messages()); + + for (const auto& message : messages) { + if (boost::starts_with(message.GetText(), "Do not clean")) { + return PluginCleanliness::do_not_clean; + } + } + + messages = game_.GetUserlist().FindPlugin(PluginMetadata(plugin)).Messages(); + + for (const auto& message : messages) { + if (boost::starts_with(message.GetText(), "Do not clean")) { + return PluginCleanliness::do_not_clean; + } + } + + return PluginCleanliness::unknown; +} + +// Writes a minimal masterlist that only contains mods that have Bash Tag suggestions, +// and/or dirty messages, plus the Tag suggestions and/or messages themselves and their +// conditions, in order to create the Wrye Bash taglist. outputFile is the path to use +// for output. If outputFile already exists, it will only be overwritten if overwrite is true. +void ApiDatabase::WriteMinimalList(const std::string& outputFile, const bool overwrite) { + if (!boost::filesystem::exists(boost::filesystem::path(outputFile).parent_path())) + throw Error(Error::Code::invalid_args, "Output directory does not exist."); + + if (boost::filesystem::exists(outputFile) && !overwrite) + throw Error(Error::Code::path_write_fail, "Output file exists but overwrite is not set to true."); + + Masterlist temp = game_.GetMasterlist(); + std::unordered_set minimalPlugins; + for (const auto &plugin : temp.Plugins()) { + PluginMetadata p(plugin.Name()); + p.Tags(plugin.Tags()); + p.DirtyInfo(plugin.DirtyInfo()); + minimalPlugins.insert(p); + } + + YAML::Emitter yout; + yout.SetIndent(2); + yout << YAML::BeginMap + << YAML::Key << "plugins" << YAML::Value << minimalPlugins + << YAML::EndMap; + + boost::filesystem::path p(outputFile); + boost::filesystem::ofstream out(p); + if (out.fail()) + throw Error(Error::Code::path_write_fail, "Couldn't open output file."); + out << yout.c_str(); + out.close(); +} +} diff --git a/src/api/api_database.h b/src/api/api_database.h new file mode 100644 index 00000000..e9357700 --- /dev/null +++ b/src/api/api_database.h @@ -0,0 +1,73 @@ +/* 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 + . + */ + +#ifndef LOOT_API_LOOT_DB +#define LOOT_API_LOOT_DB + +#include +#include +#include + +#include "backend/game/game.h" +#include "loot/database_interface.h" + +namespace loot { +struct ApiDatabase : public DatabaseInterface { + ApiDatabase(const GameType clientGame, + const std::string& gamePath, + const std::string& gameLocalDataPath); + + void LoadLists(const std::string& masterlist_path, + const std::string& userlist_path); + + void EvalLists(const LanguageCode language); + + std::vector SortPlugins(); + + void ApplyLoadOrder(const std::vector& loadOrder); + + bool UpdateMasterlist(const std::string& masterlist_path, + const std::string& remote_url, + const std::string& remote_branch); + + MasterlistInfo GetMasterlistRevision(const std::string& masterlist_path, + const bool get_short_id); + + PluginTags GetPluginTags(const std::string& plugin); + + std::vector GetPluginMessages(const std::string& plugin); + + PluginCleanliness GetPluginCleanliness(const std::string& plugin); + + void WriteMinimalList(const std::string& outputFile, + const bool overwrite); +private: + Game game_; + + Masterlist unevaluatedMasterlist_; + MetadataList unevaluatedUserlist_; +}; +} + +#endif diff --git a/src/api/loot_db.cpp b/src/api/loot_db.cpp deleted file mode 100644 index d4d786de..00000000 --- a/src/api/loot_db.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* 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 - . - */ - -#include "api/loot_db.h" - -#include "backend/error.h" - -loot_db::loot_db(const unsigned int clientGame, const std::string& gamePath, const boost::filesystem::path& gameLocalDataPath) - : Game(loot::GameType(clientGame)) { - this->SetGamePath(gamePath); - this->Init(false, gameLocalDataPath); -} - -loot::Masterlist& loot_db::getUnevaluatedMasterlist() { - return unevaluatedMasterlist_; -} - -loot::MetadataList& loot_db::getUnevaluatedUserlist() { - return unevaluatedUserlist_; -} - -const char * loot_db::getRevisionIdString() const { - return revisionId.c_str(); -} - -const char * loot_db::getRevisionDateString() const { - return revisionDate.c_str(); -} - -const std::vector& loot_db::getPluginNames() const { - return cPluginNames; -} - -const std::vector& loot_db::getBashTagMap() const { - return cBashTagMap; -} - -unsigned int loot_db::getBashTagUid(const std::string& name) const { - auto it = bashTagMap.find(name); - if (it != end(bashTagMap)) - return it->second; - - throw loot::Error(loot::Error::Code::no_tag_map, "The Bash Tag \"" + name + "\" does not exist in the Bash Tag map."); -} - -const std::vector& loot_db::getAddedTagIds() const { - return addedTagIds; -} - -const std::vector& loot_db::getRemovedTagIds() const { - return removedTagIds; -} - -const std::vector& loot_db::getPluginMessages() const { - return cPluginMessages; -} - -void loot_db::setRevisionIdString(const std::string& str) { - revisionId = str; -} - -void loot_db::setRevisionDateString(const std::string& str) { - revisionDate = str; -} - -void loot_db::setAddedTags(const std::set& names) { - addedTagIds.clear(); - for (const auto& name : names) - addedTagIds.push_back(getBashTagUid(name)); -} - -void loot_db::setRemovedTags(const std::set& names) { - removedTagIds.clear(); - for (const auto& name : names) - removedTagIds.push_back(getBashTagUid(name)); -} - -void loot_db::setPluginMessages(const std::list& pluginMessages) { - cPluginMessages.resize(pluginMessages.size()); - pluginMessageStrings.resize(pluginMessages.size()); - - size_t i = 0; - for (const auto& message : pluginMessages) { - pluginMessageStrings[i] = message.GetText(); - - cPluginMessages[i].type = static_cast(message.GetType()); - cPluginMessages[i].message = pluginMessageStrings[i].c_str(); - - ++i; - } -} - -void loot_db::addBashTagsToMap(std::set names) { - for (const auto& name : names) { - // Try adding the Bash Tag to the map assuming it's not already in - // there, then use the UID in the returned value, as that will be - // equal to the value in the map, even if the Bash Tag was already - // present. - unsigned int uid = bashTagMap.size(); - // If the tag already exists in the map, do - auto it = bashTagMap.emplace(name, uid).first; - if (it->second == cBashTagMap.size()) - cBashTagMap.push_back(it->first.c_str()); - else - cBashTagMap.at(it->second) = it->first.c_str(); - } -} - -void loot_db::clearBashTagMap() { - bashTagMap.clear(); - cBashTagMap.clear(); -} - -void loot_db::clearArrays() { - pluginNames.clear(); - cPluginNames.clear(); - - addedTagIds.clear(); - removedTagIds.clear(); - - cPluginMessages.clear(); - pluginMessageStrings.clear(); -} diff --git a/src/api/loot_db.h b/src/api/loot_db.h deleted file mode 100644 index 409a2930..00000000 --- a/src/api/loot_db.h +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 - . - */ - -#ifndef LOOT_API_LOOT_DB -#define LOOT_API_LOOT_DB - -#include -#include - -#include "backend/game/game.h" -#include "loot/api.h" - -struct loot_db : public loot::Game { - loot_db(const unsigned int clientGame, - const std::string& gamePath, - const boost::filesystem::path& gameLocalDataPath); - - loot::Masterlist& getUnevaluatedMasterlist(); - loot::MetadataList& getUnevaluatedUserlist(); - - const char * getRevisionIdString() const; - const char * getRevisionDateString() const; - - const std::vector& getPluginNames() const; - - const std::vector& getBashTagMap() const; - unsigned int getBashTagUid(const std::string& name) const; - - const std::vector& getAddedTagIds() const; - const std::vector& getRemovedTagIds() const; - - const std::vector& getPluginMessages() const; - - void setRevisionIdString(const std::string& str); - void setRevisionDateString(const std::string& str); - - template - void setPluginNames(const T& plugins) { - // First take copies of the C++ strings to store. - pluginNames.resize(plugins.size()); - std::transform(begin(plugins), - end(plugins), - begin(pluginNames), - [](const loot::PluginMetadata& plugin) { - return plugin.Name(); - }); - - // Now store their C strings. - cPluginNames.resize(pluginNames.size()); - std::transform(begin(pluginNames), - end(pluginNames), - begin(cPluginNames), - [](const std::string& pluginName) { - return pluginName.c_str(); - }); - } - - void setAddedTags(const std::set& names); - void setRemovedTags(const std::set& names); - - void setPluginMessages(const std::list& pluginMessages); - - void addBashTagsToMap(std::set names); - - void clearBashTagMap(); - void clearArrays(); -private: - loot::Masterlist unevaluatedMasterlist_; - loot::MetadataList unevaluatedUserlist_; - - std::string revisionId; - std::string revisionDate; - - std::vector pluginNames; - std::vector cPluginNames; - - // For the Bash Tag map, a string is mapped to a UID that is also the - // index of the vector where the C string can be found. - std::unordered_map bashTagMap; - std::vector cBashTagMap; - - std::vector addedTagIds; - std::vector removedTagIds; - - std::vector cPluginMessages; - std::vector pluginMessageStrings; -}; - -#endif diff --git a/src/tests/api/api_game_operations_test.h b/src/tests/api/api_game_operations_test.h index 25c31bbb..dada5b36 100644 --- a/src/tests/api/api_game_operations_test.h +++ b/src/tests/api/api_game_operations_test.h @@ -32,11 +32,11 @@ along with LOOT. If not, see namespace loot { namespace test { class ApiGameOperationsTest : - public ::testing::TestWithParam, + public ::testing::TestWithParam, public CommonGameTestFixture { protected: ApiGameOperationsTest() : - CommonGameTestFixture(GetParam()), + CommonGameTestFixture(static_cast(GetParam())), db_(nullptr), masterlistPath(localPath / "masterlist.yaml"), noteMessage("Do not clean ITM records, they are intentional and required for the mod to function."), @@ -48,14 +48,12 @@ protected: 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())); + db_ = CreateDatabase(GetParam(), dataPath.parent_path().string(), localPath.string()); } virtual void TearDown() { 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)); } @@ -109,7 +107,7 @@ protected: masterlist.close(); } - loot_db * db_; + std::shared_ptr db_; const boost::filesystem::path masterlistPath; diff --git a/src/tests/api/create_database_test.h b/src/tests/api/create_database_test.h new file mode 100644 index 00000000..1f512bef --- /dev/null +++ b/src/tests/api/create_database_test.h @@ -0,0 +1,96 @@ +/* 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 +. +*/ + +#ifndef LOOT_TESTS_API_CREATE_DATABASE_TEST +#define LOOT_TESTS_API_CREATE_DATABASE_TEST + +#include "loot/api.h" + +#include + +#include "tests/common_game_test_fixture.h" + +namespace loot { +namespace test { +class CreateDatabaseTest : + public ::testing::TestWithParam, + public CommonGameTestFixture { +protected: + CreateDatabaseTest() : + CommonGameTestFixture(static_cast(GetParam())), + db_(nullptr) {} + + void SetUp() { + setUp(); + } + + void TearDown() { + tearDown(); + } + + std::shared_ptr 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(, + CreateDatabaseTest, + ::testing::Values( + GameType::tes4, + GameType::tes5, + GameType::fo3, + GameType::fonv, + GameType::fo4)); + +TEST_P(CreateDatabaseTest, shouldSucceedIfPassedValidParametersWithRelativePaths) { + EXPECT_NO_THROW(db_ = CreateDatabase(GetParam(), dataPath.parent_path().string(), localPath.string())); + EXPECT_NE(nullptr, db_); +} + +TEST_P(CreateDatabaseTest, shouldSucceedIfPassedValidParametersWithAbsolutePaths) { + boost::filesystem::path game = boost::filesystem::current_path() / dataPath.parent_path(); + boost::filesystem::path local = boost::filesystem::current_path() / localPath; + + EXPECT_NO_THROW(db_ = CreateDatabase(GetParam(), dataPath.parent_path().string(), localPath.string())); + EXPECT_NE(nullptr, db_); +} + +TEST_P(CreateDatabaseTest, shouldThrowIfPassedAGamePathThatDoesNotExist) { + EXPECT_ANY_THROW(CreateDatabase(GetParam(), missingPath.string(), localPath.string())); +} + +TEST_P(CreateDatabaseTest, shouldThrowIfPassedALocalPathThatDoesNotExist) { + EXPECT_ANY_THROW(CreateDatabase(GetParam(), dataPath.parent_path().string(), missingPath.string())); +} + +#ifdef _WIN32 +TEST_P(CreateDatabaseTest, shouldReturnOkIfPassedAnEmptyLocalPathString) { + EXPECT_NO_THROW(db_ = CreateDatabase(GetParam(), dataPath.parent_path().string(), "")); + EXPECT_NE(nullptr, db_); +} +#endif +} +} + +#endif diff --git a/src/tests/api/database_interface_test.h b/src/tests/api/database_interface_test.h new file mode 100644 index 00000000..0636e3ed --- /dev/null +++ b/src/tests/api/database_interface_test.h @@ -0,0 +1,485 @@ +/* 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 +. +*/ + +#ifndef LOOT_TESTS_API_DATABASE_INTERFACE_TEST +#define LOOT_TESTS_API_DATABASE_INTERFACE_TEST + +#include "loot/api.h" + +#include "tests/api/api_game_operations_test.h" + +namespace loot { +namespace test { +class DatabaseInterfaceTest : public ApiGameOperationsTest { +protected: + DatabaseInterfaceTest() : + userlistPath_(localPath / "userlist.yaml"), + url_("https://github.com/loot/testing-metadata.git"), + branch_("2.x"), + minimalOutputPath_(localPath / "minimal.yml") {} + + void SetUp() { + ApiGameOperationsTest::SetUp(); + + ASSERT_FALSE(boost::filesystem::exists(minimalOutputPath_)); + } + + void TearDown() { + if (boost::filesystem::exists(minimalOutputPath_)) { + boost::filesystem::permissions(minimalOutputPath_, + boost::filesystem::perms::add_perms + | boost::filesystem::perms::owner_write); + } + + ApiGameOperationsTest::TearDown(); + + // The userlist may have been created during the test, so delete it. + ASSERT_NO_THROW(boost::filesystem::remove(userlistPath_)); + + // Also remove the ".git" folder if it has been created. + ASSERT_NO_THROW(boost::filesystem::remove_all(masterlistPath.parent_path() / ".git")); + + ASSERT_NO_THROW(boost::filesystem::remove(minimalOutputPath_)); + } + + std::string GetExpectedMinimalContent() const { + using std::endl; + + std::stringstream expectedContent; + expectedContent + << "plugins:" << endl + << " - name: '" << blankEsm << "'" << endl + << " tag:" << endl + << " - Actors.ACBS" << endl + << " - Actors.AIData" << endl + << " - -C.Water" << endl + << " - name: '" << blankDifferentEsm << "'" << endl + << " dirty:" << endl + << " - crc: 0x7d22f9df" << endl + << " utility: 'TES4Edit'" << endl + << " udr: 4"; + + return expectedContent.str(); + } + + const boost::filesystem::path userlistPath_; + const boost::filesystem::path minimalOutputPath_; + const std::string url_; + const std::string branch_; +}; + +// 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(, + DatabaseInterfaceTest, + ::testing::Values( + GameType::tes4, + GameType::tes5, + GameType::fo3, + GameType::fonv, + GameType::fo4)); + +TEST_P(DatabaseInterfaceTest, loadListsShouldThrowIfNoMasterlistIsPresent) { + EXPECT_ANY_THROW(db_->LoadLists(masterlistPath.string(), "")); +} + +TEST_P(DatabaseInterfaceTest, loadListsShouldThrowIfAMasterlistIsPresentButAUserlistDoesNotExistAtTheGivenPath) { + ASSERT_NO_THROW(GenerateMasterlist()); + EXPECT_ANY_THROW(db_->LoadLists(masterlistPath.string(), userlistPath_.string())); +} + +TEST_P(DatabaseInterfaceTest, loadListsShouldSucceedIfTheMasterlistIsPresentAndTheUserlistPathIsAnEmptyString) { + ASSERT_NO_THROW(GenerateMasterlist()); + + EXPECT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); +} + +TEST_P(DatabaseInterfaceTest, loadListsShouldSucceedIfTheMasterlistAndUserlistAreBothPresent) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(boost::filesystem::copy(masterlistPath, userlistPath_)); + + EXPECT_NO_THROW(db_->LoadLists(masterlistPath.string(), userlistPath_.string())); +} + +TEST_P(DatabaseInterfaceTest, evalListsShouldReturnOkForAllLanguagesWithNoListsLoaded) { + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::english)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::english)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::spanish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::russian)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::french)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::chinese)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::polish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::brazilian_portuguese)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::finnish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::german)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::danish)); +} + +TEST_P(DatabaseInterfaceTest, evalListsShouldReturnOKForAllLanguagesWithAMasterlistLoaded) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::english)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::english)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::spanish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::russian)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::french)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::chinese)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::polish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::brazilian_portuguese)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::finnish)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::german)); + EXPECT_NO_THROW(db_->EvalLists(LanguageCode::danish)); +} + +TEST_P(DatabaseInterfaceTest, sortPluginsShouldSucceedIfPassedValidArguments) { + std::vector expectedOrder = { + masterFile, + blankEsm, + blankMasterDependentEsm, + blankDifferentEsm, + blankDifferentMasterDependentEsm, + blankMasterDependentEsp, + blankDifferentMasterDependentEsp, + blankEsp, + blankPluginDependentEsp, + blankDifferentEsp, + blankDifferentPluginDependentEsp, + }; + + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + std::vector actualOrder = db_->SortPlugins(); + + ASSERT_EQ(expectedOrder, actualOrder); +} + +TEST_P(DatabaseInterfaceTest, applyLoadOrderShouldReturnOkIfLoadOrderGivenIsNotEmpty) { + std::vector loadOrder = { + masterFile, + blankEsm, + blankMasterDependentEsm, + blankDifferentEsm, + blankDifferentMasterDependentEsm, + blankMasterDependentEsp, + blankDifferentMasterDependentEsp, + blankEsp, + blankPluginDependentEsp, + blankDifferentEsp, + blankDifferentPluginDependentEsp, + }; + + EXPECT_NO_THROW(db_->ApplyLoadOrder(loadOrder)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAnInvalidArgsErrorIfTheMasterlistPathGivenIsInvalid) { + EXPECT_ANY_THROW(db_->UpdateMasterlist(";//\?", url_, branch_)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAnInvalidArgsErrorIfTheMasterlistPathGivenIsEmpty) { + EXPECT_ANY_THROW(db_->UpdateMasterlist("", url_, branch_)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAGitErrorIfTheRepositoryUrlGivenCannotBeFound) { + EXPECT_ANY_THROW(db_->UpdateMasterlist(masterlistPath.string(), "https://github.com/loot/oblivion-does-not-exist.git", branch_)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAnInvalidArgsErrorIfTheRepositoryUrlGivenIsEmpty) { + EXPECT_ANY_THROW(db_->UpdateMasterlist(masterlistPath.string(), "", branch_)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAGitErrorIfTheRepositoryBranchGivenCannotBeFound) { + EXPECT_ANY_THROW(db_->UpdateMasterlist(masterlistPath.string(), url_, "missing-branch")); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldReturnAnInvalidArgsErrorIfTheRepositoryBranchGivenIsEmpty) { + EXPECT_ANY_THROW(db_->UpdateMasterlist(masterlistPath.string(), url_, "")); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldSucceedIfPassedValidParametersAndOutputTrueIfTheMasterlistWasUpdated) { + bool updated = false; + EXPECT_NO_THROW(updated = db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + EXPECT_TRUE(updated); + EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); +} + +TEST_P(DatabaseInterfaceTest, updateMasterlistShouldSucceedIfCalledRepeatedlyButOnlyOutputTrueForTheFirstCall) { + bool updated = false; + EXPECT_NO_THROW(updated = db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + EXPECT_TRUE(updated); + + EXPECT_NO_THROW(updated = db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + EXPECT_FALSE(updated); + EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); +} + +TEST_P(DatabaseInterfaceTest, getMasterlistRevisionShouldSucceedIfNoMasterlistIsPresent) { + MasterlistInfo info; + EXPECT_NO_THROW(info = db_->GetMasterlistRevision(masterlistPath.string(), false)); + EXPECT_TRUE(info.revision_id.empty()); + EXPECT_TRUE(info.revision_date.empty()); + EXPECT_FALSE(info.is_modified); +} + +TEST_P(DatabaseInterfaceTest, getMasterlistRevisionShouldSucceedIfANonVersionControlledMasterlistIsPresent) { + ASSERT_NO_THROW(GenerateMasterlist()); + + MasterlistInfo info; + EXPECT_NO_THROW(info = db_->GetMasterlistRevision(masterlistPath.string(), false)); + EXPECT_TRUE(info.revision_id.empty()); + EXPECT_TRUE(info.revision_date.empty()); + EXPECT_FALSE(info.is_modified); +} + +TEST_P(DatabaseInterfaceTest, getMasterlistRevisionShouldOutputLongStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsFalse) { + ASSERT_NO_THROW(db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + + MasterlistInfo info; + EXPECT_NO_THROW(info = db_->GetMasterlistRevision(masterlistPath.string(), false)); + EXPECT_EQ(40, info.revision_id.length()); + EXPECT_EQ(10, info.revision_date.length()); + EXPECT_FALSE(info.is_modified); +} + +TEST_P(DatabaseInterfaceTest, getMasterlistRevisionShouldOutputShortStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsTrue) { + ASSERT_NO_THROW(db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + + MasterlistInfo info; + EXPECT_NO_THROW(info = db_->GetMasterlistRevision(masterlistPath.string(), false)); + EXPECT_GE(size_t(40), info.revision_id.length()); + EXPECT_LE(size_t(7), info.revision_id.length()); + EXPECT_EQ(10, info.revision_date.length()); + EXPECT_FALSE(info.is_modified); +} + +TEST_P(DatabaseInterfaceTest, getMasterlistRevisionShouldSucceedIfAnEditedVersionControlledMasterlistIsPresent) { + ASSERT_NO_THROW(db_->UpdateMasterlist(masterlistPath.string(), url_, branch_)); + ASSERT_NO_THROW(GenerateMasterlist()); + + MasterlistInfo info; + EXPECT_NO_THROW(info = db_->GetMasterlistRevision(masterlistPath.string(), false)); + EXPECT_EQ(40, info.revision_id.length()); + EXPECT_EQ(10, info.revision_date.length()); + EXPECT_TRUE(info.is_modified); +} + +TEST_P(DatabaseInterfaceTest, getPluginTagsShouldReturnOkAndOutputEmptyNonModifiedArraysIfAPluginWithoutTagsIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + PluginTags tags; + EXPECT_NO_THROW(tags = db_->GetPluginTags(blankEsp)); + + EXPECT_TRUE(tags.added.empty()); + EXPECT_TRUE(tags.removed.empty()); + EXPECT_FALSE(tags.userlist_modified); +} + +TEST_P(DatabaseInterfaceTest, getPluginTagsShouldReturnOkAndNonEmptyNonModifiedArraysIfAPluginWithTagsIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + PluginTags tags; + EXPECT_NO_THROW(tags = db_->GetPluginTags(blankEsm)); + + EXPECT_EQ(std::set({ + "Actors.ACBS", + "Actors.AIData", + }), tags.added); + EXPECT_EQ(std::set({ + "C.Water", + }), tags.removed); + EXPECT_FALSE(tags.userlist_modified); +} + +TEST_P(DatabaseInterfaceTest, getPluginTagsShouldReturnOkAndNonEmptyModifiedArraysIfAPluginWithTagsIsQueriedAndMetadataWasAlsoLoadedFromAUserlist) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), masterlistPath.string())); + + PluginTags tags; + EXPECT_NO_THROW(tags = db_->GetPluginTags(blankEsm)); + + EXPECT_EQ(std::set({ + "Actors.ACBS", + "Actors.AIData", + }), tags.added); + EXPECT_EQ(std::set({ + "C.Water", + }), tags.removed); + EXPECT_TRUE(tags.userlist_modified); +} + +TEST_P(DatabaseInterfaceTest, getPluginTagsShouldOutputTheCorrectBashTagsForPluginsWhenMakingConsecutiveCalls) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + PluginTags tags; + EXPECT_NO_THROW(tags = db_->GetPluginTags(blankEsm)); + + EXPECT_EQ(std::set({ + "Actors.ACBS", + "Actors.AIData", + }), tags.added); + EXPECT_EQ(std::set({ + "C.Water", + }), tags.removed); + EXPECT_FALSE(tags.userlist_modified); + + EXPECT_NO_THROW(tags = db_->GetPluginTags(blankEsp)); + + EXPECT_TRUE(tags.added.empty()); + EXPECT_TRUE(tags.removed.empty()); + EXPECT_FALSE(tags.userlist_modified); +} + +TEST_P(DatabaseInterfaceTest, getPluginMessagesShouldReturnOkAndOutputANullArrayIfAPluginWithNoMessagesIsQueried) { + std::vector messages; + EXPECT_NO_THROW(messages = db_->GetPluginMessages(blankEsp)); + EXPECT_TRUE(messages.empty()); +} + +TEST_P(DatabaseInterfaceTest, getPluginMessagesShouldReturnOkAndOutputANoteIfAPluginWithANoteMessageIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + std::vector messages; + EXPECT_NO_THROW(messages = db_->GetPluginMessages(blankEsm)); + ASSERT_EQ(1, messages.size()); + EXPECT_EQ(MessageType::say, messages[0].type); + EXPECT_EQ(noteMessage, messages[0].text); +} + +TEST_P(DatabaseInterfaceTest, getPluginMessagesShouldReturnOkAndOutputAWarningIfAPluginWithAWarningMessageIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + std::vector messages; + EXPECT_NO_THROW(messages = db_->GetPluginMessages(blankDifferentEsm)); + ASSERT_EQ(1, messages.size()); + EXPECT_EQ(MessageType::warn, messages[0].type); + EXPECT_EQ(warningMessage, messages[0].text); +} + +TEST_P(DatabaseInterfaceTest, getPluginMessagesShouldReturnOkAndOutputAnErrorIfAPluginWithAnErrorMessageIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + std::vector messages; + EXPECT_NO_THROW(messages = db_->GetPluginMessages(blankDifferentEsp)); + ASSERT_EQ(1, messages.size()); + EXPECT_EQ(MessageType::error, messages[0].type); + EXPECT_EQ(errorMessage, messages[0].text); +} + +TEST_P(DatabaseInterfaceTest, getPluginMessagesShouldReturnOkAndOutputMultipleMessagesIfAPluginWithMultipleMessagesIsQueried) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + std::vector messages; + EXPECT_NO_THROW(messages = db_->GetPluginMessages(blankDifferentMasterDependentEsp)); + ASSERT_EQ(3, messages.size()); + EXPECT_EQ(MessageType::say, messages[0].type); + EXPECT_EQ(noteMessage, messages[0].text); + EXPECT_EQ(MessageType::warn, messages[1].type); + EXPECT_EQ(warningMessage, messages[1].text); + EXPECT_EQ(MessageType::error, messages[2].type); + EXPECT_EQ(errorMessage, messages[2].text); +} + +TEST_P(DatabaseInterfaceTest, getPluginCleanlinessShouldReturnOkAndOutputUnknownForAPluginWithNoDirtyInfo) { + PluginCleanliness cleanliness; + EXPECT_NO_THROW(cleanliness = db_->GetPluginCleanliness(blankEsp)); + EXPECT_EQ(PluginCleanliness::unknown, cleanliness); +} + +TEST_P(DatabaseInterfaceTest, getPluginCleanlinessShouldReturnOkAndOutputYesForAPluginWithDirtyInfo) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + PluginCleanliness cleanliness; + EXPECT_NO_THROW(cleanliness = db_->GetPluginCleanliness(blankDifferentEsm)); + EXPECT_EQ(PluginCleanliness::dirty, cleanliness); +} + +TEST_P(DatabaseInterfaceTest, getPluginCleanlinessShouldReturnOkAndOutputNoForAPluginWithADoNotCleanMessage) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + PluginCleanliness cleanliness; + EXPECT_NO_THROW(cleanliness = db_->GetPluginCleanliness(blankEsm)); + EXPECT_EQ(PluginCleanliness::do_not_clean, cleanliness); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnOkAndWriteToFileIfArgumentsGivenAreValid) { + EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); + EXPECT_TRUE(boost::filesystem::exists(minimalOutputPath_)); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnAFileWriteErrorIfTheFileAlreadyExistsAndTheOverwriteArgumentIsFalse) { + ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); + ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + + EXPECT_ANY_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnOkAndWriteToFileIfTheArgumentsAreValidAndTheOverwriteArgumentIsTrue) { + EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); + EXPECT_TRUE(boost::filesystem::exists(minimalOutputPath_)); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnOkIfTheFileAlreadyExistsAndTheOverwriteArgumentIsTrue) { + ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); + ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + + EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldReturnAFileWriteErrorIfPathGivenExistsAndIsReadOnly) { + ASSERT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), false)); + ASSERT_TRUE(boost::filesystem::exists(minimalOutputPath_)); + + boost::filesystem::permissions(minimalOutputPath_, + boost::filesystem::perms::remove_perms + | boost::filesystem::perms::owner_write); + + EXPECT_ANY_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); +} + +TEST_P(DatabaseInterfaceTest, writeMinimalListShouldWriteOnlyBashTagsAndDirtyInfo) { + ASSERT_NO_THROW(GenerateMasterlist()); + ASSERT_NO_THROW(db_->LoadLists(masterlistPath.string(), "")); + + EXPECT_NO_THROW(db_->WriteMinimalList(minimalOutputPath_.string(), true)); + + boost::filesystem::ifstream in(minimalOutputPath_); + std::stringstream content; + content << in.rdbuf(); + + EXPECT_EQ(GetExpectedMinimalContent(), content.str()); +} +} +} + +#endif diff --git a/src/tests/api/is_compatible_test.h b/src/tests/api/is_compatible_test.h new file mode 100644 index 00000000..b87aae75 --- /dev/null +++ b/src/tests/api/is_compatible_test.h @@ -0,0 +1,44 @@ +/* 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 +. +*/ + +#ifndef LOOT_TESTS_API_IS_COMPATIBLE_TEST +#define LOOT_TESTS_API_IS_COMPATIBLE_TEST + +#include "loot/api.h" + +#include + +namespace loot { +namespace test { +TEST(IsCompatible, shouldReturnTrueWithEqualMajorAndMinorVersionsAndUnequalPatchVersion) { + EXPECT_TRUE(IsCompatible(LootVersion::major, LootVersion::minor, LootVersion::patch + 1)); +} + +TEST(IsCompatible, shouldReturnFalseWithEqualMajorVersionAndUnequalMinorAndPatchVersions) { + EXPECT_FALSE(IsCompatible(LootVersion::major, LootVersion::minor + 1, LootVersion::patch + 1)); +} +} +} + +#endif diff --git a/src/tests/api/loot_apply_load_order_test.h b/src/tests/api/loot_apply_load_order_test.h deleted file mode 100644 index 538ad7f7..00000000 --- a/src/tests/api/loot_apply_load_order_test.h +++ /dev/null @@ -1,78 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_APPLY_LOAD_ORDER_TEST -#define LOOT_TESTS_API_LOOT_APPLY_LOAD_ORDER_TEST - -#include "loot/api.h" - -#include "tests/api/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 diff --git a/src/tests/api/loot_create_db_test.h b/src/tests/api/loot_create_db_test.h deleted file mode 100644 index 78117859..00000000 --- a/src/tests/api/loot_create_db_test.h +++ /dev/null @@ -1,105 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_CREATE_DB_TEST -#define LOOT_TESTS_API_LOOT_CREATE_DB_TEST - -#include "loot/api.h" - -#include - -#include "tests/common_game_test_fixture.h" - -namespace loot { -namespace test { -class loot_create_db_test : - public ::testing::TestWithParam, - public CommonGameTestFixture { -protected: - loot_create_db_test() : - CommonGameTestFixture(GetParam()), - db_(nullptr) {} - - void SetUp() { - setUp(); - } - - void TearDown() { - 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 diff --git a/src/tests/api/loot_db_test.h b/src/tests/api/loot_db_test.h deleted file mode 100644 index 2101c797..00000000 --- a/src/tests/api/loot_db_test.h +++ /dev/null @@ -1,327 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_DB_TEST -#define LOOT_TESTS_API_LOOT_DB_TEST - -#include "api/loot_db.h" - -#include "tests/common_game_test_fixture.h" - -namespace loot { -namespace test { -class loot_db_test : - public ::testing::TestWithParam, - public CommonGameTestFixture { -protected: - loot_db_test() : - CommonGameTestFixture(GetParam()), - db_(nullptr) {} - - virtual void SetUp() { - setUp(); - - db_ = new loot_db(static_cast(GetParam()), dataPath.parent_path().string().c_str(), localPath.string().c_str()); - } - - inline virtual void TearDown() { - tearDown(); - - delete 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_db_test, - ::testing::Values( - static_cast(GameType::tes4), - static_cast(GameType::tes5), - static_cast(GameType::fo3), - static_cast(GameType::fonv), - static_cast(GameType::fo4))); - -TEST_P(loot_db_test, settingRevisionIdStringShouldCopyIt) { - db_->setRevisionIdString("id"); - EXPECT_STREQ("id", db_->getRevisionIdString()); -} - -TEST_P(loot_db_test, settingRevisionDateStringShouldCopyIt) { - db_->setRevisionDateString("date"); - EXPECT_STREQ("date", db_->getRevisionDateString()); -} - -TEST_P(loot_db_test, settingPluginNamesShouldCopyThem) { - db_->setPluginNames(std::vector({ - PluginMetadata("Blank.esm"), - PluginMetadata("Blank.esp"), - })); - - EXPECT_EQ(2, db_->getPluginNames().size()); - EXPECT_STREQ("Blank.esm", db_->getPluginNames()[0]); - EXPECT_STREQ("Blank.esp", db_->getPluginNames()[1]); -} - -TEST_P(loot_db_test, settingPluginNamesTwiceShouldOverwriteTheFirstDataSet) { - db_->setPluginNames(std::vector({ - PluginMetadata("Blank.esm"), - PluginMetadata("Blank.esp"), - })); - db_->setPluginNames(std::vector({ - PluginMetadata("Blank - Different.esm"), - PluginMetadata("Blank - Different.esp"), - })); - - EXPECT_EQ(2, db_->getPluginNames().size()); - EXPECT_STREQ("Blank - Different.esm", db_->getPluginNames()[0]); - EXPECT_STREQ("Blank - Different.esp", db_->getPluginNames()[1]); -} - -TEST_P(loot_db_test, addingNewBashTagsToTheMapShouldAppendThem) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - EXPECT_EQ(2, db_->getBashTagMap().size()); - EXPECT_STREQ("C.Climate", db_->getBashTagMap()[0]); - EXPECT_STREQ("Relev", db_->getBashTagMap()[1]); -} - -TEST_P(loot_db_test, addingAnExistingBashTagToTheMapShouldNotDuplicateIt) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - "C.Climate", - }); - - EXPECT_EQ(2, db_->getBashTagMap().size()); - EXPECT_STREQ("C.Climate", db_->getBashTagMap()[0]); - EXPECT_STREQ("Relev", db_->getBashTagMap()[1]); -} - -TEST_P(loot_db_test, gettingABashTagsUidForATagThatIsNotInTheMapShouldThrow) { - EXPECT_ANY_THROW(db_->getBashTagUid("Relev")); -} - -TEST_P(loot_db_test, gettingABashTagsUidShouldReturnItsTagMapIndex) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - EXPECT_EQ(1, db_->getBashTagUid("Relev")); -} - -TEST_P(loot_db_test, clearingAnEmptyBashTagMapShouldDoNothing) { - EXPECT_NO_THROW(db_->clearBashTagMap()); -} - -TEST_P(loot_db_test, clearingABashTagMapShouldEmptyIt) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - db_->clearBashTagMap(); - EXPECT_TRUE(db_->getBashTagMap().empty()); -} - -TEST_P(loot_db_test, clearingABashTagMapShouldAffectExistingReferences) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - auto& bashTagMap = db_->getBashTagMap(); - db_->clearBashTagMap(); - EXPECT_TRUE(bashTagMap.empty()); -} - -TEST_P(loot_db_test, settingAddedTagsWithNoTagMapShouldThrow) { - EXPECT_ANY_THROW(db_->setAddedTags({ - "Relev", - })); -} - -TEST_P(loot_db_test, gettingSetAddedTagsShouldReturnTheirUids) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - db_->setAddedTags({ - "Relev", - }); - - EXPECT_EQ(std::vector({ - 1, - }), db_->getAddedTagIds()); -} - -TEST_P(loot_db_test, settingAddedTagsShouldReplaceExistingTags) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - db_->setAddedTags({ - "Relev", - }); - - db_->setAddedTags({ - "C.Climate", - }); - - EXPECT_EQ(std::vector({ - 0, - }), db_->getAddedTagIds()); -} - -TEST_P(loot_db_test, settingRemovedTagsWithNoTagMapShouldThrow) { - EXPECT_ANY_THROW(db_->setRemovedTags({ - "Relev", - })); -} - -TEST_P(loot_db_test, gettingSetRemovedTagsShouldReturnTheirUids) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - db_->setRemovedTags({ - "Relev", - }); - - EXPECT_EQ(std::vector({ - 1, - }), db_->getRemovedTagIds()); -} - -TEST_P(loot_db_test, settingRemovedTagsShouldReplaceExistingTags) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - - db_->setRemovedTags({ - "Relev", - }); - - db_->setRemovedTags({ - "C.Climate", - }); - - EXPECT_EQ(std::vector({ - 0, - }), db_->getRemovedTagIds()); -} - -TEST_P(loot_db_test, settingPluginMessagesShouldCopyThem) { - db_->setPluginMessages(std::list({ - Message(MessageType::warn, "Test 1"), - Message(MessageType::error, "Test 2"), - })); - - EXPECT_EQ(2, db_->getPluginMessages().size()); - EXPECT_EQ(static_cast(MessageType::warn), db_->getPluginMessages()[0].type); - EXPECT_STREQ("Test 1", db_->getPluginMessages()[0].message); - EXPECT_EQ(static_cast(MessageType::error), db_->getPluginMessages()[1].type); - EXPECT_STREQ("Test 2", db_->getPluginMessages()[1].message); -} - -TEST_P(loot_db_test, settingPluginMessagesTwiceShouldOverwriteTheFirstDataSet) { - db_->setPluginMessages(std::list({ - Message(MessageType::warn, "Test 1"), - Message(MessageType::error, "Test 2"), - })); - db_->setPluginMessages(std::list({ - Message(MessageType::error, "Test 3"), - Message(MessageType::warn, "Test 4"), - Message(MessageType::say, "Test 5"), - })); - - EXPECT_EQ(3, db_->getPluginMessages().size()); - EXPECT_EQ(static_cast(MessageType::error), db_->getPluginMessages()[0].type); - EXPECT_STREQ("Test 3", db_->getPluginMessages()[0].message); - EXPECT_EQ(static_cast(MessageType::warn), db_->getPluginMessages()[1].type); - EXPECT_STREQ("Test 4", db_->getPluginMessages()[1].message); - EXPECT_EQ(static_cast(MessageType::say), db_->getPluginMessages()[2].type); - EXPECT_STREQ("Test 5", db_->getPluginMessages()[2].message); -} - -TEST_P(loot_db_test, clearingArraysShouldEmptyPluginNamesTagIdsAndMessages) { - db_->setPluginMessages(std::list({ - Message(MessageType::warn, "Test 1"), - Message(MessageType::error, "Test 2"), - })); - db_->setPluginNames(std::vector({ - PluginMetadata("Blank.esm"), - PluginMetadata("Blank.esp"), - })); - - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - db_->setAddedTags({ - "Relev", - }); - db_->setRemovedTags({ - "Relev", - }); - - ASSERT_FALSE(db_->getPluginMessages().empty()); - ASSERT_FALSE(db_->getPluginNames().empty()); - ASSERT_FALSE(db_->getAddedTagIds().empty()); - ASSERT_FALSE(db_->getRemovedTagIds().empty()); - ASSERT_FALSE(db_->getBashTagMap().empty()); - - EXPECT_NO_THROW(db_->clearArrays()); - - EXPECT_TRUE(db_->getPluginMessages().empty()); - EXPECT_TRUE(db_->getPluginNames().empty()); - EXPECT_TRUE(db_->getAddedTagIds().empty()); - EXPECT_TRUE(db_->getRemovedTagIds().empty()); -} - -TEST_P(loot_db_test, clearingArraysShouldNotEmptyBashTagMap) { - db_->addBashTagsToMap({ - "C.Climate", - "Relev", - }); - ASSERT_FALSE(db_->getBashTagMap().empty()); - - EXPECT_NO_THROW(db_->clearArrays()); - - EXPECT_FALSE(db_->getBashTagMap().empty()); -} -} -} - -#endif diff --git a/src/tests/api/loot_eval_lists_test.h b/src/tests/api/loot_eval_lists_test.h deleted file mode 100644 index 41f6d4e6..00000000 --- a/src/tests/api/loot_eval_lists_test.h +++ /dev/null @@ -1,88 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_EVAL_LISTS_TEST -#define LOOT_TESTS_API_LOOT_EVAL_LISTS_TEST - -#include "loot/api.h" - -#include "tests/api/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 diff --git a/src/tests/api/loot_get_dirty_info_test.h b/src/tests/api/loot_get_dirty_info_test.h deleted file mode 100644 index cc1b189c..00000000 --- a/src/tests/api/loot_get_dirty_info_test.h +++ /dev/null @@ -1,82 +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 -. -*/ - -#ifndef LOOT_TEST_API_LOOT_GET_DIRTY_INFO_TEST -#define LOOT_TEST_API_LOOT_GET_DIRTY_INFO_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_get_dirty_info_test : public ApiGameOperationsTest { -protected: - loot_get_dirty_info_test() : - needsCleaning_(0) {} - - unsigned int needsCleaning_; -}; - -// 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_get_dirty_info_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_get_dirty_info_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(NULL, blankEsp.c_str(), &needsCleaning_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(db_, NULL, &needsCleaning_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(db_, blankEsp.c_str(), NULL)); -} - -TEST_P(loot_get_dirty_info_test, shouldReturnOkAndOutputUnknownForAPluginWithNoDirtyInfo) { - EXPECT_EQ(loot_ok, loot_get_dirty_info(db_, blankEsp.c_str(), &needsCleaning_)); - EXPECT_EQ(loot_needs_cleaning_unknown, needsCleaning_); -} - -TEST_P(loot_get_dirty_info_test, shouldReturnOkAndOutputYesForAPluginWithDirtyInfo) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_dirty_info(db_, blankDifferentEsm.c_str(), &needsCleaning_)); - EXPECT_EQ(loot_needs_cleaning_yes, needsCleaning_); -} - -TEST_P(loot_get_dirty_info_test, shouldReturnOkAndOutputNoForAPluginWithADoNotCleanMessage) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_dirty_info(db_, blankEsm.c_str(), &needsCleaning_)); - EXPECT_EQ(loot_needs_cleaning_no, needsCleaning_); -} -} -} - -#endif diff --git a/src/tests/api/loot_get_masterlist_revision_test.h b/src/tests/api/loot_get_masterlist_revision_test.h deleted file mode 100644 index d98c7a11..00000000 --- a/src/tests/api/loot_get_masterlist_revision_test.h +++ /dev/null @@ -1,122 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_GET_MASTERLIST_REVISION_TEST -#define LOOT_TESTS_API_LOOT_GET_MASTERLIST_REVISION_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_get_masterlist_revision_test : public ApiGameOperationsTest { -protected: - loot_get_masterlist_revision_test() : - branch_("2.x"), - revisionId_("foo"), - revisionDate_("bar"), - isModified_(true), - updated_(false) {} - - const std::string branch_; - const char * revisionId_; - const char * revisionDate_; - bool isModified_; - bool updated_; -}; - -// 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_get_masterlist_revision_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_get_masterlist_revision_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_get_masterlist_revision(NULL, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_masterlist_revision(db_, NULL, false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, NULL, &revisionDate_, &isModified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, NULL, &isModified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, NULL)); -} - -TEST_P(loot_get_masterlist_revision_test, shouldSucceedIfNoMasterlistIsPresent) { - EXPECT_EQ(loot_ok, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_EQ(NULL, revisionId_); - EXPECT_EQ(NULL, revisionDate_); - EXPECT_FALSE(isModified_); -} - -TEST_P(loot_get_masterlist_revision_test, shouldSucceedIfANonVersionControlledMasterlistIsPresent) { - ASSERT_NO_THROW(GenerateMasterlist()); - EXPECT_EQ(loot_ok, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_EQ(NULL, revisionId_); - EXPECT_EQ(NULL, revisionDate_); - EXPECT_FALSE(isModified_); -} - -TEST_P(loot_get_masterlist_revision_test, shouldOutputLongStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsFalse) { - ASSERT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - - EXPECT_EQ(loot_ok, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_STRNE(NULL, revisionId_); - EXPECT_EQ(40, strlen(revisionId_)); - EXPECT_STRNE(NULL, revisionDate_); - EXPECT_EQ(10, strlen(revisionDate_)); - EXPECT_FALSE(isModified_); -} - -TEST_P(loot_get_masterlist_revision_test, shouldOutputShortStringsAndBooleanFalseIfAVersionControlledMasterlistIsPresentAndGetShortIdParameterIsTrue) { - ASSERT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - - EXPECT_EQ(loot_ok, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - EXPECT_STRNE(NULL, revisionId_); - EXPECT_GE(size_t(40), strlen(revisionId_)); - EXPECT_LE(size_t(7), strlen(revisionId_)); - EXPECT_STRNE(NULL, revisionDate_); - EXPECT_EQ(10, strlen(revisionDate_)); - EXPECT_FALSE(isModified_); -} - -TEST_P(loot_get_masterlist_revision_test, shouldSucceedIfAnEditedVersionControlledMasterlistIsPresent) { - ASSERT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - - ASSERT_NO_THROW(GenerateMasterlist()); - EXPECT_EQ(loot_ok, loot_get_masterlist_revision(db_, masterlistPath.string().c_str(), false, &revisionId_, &revisionDate_, &isModified_)); - - EXPECT_STRNE(NULL, revisionId_); - EXPECT_EQ(40, strlen(revisionId_)); - EXPECT_STRNE(NULL, revisionDate_); - EXPECT_EQ(10, strlen(revisionDate_)); - EXPECT_TRUE(isModified_); -} -} -} - -#endif diff --git a/src/tests/api/loot_get_plugin_messages_test.h b/src/tests/api/loot_get_plugin_messages_test.h deleted file mode 100644 index e49bef62..00000000 --- a/src/tests/api/loot_get_plugin_messages_test.h +++ /dev/null @@ -1,114 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_GET_PLUGIN_MESSAGES_TEST -#define LOOT_TESTS_API_LOOT_GET_PLUGIN_MESSAGES_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_get_plugin_messages_test : public ApiGameOperationsTest { -protected: - loot_get_plugin_messages_test() : - messages_(nullptr), - numMessages_(0) {} - - const loot_message * messages_; - size_t numMessages_; -}; - -// 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_get_plugin_messages_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_get_plugin_messages_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_messages(NULL, blankEsp.c_str(), &messages_, &numMessages_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_messages(db_, NULL, &messages_, &numMessages_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_messages(db_, blankEsp.c_str(), NULL, &numMessages_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_messages(db_, blankEsp.c_str(), &messages_, NULL)); -} - -TEST_P(loot_get_plugin_messages_test, shouldReturnOkAndOutputANullArrayIfAPluginWithNoMessagesIsQueried) { - EXPECT_EQ(loot_ok, loot_get_plugin_messages(db_, blankEsp.c_str(), &messages_, &numMessages_)); - EXPECT_EQ(0, numMessages_); - EXPECT_EQ(NULL, messages_); -} - -TEST_P(loot_get_plugin_messages_test, shouldReturnOkAndOutputANoteIfAPluginWithANoteMessageIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_plugin_messages(db_, blankEsm.c_str(), &messages_, &numMessages_)); - ASSERT_EQ(1, numMessages_); - EXPECT_EQ(loot_message_say, messages_[0].type); - EXPECT_STREQ(noteMessage.c_str(), messages_[0].message); -} - -TEST_P(loot_get_plugin_messages_test, shouldReturnOkAndOutputAWarningIfAPluginWithAWarningMessageIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_plugin_messages(db_, blankDifferentEsm.c_str(), &messages_, &numMessages_)); - ASSERT_EQ(1, numMessages_); - EXPECT_EQ(loot_message_warn, messages_[0].type); - EXPECT_STREQ(warningMessage.c_str(), messages_[0].message); -} - -TEST_P(loot_get_plugin_messages_test, shouldReturnOkAndOutputAnErrorIfAPluginWithAnErrorMessageIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_plugin_messages(db_, blankDifferentEsp.c_str(), &messages_, &numMessages_)); - ASSERT_EQ(1, numMessages_); - EXPECT_EQ(loot_message_error, messages_[0].type); - EXPECT_STREQ(errorMessage.c_str(), messages_[0].message); -} - -TEST_P(loot_get_plugin_messages_test, shouldReturnOkAndOutputMultipleMessagesIfAPluginWithMultipleMessagesIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_plugin_messages(db_, blankDifferentMasterDependentEsp.c_str(), &messages_, &numMessages_)); - ASSERT_EQ(3, numMessages_); - EXPECT_EQ(loot_message_say, messages_[0].type); - EXPECT_STREQ(noteMessage.c_str(), messages_[0].message); - EXPECT_EQ(loot_message_warn, messages_[1].type); - EXPECT_STREQ(warningMessage.c_str(), messages_[1].message); - EXPECT_EQ(loot_message_error, messages_[2].type); - EXPECT_STREQ(errorMessage.c_str(), messages_[2].message); -} -} -} - -#endif diff --git a/src/tests/api/loot_get_plugin_tags_test.h b/src/tests/api/loot_get_plugin_tags_test.h deleted file mode 100644 index 659bf6f7..00000000 --- a/src/tests/api/loot_get_plugin_tags_test.h +++ /dev/null @@ -1,165 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_GET_PLUGIN_TAGS_TEST -#define LOOT_TESTS_API_LOOT_GET_PLUGIN_TAGS_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_get_plugin_tags_test : public ApiGameOperationsTest { -protected: - loot_get_plugin_tags_test() : - tagMap_(nullptr), - numTags_(0), - added_(nullptr), - removed_(nullptr), - numAdded_(0), - numRemoved_(0), - modified_(false) {} - - const char * const * tagMap_; - size_t numTags_; - - const unsigned int * added_; - const unsigned int * removed_; - size_t numAdded_; - size_t numRemoved_; - bool modified_; - - void getTagMap() { - ASSERT_EQ(loot_ok, loot_get_tag_map(db_, &tagMap_, &numTags_)); - - ASSERT_EQ(3, numTags_); - ASSERT_STREQ("Actors.ACBS", tagMap_[0]); - ASSERT_STREQ("Actors.AIData", tagMap_[1]); - ASSERT_STREQ("C.Water", tagMap_[2]); - } -}; - -// 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_get_plugin_tags_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_get_plugin_tags_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(NULL, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, NULL, &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, blankEsm.c_str(), NULL, &numAdded_, &removed_, &numRemoved_, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, NULL, &removed_, &numRemoved_, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, NULL, &numRemoved_, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, NULL, &modified_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, NULL)); -} - -TEST_P(loot_get_plugin_tags_test, shouldReturnANoTagMapIfCalledBeforeATagMapHasBeenGotten) { - EXPECT_EQ(loot_error_no_tag_map, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); -} - -TEST_P(loot_get_plugin_tags_test, shouldReturnOkAndOutputEmptyNonModifiedArraysIfAPluginWithoutTagsIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - getTagMap(); - - EXPECT_EQ(loot_ok, loot_get_plugin_tags(db_, blankEsp.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - - EXPECT_EQ(0, numAdded_); - EXPECT_EQ(NULL, added_); - EXPECT_EQ(0, numRemoved_); - EXPECT_EQ(NULL, removed_); - EXPECT_FALSE(modified_); -} - -TEST_P(loot_get_plugin_tags_test, shouldReturnOkAndNonEmptyNonModifiedArraysIfAPluginWithTagsIsQueried) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - getTagMap(); - - EXPECT_EQ(loot_ok, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - - // The values are tag map indices, check they match up as expected. - ASSERT_EQ(2, numAdded_); - EXPECT_EQ(0, added_[0]); - EXPECT_EQ(1, added_[1]); - - ASSERT_EQ(1, numRemoved_); - EXPECT_EQ(2, removed_[0]); - - EXPECT_FALSE(modified_); -} - -TEST_P(loot_get_plugin_tags_test, shouldReturnOkAndNonEmptyModifiedArraysIfAPluginWithTagsIsQueriedAndMetadataWasAlsoLoadedFromAUserlist) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), masterlistPath.string().c_str())); - getTagMap(); - - EXPECT_EQ(loot_ok, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - - // The values are tag map indices, check they match up as expected. - ASSERT_EQ(2, numAdded_); - EXPECT_EQ(0, added_[0]); - EXPECT_EQ(1, added_[1]); - - ASSERT_EQ(1, numRemoved_); - EXPECT_EQ(2, removed_[0]); - - EXPECT_TRUE(modified_); -} - -TEST_P(loot_get_plugin_tags_test, shouldOutputTheCorrectBashTagsForPluginsWhenMakingConsecutiveCalls) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - getTagMap(); - - EXPECT_EQ(loot_ok, loot_get_plugin_tags(db_, blankEsm.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - - ASSERT_EQ(2, numAdded_); - EXPECT_EQ(0, added_[0]); - EXPECT_EQ(1, added_[1]); - - ASSERT_EQ(1, numRemoved_); - EXPECT_EQ(2, removed_[0]); - EXPECT_FALSE(modified_); - - EXPECT_EQ(loot_ok, loot_get_plugin_tags(db_, blankEsp.c_str(), &added_, &numAdded_, &removed_, &numRemoved_, &modified_)); - - EXPECT_EQ(0, numAdded_); - EXPECT_EQ(NULL, added_); - EXPECT_EQ(0, numRemoved_); - EXPECT_EQ(NULL, removed_); - EXPECT_FALSE(modified_); -} -} -} - -#endif diff --git a/src/tests/api/loot_get_tag_map_test.h b/src/tests/api/loot_get_tag_map_test.h deleted file mode 100644 index a4ecf3c6..00000000 --- a/src/tests/api/loot_get_tag_map_test.h +++ /dev/null @@ -1,81 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_GET_TAG_MAP_TEST -#define LOOT_TESTS_API_LOOT_GET_TAG_MAP_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_get_tag_map_test : public ApiGameOperationsTest { -protected: - loot_get_tag_map_test() : - tagMap_(nullptr), - numTags_(0) {} - - const char * const * tagMap_; - size_t numTags_; -}; - -// 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_get_tag_map_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_get_tag_map_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_get_tag_map(NULL, &tagMap_, &numTags_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_tag_map(db_, NULL, &numTags_)); - EXPECT_EQ(loot_error_invalid_args, loot_get_tag_map(db_, &tagMap_, NULL)); -} - -TEST_P(loot_get_tag_map_test, shouldReturnOkAndOutputAnEmptyTagMapIfNoMetadataHasBeenLoaded) { - EXPECT_EQ(loot_ok, loot_get_tag_map(db_, &tagMap_, &numTags_)); - EXPECT_EQ(0, numTags_); - EXPECT_EQ(NULL, tagMap_); -} - -TEST_P(loot_get_tag_map_test, shouldReturnOKAndOutputANonEmptyTagMapIfMetadataHasBeenLoaded) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_get_tag_map(db_, &tagMap_, &numTags_)); - - ASSERT_EQ(3, numTags_); - EXPECT_STREQ("Actors.ACBS", tagMap_[0]); - EXPECT_STREQ("Actors.AIData", tagMap_[1]); - EXPECT_STREQ("C.Water", tagMap_[2]); -} -} -} - -#endif diff --git a/src/tests/api/loot_load_lists_test.h b/src/tests/api/loot_load_lists_test.h deleted file mode 100644 index c6744a89..00000000 --- a/src/tests/api/loot_load_lists_test.h +++ /dev/null @@ -1,83 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_LOAD_LISTS_TEST -#define LOOT_TESTS_API_LOOT_LOAD_LISTS_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_load_lists_test : public ApiGameOperationsTest { -protected: - loot_load_lists_test() : - userlistPath(localPath / "userlist.yaml") {} - - inline virtual void TearDown() { - ApiGameOperationsTest::TearDown(); - - // The userlist may have been created during the test, so delete it. - ASSERT_NO_THROW(boost::filesystem::remove(userlistPath)); - } - - const boost::filesystem::path userlistPath; -}; - -// 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_load_lists_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_load_lists_test, shouldReturnAnInvalidArgsErrorIfTheDbOrMasterlistPathArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_load_lists(NULL, masterlistPath.string().c_str(), NULL)); - EXPECT_EQ(loot_error_invalid_args, loot_load_lists(db_, NULL, NULL)); -} - -TEST_P(loot_load_lists_test, shouldReturnAPathNotFoundErrorIfNoMasterlistIsPresent) { - EXPECT_EQ(loot_error_path_not_found, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); -} - -TEST_P(loot_load_lists_test, shouldReturnAPathNotFoundErrorIfAMasterlistIsPresentButAUserlistDoesNotExistAtTheGivenPath) { - ASSERT_NO_THROW(GenerateMasterlist()); - EXPECT_EQ(loot_error_path_not_found, loot_load_lists(db_, masterlistPath.string().c_str(), userlistPath.string().c_str())); -} - -TEST_P(loot_load_lists_test, shouldReturnOkIfTheMasterlistAndUserlistAreBothPresent) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_NO_THROW(boost::filesystem::copy(masterlistPath, userlistPath)); - - EXPECT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), userlistPath.string().c_str())); -} -} -} - -#endif diff --git a/src/tests/api/loot_sort_plugins_test.h b/src/tests/api/loot_sort_plugins_test.h deleted file mode 100644 index e1a729f0..00000000 --- a/src/tests/api/loot_sort_plugins_test.h +++ /dev/null @@ -1,92 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_SORT_PLUGINS_TEST -#define LOOT_TESTS_API_LOOT_SORT_PLUGINS_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_sort_plugins_test : public ApiGameOperationsTest { -protected: - loot_sort_plugins_test() : - sortedPlugins_(nullptr), - numPlugins_(0) {} - - const char * const * sortedPlugins_; - size_t numPlugins_; -}; - -// 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_sort_plugins_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_sort_plugins_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_sort_plugins(NULL, &sortedPlugins_, &numPlugins_)); - EXPECT_EQ(loot_error_invalid_args, loot_sort_plugins(db_, NULL, &numPlugins_)); - EXPECT_EQ(loot_error_invalid_args, loot_sort_plugins(db_, &sortedPlugins_, NULL)); -} - -TEST_P(loot_sort_plugins_test, shouldSucceedIfPassedValidArguments) { - std::list expectedOrder = { - masterFile, - blankEsm, - blankMasterDependentEsm, - blankDifferentEsm, - blankDifferentMasterDependentEsm, - blankMasterDependentEsp, - blankDifferentMasterDependentEsp, - blankEsp, - blankPluginDependentEsp, - blankDifferentEsp, - blankDifferentPluginDependentEsp, - }; - - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_sort_plugins(db_, &sortedPlugins_, &numPlugins_)); - - ASSERT_EQ(expectedOrder.size(), numPlugins_); - - size_t i = 0; - for (const auto& plugin : expectedOrder) { - EXPECT_EQ(plugin, sortedPlugins_[i]); - ++i; - } -} -} -} - -#endif diff --git a/src/tests/api/loot_update_masterlist_test.h b/src/tests/api/loot_update_masterlist_test.h deleted file mode 100644 index 0f1b4824..00000000 --- a/src/tests/api/loot_update_masterlist_test.h +++ /dev/null @@ -1,111 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_UPDATE_MASTERLIST_TEST -#define LOOT_TESTS_API_LOOT_UPDATE_MASTERLIST_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_update_masterlist_test : public ApiGameOperationsTest { -protected: - loot_update_masterlist_test() : - branch_("2.x"), - updated_(false) {} - - inline void TearDown() { - ApiGameOperationsTest::TearDown(); - - // Also remove the ".git" folder if it has been created. - ASSERT_NO_THROW(boost::filesystem::remove_all(masterlistPath.parent_path() / ".git")); - } - - const std::string branch_; - bool updated_; -}; - -// 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_update_masterlist_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_update_masterlist_test, shouldReturnAnInvalidArgsErrorIfAnyOfTheArgumentsAreNull) { - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(NULL, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, NULL, "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, masterlistPath.string().c_str(), NULL, branch_.c_str(), &updated_)); - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", NULL, &updated_)); - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), NULL)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAnInvalidArgsErrorIfTheMasterlistPathGivenIsInvalid) { - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, ";//\?", "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAnInvalidArgsErrorIfTheMasterlistPathGivenIsEmpty) { - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, "", "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAGitErrorIfTheRepositoryUrlGivenCannotBeFound) { - EXPECT_EQ(loot_error_git_error, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/oblivion-does-not-exist.git", branch_.c_str(), &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAnInvalidArgsErrorIfTheRepositoryUrlGivenIsEmpty) { - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, masterlistPath.string().c_str(), "", branch_.c_str(), &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAGitErrorIfTheRepositoryBranchGivenCannotBeFound) { - EXPECT_EQ(loot_error_git_error, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", "missing-branch", &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldReturnAnInvalidArgsErrorIfTheRepositoryBranchGivenIsEmpty) { - EXPECT_EQ(loot_error_invalid_args, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", "", &updated_)); -} - -TEST_P(loot_update_masterlist_test, shouldSucceedIfPassedValidParametersAndOutputTrueIfTheMasterlistWasUpdated) { - EXPECT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - EXPECT_TRUE(updated_); - EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); -} - -TEST_P(loot_update_masterlist_test, shouldSucceedIfCalledRepeatedlyButOnlyOutputTrueForTheFirstCall) { - EXPECT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - EXPECT_TRUE(updated_); - - EXPECT_EQ(loot_ok, loot_update_masterlist(db_, masterlistPath.string().c_str(), "https://github.com/loot/testing-metadata.git", branch_.c_str(), &updated_)); - EXPECT_FALSE(updated_); - EXPECT_TRUE(boost::filesystem::exists(masterlistPath)); -} -} -} - -#endif diff --git a/src/tests/api/loot_write_minimal_list_test.h b/src/tests/api/loot_write_minimal_list_test.h deleted file mode 100644 index 0ba4ca32..00000000 --- a/src/tests/api/loot_write_minimal_list_test.h +++ /dev/null @@ -1,146 +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 -. -*/ - -#ifndef LOOT_TESTS_API_LOOT_WRITE_MINIMAL_LIST_TEST -#define LOOT_TESTS_API_LOOT_WRITE_MINIMAL_LIST_TEST - -#include "loot/api.h" - -#include "tests/api/api_game_operations_test.h" - -namespace loot { -namespace test { -class loot_write_minimal_list_test : public ApiGameOperationsTest { -protected: - loot_write_minimal_list_test() : - outputPath(localPath / "minimal.yml") {} - - void SetUp() { - ApiGameOperationsTest::SetUp(); - - ASSERT_FALSE(boost::filesystem::exists(outputPath)); - } - - void TearDown() { - if (boost::filesystem::exists(outputPath)) { - boost::filesystem::permissions(outputPath, - boost::filesystem::perms::add_perms - | boost::filesystem::perms::owner_write); - } - - ApiGameOperationsTest::TearDown(); - - ASSERT_NO_THROW(boost::filesystem::remove(outputPath)); - } - - std::string GetExpectedContent() const { - using std::endl; - - std::stringstream expectedContent; - expectedContent - << "plugins:" << endl - << " - name: '" << blankEsm << "'" << endl - << " tag:" << endl - << " - Actors.ACBS" << endl - << " - Actors.AIData" << endl - << " - -C.Water" << endl - << " - name: '" << blankDifferentEsm << "'" << endl - << " dirty:" << endl - << " - crc: 0x7d22f9df" << endl - << " utility: 'TES4Edit'" << endl - << " udr: 4"; - - return expectedContent.str(); - } - - const boost::filesystem::path outputPath; -}; - -// 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_write_minimal_list_test, - ::testing::Values( - loot_game_tes4, - loot_game_tes5, - loot_game_fo3, - loot_game_fonv, - loot_game_fo4)); - -TEST_P(loot_write_minimal_list_test, shouldReturnAnInvalidArgsErrorIfAPointerArgumentIsNull) { - EXPECT_EQ(loot_error_invalid_args, loot_write_minimal_list(NULL, outputPath.string().c_str(), false)); - EXPECT_EQ(loot_error_invalid_args, loot_write_minimal_list(db_, NULL, false)); -} - -TEST_P(loot_write_minimal_list_test, shouldReturnOkAndWriteToFileIfArgumentsGivenAreValid) { - EXPECT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), false)); - EXPECT_TRUE(boost::filesystem::exists(outputPath)); -} - -TEST_P(loot_write_minimal_list_test, shouldReturnAFileWriteErrorIfTheFileAlreadyExistsAndTheOverwriteArgumentIsFalse) { - ASSERT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), false)); - ASSERT_TRUE(boost::filesystem::exists(outputPath)); - - EXPECT_EQ(loot_error_file_write_fail, loot_write_minimal_list(db_, outputPath.string().c_str(), false)); -} - -TEST_P(loot_write_minimal_list_test, shouldReturnOkAndWriteToFileIfTheArgumentsAreValidAndTheOverwriteArgumentIsTrue) { - EXPECT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), true)); - EXPECT_TRUE(boost::filesystem::exists(outputPath)); -} - -TEST_P(loot_write_minimal_list_test, shouldReturnOkIfTheFileAlreadyExistsAndTheOverwriteArgumentIsTrue) { - ASSERT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), false)); - ASSERT_TRUE(boost::filesystem::exists(outputPath)); - - EXPECT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), true)); -} - -TEST_P(loot_write_minimal_list_test, shouldReturnAFileWriteErrorIfPathGivenExistsAndIsReadOnly) { - ASSERT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), false)); - ASSERT_TRUE(boost::filesystem::exists(outputPath)); - - boost::filesystem::permissions(outputPath, - boost::filesystem::perms::remove_perms - | boost::filesystem::perms::owner_write); - - EXPECT_EQ(loot_error_file_write_fail, loot_write_minimal_list(db_, outputPath.string().c_str(), true)); -} - -TEST_P(loot_write_minimal_list_test, shouldWriteOnlyBashTagsAndDirtyInfo) { - ASSERT_NO_THROW(GenerateMasterlist()); - ASSERT_EQ(loot_ok, loot_load_lists(db_, masterlistPath.string().c_str(), NULL)); - - EXPECT_EQ(loot_ok, loot_write_minimal_list(db_, outputPath.string().c_str(), true)); - - boost::filesystem::ifstream in(outputPath); - std::stringstream content; - content << in.rdbuf(); - - EXPECT_EQ(GetExpectedContent(), content.str()); -} -} -} - -#endif diff --git a/src/tests/api/main.cpp b/src/tests/api/main.cpp index 88ff2268..7748fff9 100644 --- a/src/tests/api/main.cpp +++ b/src/tests/api/main.cpp @@ -24,19 +24,9 @@ #include -#include "loot_apply_load_order_test.h" -#include "loot_create_db_test.h" -#include "loot_eval_lists_test.h" -#include "loot_get_dirty_info_test.h" -#include "loot_get_masterlist_revision_test.h" -#include "loot_get_plugin_messages_test.h" -#include "loot_get_plugin_tags_test.h" -#include "loot_get_tag_map_test.h" -#include "loot_load_lists_test.h" -#include "loot_sort_plugins_test.h" -#include "loot_update_masterlist_test.h" -#include "loot_write_minimal_list_test.h" -#include "test_api.h" +#include "tests/api/create_database_test.h" +#include "tests/api/database_interface_test.h" +#include "tests/api/is_compatible_test.h" #include #include diff --git a/src/tests/api/test_api.h b/src/tests/api/test_api.h deleted file mode 100644 index e921a813..00000000 --- a/src/tests/api/test_api.h +++ /dev/null @@ -1,99 +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 -. -*/ - -#ifndef LOOT_TESTS_API_TEST_API -#define LOOT_TESTS_API_TEST_API - -#include "loot/api.h" - -#include - -namespace loot { -namespace test { -TEST(loot_get_version, shouldReturnAnInvalidArgsErrorIfPassedNullPointers) { - unsigned int vMajor, vMinor, vPatch; - EXPECT_EQ(loot_error_invalid_args, loot_get_version(&vMajor, NULL, NULL)); - EXPECT_EQ(loot_error_invalid_args, loot_get_version(NULL, &vMinor, NULL)); - EXPECT_EQ(loot_error_invalid_args, loot_get_version(NULL, NULL, &vPatch)); - EXPECT_EQ(loot_error_invalid_args, loot_get_version(NULL, NULL, NULL)); -} - -TEST(loot_get_version, shouldReturnOkIfPassedNonNullPointers) { - unsigned int vMajor, vMinor, vPatch; - EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch)); -} - -TEST(loot_get_build_id, shouldReturnAnInvalidArgsErrorIfPassedANullPointer) { - EXPECT_EQ(loot_error_invalid_args, loot_get_build_id(NULL)); -} - -TEST(loot_get_build_id, shouldReturnOkAndOutputANonNullNonPlaceholderRevisionString) { - const char * revision; - EXPECT_EQ(loot_ok, loot_get_build_id(&revision)); - EXPECT_STRNE(NULL, revision); - EXPECT_STRNE("@GIT_COMMIT_STRING@", revision); // The CMake placeholder. -} - -TEST(loot_is_compatible, shouldReturnTrueWithEqualMajorAndMinorVersionsAndUnequalPatchVersion) { - unsigned int vMajor, vMinor, vPatch; - EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch)); - - EXPECT_TRUE(loot_is_compatible(vMajor, vMinor, vPatch + 1)); -} - -TEST(loot_is_compatible, shouldReturnFalseWithEqualMajorVersionAndUnequalMinorAndPatchVersions) { - unsigned int vMajor, vMinor, vPatch; - EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch)); - - EXPECT_FALSE(loot_is_compatible(vMajor, vMinor + 1, vPatch + 1)); -} - -TEST(loot_get_error_message, shouldReturnAnInvalidArgsErrorIfPassedANullPointer) { - EXPECT_EQ(loot_error_invalid_args, loot_get_error_message(NULL)); - - const char * error; - EXPECT_EQ(loot_ok, loot_get_error_message(&error)); - ASSERT_STREQ("Null message pointer passed.", error); -} - -TEST(loot_get_error_message, shouldReturnOkIfPassedANonNullPointer) { - const char * error; - EXPECT_EQ(loot_ok, loot_get_error_message(&error)); -} - -TEST(loot_get_error_message, shouldOutputAnErrorMessageDetailingTheLastErrorIfAnErrorHasOccurred) { - EXPECT_EQ(loot_error_invalid_args, loot_get_error_message(NULL)); - - const char * error; - EXPECT_EQ(loot_ok, loot_get_error_message(&error)); - ASSERT_STREQ("Null message pointer passed.", error); -} - -TEST(loot_destroy_db, shouldNotThrowIfPassedANullPointer) { - ASSERT_NO_THROW(loot_destroy_db(NULL)); -} -} -} - -#endif diff --git a/src/tests/backend/main.cpp b/src/tests/backend/main.cpp index d017dc70..9c3bc35f 100644 --- a/src/tests/backend/main.cpp +++ b/src/tests/backend/main.cpp @@ -24,7 +24,6 @@ #include -#include "tests/api/loot_db_test.h" #include "tests/backend/app/loot_paths_test.h" #include "tests/backend/app/loot_settings_test.h" #include "tests/backend/app/loot_state_test.h"