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
namespace Helper {
struct ArgumentValueConversionError {
struct CPP_UTILITIES_EXPORT ArgumentValueConversionError {
const char *const errorMessage;
const char *const valueToConvert;
const char *const targetTypeName;

View File

@ -29,6 +29,19 @@ using namespace TestUtilities::Literals;
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.
*/

View File

@ -7,6 +7,7 @@
#include "../io/catchiofailure.h"
#include "../io/misc.h"
#include "../io/path.h"
#include "../io/nativefilestream.h"
#include <cerrno>
#include <cstdlib>
@ -23,6 +24,10 @@
#include <unistd.h>
#endif
#ifdef PLATFORM_WINDOWS
#include <windows.h>
#endif
using namespace std;
using namespace ApplicationUtilities;
using namespace ConversionUtilities;
@ -34,6 +39,52 @@ using namespace IoUtilities;
*/
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;
/*!
@ -175,31 +226,25 @@ string TestApplication::testFilePath(const string &name) const
// check the path specified by command line argument or via environment variable
if (!m_testFilesPath.empty()) {
file.open(path = m_testFilesPath + name, ios_base::in);
if (file.good()) {
if (fileExists(path = m_testFilesPath + name)) {
return path;
}
}
// check the fallback path (value from environment variable or source directory)
if (!m_fallbackTestFilesPath.empty()) {
file.clear();
file.open(path = m_fallbackTestFilesPath + name, ios_base::in);
if (file.good()) {
if (fileExists(path = m_fallbackTestFilesPath + name)) {
return path;
}
}
// file still not found -> return default path
file.clear();
file.open(path = "./testfiles/" + name, ios_base::in);
if (!file.good()) {
if (!fileExists(path = "./testfiles/" + name)) {
cerr << Phrases::Warning << "The testfile \"" << path << "\" can not be located." << Phrases::EndFlush;
}
return path;
}
#ifdef PLATFORM_UNIX
/*!
* \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
{
// ensure working directory is present
struct stat currentStat;
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)) {
if (!dirExists(m_workingDir) && !makeDir(m_workingDir)) {
cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush;
return string();
}
@ -232,11 +275,11 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode
currentLevel += *i;
// continue if subdirectory level already exists
if (!stat(currentLevel.c_str(), &currentStat) && S_ISDIR(currentStat.st_mode)) {
if (dirExists(currentLevel)) {
continue;
}
// 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;
}
// fail otherwise
@ -254,7 +297,7 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode
const auto origFilePath(testFilePath(name));
auto workingCopyPath(m_workingDir + name);
size_t workingCopyPathAttempt = 0;
fstream origFile, workingCopy;
NativeFileStream origFile, workingCopy;
origFile.open(origFilePath, ios_base::in | ios_base::binary);
if (origFile.fail()) {
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();
}
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
workingCopyPath = argsToString(m_workingDir, name, '.', ++workingCopyPathAttempt);
workingCopy.clear();
@ -307,6 +350,7 @@ string TestApplication::workingCopyPath(const string &name) const
return workingCopyPathMode(name, WorkingCopyMode::CreateCopy);
}
#ifdef PLATFORM_UNIX
/*!
* \brief Executes an application with the specified \a args.
* \remarks Provides internal implementation of execApp() and execHelperApp().

View File

@ -26,9 +26,9 @@ public:
operator bool() const;
std::string testFilePath(const std::string &name) const;
#ifdef PLATFORM_UNIX
std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode) 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;
#endif
bool unitsSpecified() const;
@ -107,7 +107,6 @@ inline CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &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.
* \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);
}
#ifdef PLATFORM_UNIX
/*!
* \brief Convenience function which executes the application to be tested with the specified \a args.
* \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(
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