diff --git a/cmake/modules/TestTarget.cmake b/cmake/modules/TestTarget.cmake index 3887dfd..426fa9b 100644 --- a/cmake/modules/TestTarget.cmake +++ b/cmake/modules/TestTarget.cmake @@ -160,7 +160,7 @@ if(CPP_UNIT_LIB OR META_NO_CPP_UNIT) LINK_SEARCH_END_STATIC ${STATIC_LINKAGE} ) - # make a test recognized by ctest + # make the test recognized by ctest unset(RUN_TESTS_APPLICATION_ARG) if(META_PROJECT_TYPE STREQUAL "application") set(RUN_TESTS_APPLICATION_ARGS -a "$") @@ -302,6 +302,9 @@ if(CPP_UNIT_LIB OR META_NO_CPP_UNIT) endif() endif() + # add a file called "srcdirref" to the build directory; this file contains the path of the sources so tests can easily find test files contained in the source directory + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/srcdirref" "${CMAKE_CURRENT_SOURCE_DIR}") + set(META_HAVE_TESTS YES) else() diff --git a/tests/testutils.cpp b/tests/testutils.cpp index 69d427f..68c4c68 100644 --- a/tests/testutils.cpp +++ b/tests/testutils.cpp @@ -5,6 +5,8 @@ #include "../conversion/stringconversion.h" #include "../io/ansiescapecodes.h" #include "../io/catchiofailure.h" +#include "../io/misc.h" +#include "../io/path.h" #include #include @@ -56,13 +58,13 @@ TestApplication::TestApplication(int argc, char **argv) } m_instance = this; - // read TEST_FILE_PATH environment variable - if (const char *testFilesPathEnv = getenv("TEST_FILE_PATH")) { - if (const auto len = strlen(testFilesPathEnv)) { - m_testFilesPathEnvValue.reserve(len + 1); - m_testFilesPathEnvValue += testFilesPathEnv; - m_testFilesPathEnvValue += '/'; - } + // determine fallback path for testfiles which is used when --test-files-path/-p not present + // -> read TEST_FILE_PATH environment variable + readFallbackTestfilePathFromEnv(); + // -> find source directory if TEST_FILE_PATH not present + const bool fallbackIsSourceDir = m_fallbackTestFilesPath.empty(); + if (fallbackIsSourceDir) { + readFallbackTestfilePathFromSrcRef(); } // setup argument parser @@ -95,13 +97,13 @@ TestApplication::TestApplication(int argc, char **argv) cerr << "Directories used to search for testfiles:" << endl; if (m_testFilesPathArg.isPresent()) { if (*m_testFilesPathArg.values().front()) { - cerr << ((m_testFilesPathArgValue = m_testFilesPathArg.values().front()) += '/') << endl; + cerr << ((m_testFilesPath = m_testFilesPathArg.values().front()) += '/') << endl; } else { - cerr << (m_testFilesPathArgValue = "./") << endl; + cerr << (m_testFilesPath = "./") << endl; } } - if (!m_testFilesPathEnvValue.empty()) { - cerr << m_testFilesPathEnvValue << endl; + if (!m_fallbackTestFilesPath.empty() && m_testFilesPath != m_fallbackTestFilesPath) { + cerr << m_fallbackTestFilesPath << endl; } cerr << "./testfiles/" << endl << endl; cerr << "Directory used to store working copies:" << endl; @@ -119,9 +121,9 @@ TestApplication::TestApplication(int argc, char **argv) } } else { if (m_testFilesPathArg.isPresent()) { - m_workingDir = m_testFilesPathArgValue + "workingdir/"; - } else if (!m_testFilesPathEnvValue.empty()) { - m_workingDir = m_testFilesPathEnvValue + "workingdir/"; + m_workingDir = m_testFilesPath + "workingdir/"; + } else if (!m_fallbackTestFilesPath.empty() && !fallbackIsSourceDir) { + m_workingDir = m_fallbackTestFilesPath + "workingdir/"; } else { m_workingDir = "./testfiles/workingdir/"; } @@ -155,16 +157,16 @@ string TestApplication::testFilePath(const string &name) const // check the path specified by command line argument if (m_testFilesPathArg.isPresent()) { - file.open(path = m_testFilesPathArgValue + name, ios_base::in); + file.open(path = m_testFilesPath + name, ios_base::in); if (file.good()) { return path; } } // check the path specified by environment variable - if (!m_testFilesPathEnvValue.empty()) { + if (!m_fallbackTestFilesPath.empty()) { file.clear(); - file.open(path = m_testFilesPathEnvValue + name, ios_base::in); + file.open(path = m_fallbackTestFilesPath + name, ios_base::in); if (file.good()) { return path; } @@ -384,6 +386,53 @@ int TestApplication::execApp(const char *const *args, string &output, string &er return execAppInternal(appPath, args, output, errors, suppressLogging, timeout, newProfilingPath); } +void TestApplication::readFallbackTestfilePathFromEnv() +{ + if (const char *testFilesPathEnv = getenv("TEST_FILE_PATH")) { + if (const auto len = strlen(testFilesPathEnv)) { + m_fallbackTestFilesPath.reserve(len + 1); + m_fallbackTestFilesPath += testFilesPathEnv; + m_fallbackTestFilesPath += '/'; + } + } +} + +void TestApplication::readFallbackTestfilePathFromSrcRef() +{ + try { + // read "srcdirref" file which should contain the path of the source directory; this file should have been + // create by the CMake module "TestTarget.cmake" + const string srcDirContent(readFile("srcdirref", 2 * 1024)); + if (srcDirContent.empty()) { + cerr << Phrases::Warning << "The file \"srcdirref\" is empty." << Phrases::EndFlush; + return; + } + + // check whether the referenced source directory contains a "testfiles" directory +#ifdef PLATFORM_UNIX // directoryEntries() is not implemented under Windows so we can only to the check under UNIX + bool hasTestfilesDir = false; + for (const string dir : directoryEntries(srcDirContent.data(), DirectoryEntryType::Directory)) { + if (dir == "testfiles") { + hasTestfilesDir = true; + break; + } + } + if (!hasTestfilesDir) { + cerr << Phrases::Warning + << "The source directory referenced by the file \"srcdirref\" does not contain a \"testfiles\" directory or does not exist." + << Phrases::End << "Referenced source directory: " << srcDirContent << endl; + return; + } +#endif + + m_fallbackTestFilesPath = move(srcDirContent); + m_fallbackTestFilesPath += "/testfiles/"; + } catch (...) { + // the "srcdirref" file likely just does not exist, so ignore the error case for now + catchIoFailure(); + } +} + /*! * \brief Executes an application with the specified \a args. * \remarks diff --git a/tests/testutils.h b/tests/testutils.h index f1abe82..ff07085 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -37,14 +37,17 @@ public: static const char *appPath(); private: + void readFallbackTestfilePathFromEnv(); + void readFallbackTestfilePathFromSrcRef(); + ApplicationUtilities::ArgumentParser m_parser; ApplicationUtilities::HelpArgument m_helpArg; ApplicationUtilities::Argument m_testFilesPathArg; ApplicationUtilities::Argument m_applicationPathArg; ApplicationUtilities::Argument m_workingDirArg; ApplicationUtilities::Argument m_unitsArg; - std::string m_testFilesPathArgValue; - std::string m_testFilesPathEnvValue; + std::string m_testFilesPath; + std::string m_fallbackTestFilesPath; std::string m_workingDir; bool m_valid; static TestApplication *m_instance;