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).
This commit is contained in:
Martchus 2017-10-30 23:01:07 +01:00
parent 3c16d2beb8
commit 2bb4aa36a4
3 changed files with 75 additions and 20 deletions

View File

@ -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 "$<TARGET_FILE:${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}>")
@ -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()

View File

@ -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 <cstdlib>
#include <cstring>
@ -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

View File

@ -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;