Started to implement Google Test unit tests.

Added a project for the tests to the CMake config, and added Google Test
as a dependency for it. Travis runs the tests. Some tests currently fail.
This commit is contained in:
Oliver Hamlet
2014-11-01 12:38:17 +00:00
parent 05c7532f62
commit a22d1310a3
6 changed files with 454 additions and 22 deletions
+9 -5
View File
@@ -3,13 +3,13 @@ compiler:
- gcc
before_install:
# Add a PPA for Boost 1.55.
- sudo add-apt-repository ppa:boost-latest/ppa -y
- sudo apt-get update -qq
install:
# Currently inside the cloned repo path.
# Need Boost 1.54+, which isn't in the 12.04 repositories - install from a PPA.
- sudo add-apt-repository ppa:boost-latest/ppa -y
- sudo apt-get update -qq
# Install Boost.
- sudo apt-get install libboost-log1.55-dev libboost-date-time1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-locale1.55-dev libboost-iostreams1.55-dev
# Install Alphanum
- cd ../..
@@ -54,7 +54,11 @@ install:
before_script:
- mkdir build
- cd build
# Fetch plugins to test with.
- wget https://github.com/WrinklyNinja/testing-plugins/archive/master.zip
- unzip master.zip
- mv testing-plugins-master/* ./
# Travis machines are 64 bit, and the deps use dynamic linking.
- cmake .. -DPROJECT_ARCH=64 -DPROJECT_STATIC_RUNTIME=OFF -DBUILD_SHARED_LIBS=OFF
- cmake .. -DPROJECT_ARCH=64 -DPROJECT_STATIC_RUNTIME=OFF -DBUILD_SHARED_LIBS=OFF -DGTEST_ROOT=../../gtest-1.7.0
script: make loot64
script: make tests && ./tests
+51 -17
View File
@@ -46,7 +46,12 @@ set (Boost_USE_STATIC_LIBS ${PROJECT_STATIC_RUNTIME})
set (Boost_USE_MULTITHREADED ON)
set (Boost_USE_STATIC_RUNTIME ${PROJECT_STATIC_RUNTIME})
IF (NOT Boost_USE_STATIC_LIBS)
add_definitions(-DBOOST_LOG_DYN_LINK)
ENDIF ()
find_package(Boost REQUIRED COMPONENTS log log_setup regex locale thread date_time chrono filesystem system iostreams)
find_package(GTest)
set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/game.cpp"
@@ -88,7 +93,12 @@ set (LOOT_API_SRC ${LOOT_SRC}
set (LOOT_API_HEADERS ${LOOT_HEADERS}
"${CMAKE_SOURCE_DIR}/src/api/api.h")
source_group("Header Files" FILES ${LOOT_HEADERS} ${LOOT_GUI_HEADERS} ${LOOT_API_HEADERS})
set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/tests/main.cpp")
set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/api.h")
source_group("Header Files" FILES ${LOOT_HEADERS} ${LOOT_GUI_HEADERS} ${LOOT_API_HEADERS} ${LOOT_TESTS_HEADERS})
# Include source and library directories.
include_directories ("${CMAKE_SOURCE_DIR}/src"
@@ -98,7 +108,8 @@ include_directories ("${CMAKE_SOURCE_DIR}/src"
"${LIBGIT2_ROOT}/include"
${CEF_ROOT}
${LIBESPM_ROOT}
${Boost_INCLUDE_DIRS})
${Boost_INCLUDE_DIRS}
${GTEST_INCLUDE_DIRS})
link_directories ("${LIBLOADORDER_ROOT}/build"
"${LIBGIT2_ROOT}/build"
@@ -113,12 +124,7 @@ link_directories ("${LIBLOADORDER_ROOT}/build"
# Settings when compiling for Windows. Since it's a Windows-only app this is always true, but useful to check for copy/paste into other projects.
IF (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_definitions (-DUNICODE -D_UNICODE -DNDEBUG -DLIBLO_STATIC -DWIN32 -D_WINDOWS)
IF (BUILD_SHARED_LIBS)
add_definitions (-DLOOT_EXPORT)
ELSE ()
add_definitions (-DLOOT_STATIC)
ENDIF ()
add_definitions (-DUNICODE -D_UNICODE -DLIBLO_STATIC)
ENDIF ()
# GCC and MinGW settings.
@@ -144,8 +150,8 @@ IF (MINGW)
set (LOOT_LIBS ${LOOT_LIBS}
version
ws2_32
shlwapi)
ws2_32
shlwapi)
set (LOOT_GUI_LIBS ${LOOT_LIBS}
cef_sandbox
libcef
@@ -165,13 +171,12 @@ ELSEIF (MSVC)
ENDFOREACH()
ENDIF ()
set (CMAKE_EXE_LINKER_FLAGS "/SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE")
set (LOOT_LIBS git2
libyaml-cppmt
version
loadorder${PROJECT_ARCH}
ws2_32
shlwapi)
libyaml-cppmt
version
loadorder${PROJECT_ARCH}
ws2_32
shlwapi)
set (LOOT_GUI_LIBS ${LOOT_LIBS}
cef_sandbox
libcef
@@ -182,17 +187,46 @@ ENDIF ()
##############################
# Actual Building
# Define Targets
##############################
# Build API.
add_library (loot${PROJECT_ARCH} ${LOOT_API_SRC} ${LOOT_API_HEADERS})
target_link_libraries (loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${LOOT_LIBS})
IF (${GTEST_FOUND})
# Build tests.
add_executable(tests ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS})
target_link_libraries(tests loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${LOOT_LIBS} ${GTEST_BOTH_LIBRARIES})
ENDIF ()
# Build application.
add_executable (LOOT ${LOOT_GUI_SRC} ${LOOT_GUI_HEADERS})
target_link_libraries (LOOT ${Boost_LIBRARIES} ${LOOT_GUI_LIBS})
##############################
# Set Target-Specific Flags
##############################
IF (MSVC)
set_target_properties (LOOT PROPERTIES CMAKE_EXE_LINKER_FLAGS "/SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE")
ENDIF ()
IF (CMAKE_SYSTEM_NAME MATCHES "Windows")
IF (BUILD_SHARED_LIBS)
set_target_properties (loot${PROJECT_ARCH} PROPERTIES COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS} LOOT_EXPORT")
ELSE ()
set_target_properties (loot${PROJECT_ARCH} PROPERTIES COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS} LOOT_STATIC")
ENDIF ()
ENDIF ()
##############################
# Post-Build Steps
##############################
add_custom_command(
TARGET LOOT
POST_BUILD
+1
View File
@@ -17,6 +17,7 @@ LOOT uses [CMake](http://cmake.org) to generate build files, and requires the fo
* [Alphanum](http://www.davekoelle.com/files/alphanum.hpp)
* [Boost](http://www.boost.org) v1.56.0
* [Chromium Embedded Framework](https://code.google.com/p/chromiumembedded/) branch 2062
* [Google Test](https://code.google.com/p/googletest/) v1.7: Required to build the LOOT API's tests, but not the API itself or the LOOT application.
* [Libespm](http://github.com/WrinklyNinja/libespm)
* [Libgit2](http://libgit2.github.com/) v0.21.1
* [Libloadorder](http://github.com/WrinklyNinja/libloadorder)
+135
View File
@@ -0,0 +1,135 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_API
#define LOOT_TEST_API
#include "../../api/api.h"
#include "tests/fixtures.h"
TEST(GetVersion, HandlesNullInput) {
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(GetVersion, HandlesValidInput) {
unsigned int vMajor, vMinor, vPatch;
EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch));
}
TEST(IsCompatible, HandlesCompatibleVersion) {
unsigned int vMajor, vMinor, vPatch;
EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch));
EXPECT_TRUE(loot_is_compatible(vMajor, vMinor, vPatch));
// Test somewhat arbitrary variations.
EXPECT_TRUE(loot_is_compatible(vMajor, vMinor + 1, vPatch + 1));
if (vMinor > 0 && vPatch > 0)
EXPECT_TRUE(loot_is_compatible(vMajor, vMinor - 1, vPatch - 1));
}
TEST(IsCompatible, HandlesIncompatibleVersion) {
unsigned int vMajor, vMinor, vPatch;
EXPECT_EQ(loot_ok, loot_get_version(&vMajor, &vMinor, &vPatch));
EXPECT_FALSE(loot_is_compatible(vMajor + 1, vMinor, vPatch));
// Test somewhat arbitrary variations.
EXPECT_FALSE(loot_is_compatible(vMajor + 1, vMinor + 1, vPatch + 1));
if (vMinor > 0 && vPatch > 0)
EXPECT_FALSE(loot_is_compatible(vMajor + 1, vMinor - 1, vPatch - 1));
}
TEST(GetErrorMessage, HandlesInputCorrectly) {
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(Cleanup, CleansUpAfterError) {
// First generate an error.
EXPECT_EQ(loot_error_invalid_args, loot_get_error_message(NULL));
// Check that the error message is non-null.
const char * error;
EXPECT_EQ(loot_ok, loot_get_error_message(&error));
ASSERT_STREQ("Null message pointer passed.", error);
ASSERT_NO_THROW(loot_cleanup());
// Now check that the error message pointer is null.
error = nullptr;
EXPECT_EQ(loot_ok, loot_get_error_message(&error));
EXPECT_EQ(nullptr, error);
}
TEST(Cleanup, HandlesNoError) {
ASSERT_NO_THROW(loot_cleanup());
const char * error = nullptr;
EXPECT_EQ(loot_ok, loot_get_error_message(&error));
EXPECT_EQ(nullptr, error);
}
TEST_F(OblivionTest, CreateDbHandlesValidInputs) {
EXPECT_EQ(loot_ok, loot_create_db(&db, loot_game_tes4, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
ASSERT_NO_THROW(loot_destroy_db(db));
db = nullptr;
// Also test absolute paths.
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, loot_game_tes4, game.string().c_str(), local.string().c_str()));
}
TEST_F(OblivionTest, CreateDbHandlesInvalidHandleInput) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(NULL, loot_game_tes4, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
TEST_F(OblivionTest, CreateDbHandlesInvalidGameType) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, UINT_MAX, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
TEST_F(OblivionTest, CreateDbHandlesInvalidGamePathInput) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, loot_game_tes4, missingPath.string().c_str(), localPath.string().c_str()));
}
TEST_F(OblivionTest, CreateDbHandlesInvalidLocalPathInput) {
EXPECT_EQ(loot_error_invalid_args, loot_create_db(&db, loot_game_tes4, dataPath.parent_path().string().c_str(), missingPath.string().c_str()));
}
#ifdef _WIN32
TEST_F(OblivionTest, CreateDbHandlesNullLocalPath) {
EXPECT_EQ(loot_ok, loot_create_db(&db, loot_game_tes4, dataPath.parent_path().string().c_str(), NULL));
}
#endif
TEST(GameHandleDestroyTest, HandledNullInput) {
ASSERT_NO_THROW(loot_destroy_db(NULL));
}
#endif
+228
View File
@@ -0,0 +1,228 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2013-2014 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_FIXTURES
#define LOOT_TEST_FIXTURES
#include "backend/streams.h"
#include <gtest/gtest.h>
#ifdef __GNUC__ // Workaround for GCC linking error.
#pragma message("GCC detected: Defining BOOST_NO_CXX11_SCOPED_ENUMS and BOOST_NO_SCOPED_ENUMS to avoid linking errors for boost::filesystem::copy_file().")
#define BOOST_NO_CXX11_SCOPED_ENUMS
#define BOOST_NO_SCOPED_ENUMS // For older versions.
#endif
#include <boost/filesystem.hpp>
class GameTest : public ::testing::Test {
protected:
GameTest(const boost::filesystem::path& gameDataPath, const boost::filesystem::path& gameLocalPath)
: dataPath(gameDataPath), localPath(gameLocalPath), missingPath("./missing"), db(nullptr) {}
inline virtual void SetUp() {
ASSERT_NO_THROW(boost::filesystem::create_directories(localPath));
ASSERT_TRUE(boost::filesystem::exists(localPath));
ASSERT_FALSE(boost::filesystem::exists(missingPath));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Different.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Different Master Dependent.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank.esp"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Different.esp"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esp"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Different Master Dependent.esp"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Plugin Dependent.esp"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Different Plugin Dependent.esp"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Blank.esm.missing"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Blank.esp.missing"));
// Ghost a plugin.
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esm.ghost"));
ASSERT_NO_THROW(boost::filesystem::rename(dataPath / "Blank - Master Dependent.esm", dataPath / "Blank - Master Dependent.esm.ghost"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esm.ghost"));
// Write out an empty file.
loot::ofstream out(dataPath / "EmptyFile.esm");
out.close();
ASSERT_TRUE(boost::filesystem::exists(dataPath / "EmptyFile.esm"));
// Write out an non-empty, non-plugin file.
out.open(dataPath / "NotAPlugin.esm");
out << "This isn't a valid plugin file.";
out.close();
ASSERT_TRUE(boost::filesystem::exists(dataPath / "NotAPlugin.esm"));
}
inline virtual void TearDown() {
// Unghost the ghosted plugin.
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esm.ghost"));
ASSERT_NO_THROW(boost::filesystem::rename(dataPath / "Blank - Master Dependent.esm.ghost", dataPath / "Blank - Master Dependent.esm"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Blank - Master Dependent.esm.ghost"));
// Delete generated files.
ASSERT_NO_THROW(boost::filesystem::remove(dataPath / "EmptyFile.esm"));
ASSERT_NO_THROW(boost::filesystem::remove(dataPath / "NotAPlugin.esm"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "EmptyFile.esm"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "NotAPlugin.esm"));
ASSERT_NO_THROW(loot_destroy_db(db));
}
const boost::filesystem::path dataPath;
const boost::filesystem::path localPath;
const boost::filesystem::path missingPath;
loot_db db;
};
class OblivionTest : public GameTest {
protected:
OblivionTest() : GameTest("./Oblivion/Data", "./local/Oblivion") {}
inline virtual void SetUp() {
GameTest::SetUp();
// LOOT expects the game master file to be present, so mock it.
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Oblivion.esm"));
ASSERT_NO_THROW(boost::filesystem::copy_file(dataPath / "Blank.esm", dataPath / "Oblivion.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Oblivion.esm"));
// Oblivion's load order is decided through timestamps, so reset them to a known order before each test.
std::list<std::string> loadOrder = {
"Oblivion.esm",
"Blank.esm",
"Blank - Different.esm",
"Blank - Master Dependent.esm", // Ghosted
"Blank - Different Master Dependent.esm",
"Blank.esp",
"Blank - Different.esp",
"Blank - Master Dependent.esp",
"Blank - Different Master Dependent.esp",
"Blank - Plugin Dependent.esp",
"Blank - Different Plugin Dependent.esp"
};
time_t modificationTime = time(NULL); // Current time.
for (const auto &plugin : loadOrder) {
if (boost::filesystem::exists(dataPath / boost::filesystem::path(plugin + ".ghost"))) {
boost::filesystem::last_write_time(dataPath / boost::filesystem::path(plugin + ".ghost"), modificationTime);
}
else {
boost::filesystem::last_write_time(dataPath / plugin, modificationTime);
}
modificationTime += 60;
}
// Set Oblivion's active plugins to a known list before running the test.
loot::ofstream activePlugins(localPath / "plugins.txt");
activePlugins
<< "Oblivion.esm" << std::endl
<< "Blank.esm" << std::endl;
activePlugins.close();
}
inline virtual void TearDown() {
GameTest::TearDown();
// Delete the mock Oblivion.esm.
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Oblivion.esm"));
ASSERT_NO_THROW(boost::filesystem::remove(dataPath / "Oblivion.esm"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Oblivion.esm"));
// Delete existing plugins.txt.
ASSERT_NO_THROW(boost::filesystem::remove(localPath / "plugins.txt"));
};
};
class OblivionAPIOperationsTest : public OblivionTest {
protected:
inline virtual void SetUp() {
OblivionTest::SetUp();
ASSERT_EQ(loot_ok, loot_create_db(&db, loot_game_tes4, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
};
class SkyrimTest : public GameTest {
protected:
SkyrimTest() : GameTest("./Skyrim/Data", "./local/Skyrim") {}
inline virtual void SetUp() {
GameTest::SetUp();
// Can't change Skyrim's main master file, so mock it.
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Skyrim.esm"));
ASSERT_NO_THROW(boost::filesystem::copy_file(dataPath / "Blank.esm", dataPath / "Skyrim.esm"));
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Skyrim.esm"));
// Set Skyrim's load order to a known list before running the test.
loot::ofstream loadOrder(localPath / "loadorder.txt");
loadOrder
<< "Skyrim.esm" << std::endl
<< "Blank.esm" << std::endl
<< "Blank - Different.esm" << std::endl
<< "Blank - Master Dependent.esm" << std::endl // Ghosted
<< "Blank - Different Master Dependent.esm" << std::endl
<< "Blank.esp" << std::endl
<< "Blank - Different.esp" << std::endl
<< "Blank - Master Dependent.esp" << std::endl
<< "Blank - Different Master Dependent.esp" << std::endl
<< "Blank - Plugin Dependent.esp" << std::endl
<< "Blank - Different Plugin Dependent.esp" << std::endl;
loadOrder.close();
// Set Skyrim's active plugins to a known list before running the test.
loot::ofstream activePlugins(localPath / "plugins.txt");
activePlugins
<< "Blank.esm" << std::endl;
activePlugins.close();
}
inline virtual void TearDown() {
GameTest::TearDown();
// Delete the mock Skyrim.esm.
ASSERT_TRUE(boost::filesystem::exists(dataPath / "Skyrim.esm"));
ASSERT_NO_THROW(boost::filesystem::remove(dataPath / "Skyrim.esm"));
ASSERT_FALSE(boost::filesystem::exists(dataPath / "Skyrim.esm"));
// Delete existing plugins.txt and loadorder.txt.
ASSERT_NO_THROW(boost::filesystem::remove(localPath / "plugins.txt"));
ASSERT_NO_THROW(boost::filesystem::remove(localPath / "loadorder.txt"));
};
};
class SkyrimAPIOperationsTest : public SkyrimTest {
protected:
inline virtual void SetUp() {
SkyrimTest::SetUp();
ASSERT_EQ(loot_ok, loot_create_db(&db, loot_game_tes5, dataPath.parent_path().string().c_str(), localPath.string().c_str()));
}
};
#endif
+30
View File
@@ -0,0 +1,30 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#include "tests/api/api.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}