diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 63f5bfb45e..1e4e58fd6a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -72,6 +72,7 @@ Ubuntu_GCC_preprocess: - cmake --install . - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_test_suite --gtest_output="xml:openmw_tests.xml"; fi - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw-cs-tests --gtest_output="xml:openmw_cs_tests.xml"; fi + - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw-iniimporter-tests --gtest_output="xml:openmw_iniimporter_tests.xml"; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_esm_refid_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_settings_access_benchmark; fi diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index 0edd38628f..2a5a33d841 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -49,6 +49,7 @@ if [[ $CI_CLANG_TIDY ]]; then -DCMAKE_CXX_CLANG_TIDY="clang-tidy;--warnings-as-errors=*" -DBUILD_UNITTESTS=ON -DBUILD_OPENCS_TESTS=ON + -DBUILD_TOOL_TESTS=ON -DBUILD_BENCHMARKS=ON ) fi @@ -105,6 +106,7 @@ if [[ "${BUILD_TESTS_ONLY}" ]]; then -DBUILD_NIFTEST=OFF \ -DBUILD_UNITTESTS=${BUILD_UNITTESTS} \ -DBUILD_OPENCS_TESTS=${BUILD_UNITTESTS} \ + -DBUILD_TOOL_TESTS=${BUILD_UNITTESTS} \ -DBUILD_BENCHMARKS=${BUILD_BENCHMARKS} \ .. elif [[ "${BUILD_OPENMW_ONLY}" ]]; then diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index e11ceb499d..83c3acd187 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -1119,6 +1119,7 @@ fi if [ -n "${TEST_FRAMEWORK}" ]; then add_cmake_opts -DBUILD_UNITTESTS=ON add_cmake_opts -DBUILD_OPENCS_TESTS=ON + add_cmake_opts -DBUILD_TOOL_TESTS=ON fi if [ -n "$ACTIVATE_MSVC" ]; then diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ea891b56d..d0c919a892 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ option(BUILD_BENCHMARKS "Build benchmarks with Google Benchmark" OFF) option(BUILD_NAVMESHTOOL "Build navmesh tool" ON) option(BUILD_BULLETOBJECTTOOL "Build Bullet object tool" ON) option(BUILD_OPENCS_TESTS "Build OpenMW Construction Set tests" OFF) +option(BUILD_TOOL_TESTS "Build OpenMW related tool tests" OFF) set(OpenGL_GL_PREFERENCE LEGACY) # Use LEGACY as we use GL2; GLNVD is for GL3 and up. @@ -633,7 +634,7 @@ if (BUILD_LAUNCHER) add_subdirectory( apps/launcher ) endif() -if (BUILD_MWINIIMPORTER) +if (BUILD_MWINIIMPORTER OR BUILD_TOOL_TESTS) add_subdirectory( apps/mwiniimporter ) endif() @@ -674,6 +675,10 @@ if (BUILD_OPENCS_TESTS) add_subdirectory(apps/opencs_tests) endif() +if (BUILD_TOOL_TESTS) + add_subdirectory( apps/mwiniimporter_tests ) +endif() + if (WIN32) if (MSVC) foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) diff --git a/apps/mwiniimporter_tests/CMakeLists.txt b/apps/mwiniimporter_tests/CMakeLists.txt new file mode 100644 index 0000000000..6692c6021d --- /dev/null +++ b/apps/mwiniimporter_tests/CMakeLists.txt @@ -0,0 +1,26 @@ +file(GLOB INIIMPORTER_TESTS_SRC_FILES + main.cpp +) + +source_group(apps\\openmw-iniimporter-tests FILES ${INIIMPORTER_TESTS_SRC_FILES}) + +openmw_add_executable(openmw-iniimporter-tests ${INIIMPORTER_TESTS_SRC_FILES}) + +target_include_directories(openmw-iniimporter-tests SYSTEM PRIVATE ${GTEST_INCLUDE_DIRS}) +target_include_directories(openmw-iniimporter-tests SYSTEM PRIVATE ${GMOCK_INCLUDE_DIRS}) + +target_link_libraries(openmw-iniimporter-tests PRIVATE + GTest::GTest + GMock::GMock +) + +if (BUILD_WITH_CODE_COVERAGE) + target_compile_options(openmw-iniimporter-tests PRIVATE --coverage) + target_link_libraries(openmw-iniimporter-tests PRIVATE gcov) +endif() + +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) + target_precompile_headers(openmw-iniimporter-tests PRIVATE + + ) +endif() diff --git a/apps/mwiniimporter_tests/main.cpp b/apps/mwiniimporter_tests/main.cpp new file mode 100644 index 0000000000..2c40db293d --- /dev/null +++ b/apps/mwiniimporter_tests/main.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#elif defined(__APPLE__) +#include +#else +#include +#endif + +std::filesystem::path getExecutablePath() +{ +#ifdef _WIN32 + WCHAR buffer[MAX_PATH]; + GetModuleFileNameW(NULL, buffer, MAX_PATH); + std::wstring exe_path(buffer); + return std::filesystem::path(exe_path).parent_path(); +#elif defined(__APPLE__) + char buffer[PATH_MAX]; + uint32_t bufsize = sizeof(buffer); + _NSGetExecutablePath(buffer, &bufsize); + return std::filesystem::path(buffer).parent_path(); +#else + char buffer[PATH_MAX]; + ssize_t len = ::readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); + if (len == -1) + { + throw std::runtime_error("Could not retrieve executable path"); + } + buffer[len] = '\0'; + std::string exe_path(buffer); + return std::filesystem::path(exe_path).parent_path(); +#endif +} + +int runBinary( + const std::filesystem::path& binaryPath, const std::filesystem::path& iniPath, const std::filesystem::path& cfgPath) +{ +#ifdef _WIN32 + std::wstring wBinaryPath = binaryPath.native(); + std::wstring wIniPath = iniPath.native(); + std::wstring wCfgPath = cfgPath.native(); + std::wstringstream cmd; + cmd << wBinaryPath << L" -i " << wIniPath << L" -c " << wCfgPath; + return _wsystem(cmd.str().c_str()); +#else + std::stringstream cmd; + cmd << binaryPath << " -i " << iniPath << " -c " << cfgPath; + return std::system(cmd.str().c_str()); +#endif +} + +struct TestParam +{ + std::string name; + std::string fileName; +}; + +const std::vector testParams = { { "ascii", "ascii" }, { "unicode", "(╯°□°)╯︵ ┻━┻" }, { "emoji", "💩" } }; + +class IniImporterTest : public ::testing::TestWithParam +{ +}; + +TEST_P(IniImporterTest, TestIniImport) +{ + auto const& param = IniImporterTest::GetParam(); + + // Create temporary file + std::string iniData = R"([Archives] +Archive 0=game1.bsa +Archive 1=game2.bsa +)"; + std::filesystem::path tempIniFile = std::filesystem::temp_directory_path() / (param.fileName + ".ini"); + std::ofstream tempFile(tempIniFile); + tempFile << iniData; + tempFile.close(); + std::filesystem::path tempCfgFile = std::filesystem::temp_directory_path() / (param.fileName + ".cfg"); + std::filesystem::path binaryPath = getExecutablePath() / "openmw-iniimporter"; + + int ret = runBinary(binaryPath, tempIniFile, tempCfgFile); + ASSERT_EQ(ret, 0); + + // Verify the cfg file was created and has the expected contents + std::ifstream ifs(tempCfgFile); + ASSERT_TRUE(ifs.good()); + + std::string cfgData = R"(fallback-archive=Morrowind.bsa +fallback-archive=game1.bsa +fallback-archive=game2.bsa +)"; + + std::stringstream actual; + actual << ifs.rdbuf(); + + ASSERT_EQ(cfgData, actual.str()); + + // Clean up temporary file + std::filesystem::remove(tempCfgFile); + std::filesystem::remove(tempIniFile); +} + +INSTANTIATE_TEST_SUITE_P(IniImporterTests, IniImporterTest, ::testing::ValuesIn(testParams)); + +int main(int argc, char* argv[]) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file