Make tests compile under Windows

This commit is contained in:
Martchus 2018-09-29 20:52:13 +02:00
parent 749eea2ab6
commit 25ef4e28a2
4 changed files with 77 additions and 20 deletions

View File

@ -148,7 +148,7 @@ template <typename TargetType, Traits::EnableIf<std::is_arithmetic<TargetType>>
/// \cond /// \cond
namespace Helper { namespace Helper {
struct ArgumentValueConversionError { struct CPP_UTILITIES_EXPORT ArgumentValueConversionError {
const char *const errorMessage; const char *const errorMessage;
const char *const valueToConvert; const char *const valueToConvert;
const char *const targetTypeName; const char *const targetTypeName;

View File

@ -29,6 +29,19 @@ using namespace TestUtilities::Literals;
using namespace CPPUNIT_NS; using namespace CPPUNIT_NS;
#ifdef PLATFORM_WINDOWS
void setenv(const char *variableName, const char *value, bool replace)
{
VAR_UNUSED(replace)
_putenv_s(variableName, value);
}
void unsetenv(const char *variableName)
{
_putenv_s(variableName, "");
}
#endif
/*! /*!
* \brief The ArgumentParserTests class tests the ArgumentParser and Argument classes. * \brief The ArgumentParserTests class tests the ArgumentParser and Argument classes.
*/ */

View File

@ -7,6 +7,7 @@
#include "../io/catchiofailure.h" #include "../io/catchiofailure.h"
#include "../io/misc.h" #include "../io/misc.h"
#include "../io/path.h" #include "../io/path.h"
#include "../io/nativefilestream.h"
#include <cerrno> #include <cerrno>
#include <cstdlib> #include <cstdlib>
@ -23,6 +24,10 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef PLATFORM_WINDOWS
#include <windows.h>
#endif
using namespace std; using namespace std;
using namespace ApplicationUtilities; using namespace ApplicationUtilities;
using namespace ConversionUtilities; using namespace ConversionUtilities;
@ -34,6 +39,52 @@ using namespace IoUtilities;
*/ */
namespace TestUtilities { namespace TestUtilities {
bool fileSystemItemExists(const string &path)
{
#ifdef PLATFORM_UNIX
struct stat res;
return stat(path.data(), &res) == 0;
#else
const auto widePath(NativeFileStream::makeWidePath(path));
const auto fileType(GetFileAttributesW(widePath.get()));
return fileType != INVALID_FILE_ATTRIBUTES;
#endif
}
bool fileExists(const string &path)
{
#ifdef PLATFORM_UNIX
struct stat res;
return stat(path.data(), &res) == 0 && !S_ISDIR(res.st_mode);
#else
const auto widePath(NativeFileStream::makeWidePath(path));
const auto fileType(GetFileAttributesW(widePath.get()));
return fileType != INVALID_FILE_ATTRIBUTES && fileType != FILE_ATTRIBUTE_DIRECTORY;
#endif
}
bool dirExists(const string &path)
{
#ifdef PLATFORM_UNIX
struct stat res;
return stat(path.data(), &res) == 0 && S_ISDIR(res.st_mode);
#else
const auto widePath(NativeFileStream::makeWidePath(path));
const auto fileType(GetFileAttributesW(widePath.get()));
return fileType != INVALID_FILE_ATTRIBUTES && fileType == FILE_ATTRIBUTE_DIRECTORY;
#endif
}
bool makeDir(const string &path)
{
#ifdef PLATFORM_UNIX
return mkdir(path.data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
#else
const auto widePath(NativeFileStream::makeWidePath(path));
return CreateDirectoryW(widePath.get(), nullptr) || GetLastError() == ERROR_ALREADY_EXISTS;
#endif
}
TestApplication *TestApplication::m_instance = nullptr; TestApplication *TestApplication::m_instance = nullptr;
/*! /*!
@ -175,31 +226,25 @@ string TestApplication::testFilePath(const string &name) const
// check the path specified by command line argument or via environment variable // check the path specified by command line argument or via environment variable
if (!m_testFilesPath.empty()) { if (!m_testFilesPath.empty()) {
file.open(path = m_testFilesPath + name, ios_base::in); if (fileExists(path = m_testFilesPath + name)) {
if (file.good()) {
return path; return path;
} }
} }
// check the fallback path (value from environment variable or source directory) // check the fallback path (value from environment variable or source directory)
if (!m_fallbackTestFilesPath.empty()) { if (!m_fallbackTestFilesPath.empty()) {
file.clear(); if (fileExists(path = m_fallbackTestFilesPath + name)) {
file.open(path = m_fallbackTestFilesPath + name, ios_base::in);
if (file.good()) {
return path; return path;
} }
} }
// file still not found -> return default path // file still not found -> return default path
file.clear(); if (!fileExists(path = "./testfiles/" + name)) {
file.open(path = "./testfiles/" + name, ios_base::in);
if (!file.good()) {
cerr << Phrases::Warning << "The testfile \"" << path << "\" can not be located." << Phrases::EndFlush; cerr << Phrases::Warning << "The testfile \"" << path << "\" can not be located." << Phrases::EndFlush;
} }
return path; return path;
} }
#ifdef PLATFORM_UNIX
/*! /*!
* \brief Returns the full path to a working copy of the test file with the specified \a name. * \brief Returns the full path to a working copy of the test file with the specified \a name.
* *
@ -211,9 +256,7 @@ string TestApplication::testFilePath(const string &name) const
string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode mode) const string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode mode) const
{ {
// ensure working directory is present // ensure working directory is present
struct stat currentStat; if (!dirExists(m_workingDir) && !makeDir(m_workingDir)) {
if ((stat(m_workingDir.c_str(), &currentStat) || !S_ISDIR(currentStat.st_mode))
&& mkdir(m_workingDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush; cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush;
return string(); return string();
} }
@ -232,11 +275,11 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode
currentLevel += *i; currentLevel += *i;
// continue if subdirectory level already exists // continue if subdirectory level already exists
if (!stat(currentLevel.c_str(), &currentStat) && S_ISDIR(currentStat.st_mode)) { if (dirExists(currentLevel)) {
continue; continue;
} }
// continue if we can successfully create the directory // continue if we can successfully create the directory
if (!mkdir(currentLevel.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { if (!makeDir(currentLevel)) {
continue; continue;
} }
// fail otherwise // fail otherwise
@ -254,7 +297,7 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode
const auto origFilePath(testFilePath(name)); const auto origFilePath(testFilePath(name));
auto workingCopyPath(m_workingDir + name); auto workingCopyPath(m_workingDir + name);
size_t workingCopyPathAttempt = 0; size_t workingCopyPathAttempt = 0;
fstream origFile, workingCopy; NativeFileStream origFile, workingCopy;
origFile.open(origFilePath, ios_base::in | ios_base::binary); origFile.open(origFilePath, ios_base::in | ios_base::binary);
if (origFile.fail()) { if (origFile.fail()) {
cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening original file \"" cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening original file \""
@ -263,7 +306,7 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode
return string(); return string();
} }
workingCopy.open(workingCopyPath, ios_base::out | ios_base::binary | ios_base::trunc); workingCopy.open(workingCopyPath, ios_base::out | ios_base::binary | ios_base::trunc);
while (workingCopy.fail() && !stat(workingCopyPath.c_str(), &currentStat)) { while (workingCopy.fail() && fileSystemItemExists(workingCopyPath)) {
// adjust the working copy path if the target file already exists and can not be truncated // adjust the working copy path if the target file already exists and can not be truncated
workingCopyPath = argsToString(m_workingDir, name, '.', ++workingCopyPathAttempt); workingCopyPath = argsToString(m_workingDir, name, '.', ++workingCopyPathAttempt);
workingCopy.clear(); workingCopy.clear();
@ -307,6 +350,7 @@ string TestApplication::workingCopyPath(const string &name) const
return workingCopyPathMode(name, WorkingCopyMode::CreateCopy); return workingCopyPathMode(name, WorkingCopyMode::CreateCopy);
} }
#ifdef PLATFORM_UNIX
/*! /*!
* \brief Executes an application with the specified \a args. * \brief Executes an application with the specified \a args.
* \remarks Provides internal implementation of execApp() and execHelperApp(). * \remarks Provides internal implementation of execApp() and execHelperApp().

View File

@ -26,9 +26,9 @@ public:
operator bool() const; operator bool() const;
std::string testFilePath(const std::string &name) const; std::string testFilePath(const std::string &name) const;
#ifdef PLATFORM_UNIX
std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode) const; std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode) const;
std::string workingCopyPath(const std::string &name) const; std::string workingCopyPath(const std::string &name) const;
#ifdef PLATFORM_UNIX
int execApp(const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1) const; int execApp(const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1) const;
#endif #endif
bool unitsSpecified() const; bool unitsSpecified() const;
@ -107,7 +107,6 @@ inline CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &name)
return TestApplication::instance()->testFilePath(name); return TestApplication::instance()->testFilePath(name);
} }
#ifdef PLATFORM_UNIX
/*! /*!
* \brief Convenience function which returns the full path to a working copy of the test file with the specified \a name. * \brief Convenience function which returns the full path to a working copy of the test file with the specified \a name.
* \remarks A TestApplication must be present. * \remarks A TestApplication must be present.
@ -128,6 +127,7 @@ inline CPP_UTILITIES_EXPORT std::string workingCopyPathMode(const std::string &n
return TestApplication::instance()->workingCopyPathMode(name, mode); return TestApplication::instance()->workingCopyPathMode(name, mode);
} }
#ifdef PLATFORM_UNIX
/*! /*!
* \brief Convenience function which executes the application to be tested with the specified \a args. * \brief Convenience function which executes the application to be tested with the specified \a args.
* \remarks A TestApplication must be present. * \remarks A TestApplication must be present.
@ -140,7 +140,7 @@ inline CPP_UTILITIES_EXPORT int execApp(const char *const *args, std::string &ou
CPP_UTILITIES_EXPORT int execHelperApp( CPP_UTILITIES_EXPORT int execHelperApp(
const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1); const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1);
#endif #endif // PLATFORM_UNIX
/*! /*!
* \brief The AsHexNumber class allows printing values asserted with cppunit (or similar test framework) using the * \brief The AsHexNumber class allows printing values asserted with cppunit (or similar test framework) using the