From 2bb4aa36a4dd6eec0c9d620273f7f1e6a89d7b5e Mon Sep 17 00:00:00 2001 From: Martchus Date: Mon, 30 Oct 2017 23:01:07 +0100 Subject: [PATCH] Let tests find the testfiles from sources without extra args Currently the path of the testfiles always had to be specified either manually using the -p argument or by running the tests via the build system targets. The first option is annoying and the second option not so nice when using Qt Creator and the debugger. This commit allows tests to find the testfiles from the source directory automatically (as fallback). This is achieved by creating a file containing the path of the source directory with CMake. Note that this file can only be found if the working directory is set to the binary directory (default in Qt Creator). --- cmake/modules/TestTarget.cmake | 5 +- tests/testutils.cpp | 83 +++++++++++++++++++++++++++------- tests/testutils.h | 7 ++- 3 files changed, 75 insertions(+), 20 deletions(-) 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;