diff --git a/.travis.yml b/.travis.yml
index 52942e4d..1c3ed166 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 231ec74f..7ffe9664 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/README.md b/README.md
index 66f21645..abafdf0f 100644
--- a/README.md
+++ b/README.md
@@ -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)
diff --git a/src/tests/api/api.h b/src/tests/api/api.h
new file mode 100644
index 00000000..53781f4e
--- /dev/null
+++ b/src/tests/api/api.h
@@ -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
+.
+*/
+
+#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
diff --git a/src/tests/fixtures.h b/src/tests/fixtures.h
new file mode 100644
index 00000000..179a61f0
--- /dev/null
+++ b/src/tests/fixtures.h
@@ -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
+.
+*/
+
+#ifndef LOOT_TEST_FIXTURES
+#define LOOT_TEST_FIXTURES
+
+#include "backend/streams.h"
+
+#include
+
+#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
+
+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 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
\ No newline at end of file
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
new file mode 100644
index 00000000..a5824db2
--- /dev/null
+++ b/src/tests/main.cpp
@@ -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
+ .
+ */
+
+#include "tests/api/api.h"
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}