Make tests compile under Windows
This commit is contained in:
parent
749eea2ab6
commit
25ef4e28a2
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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(), ¤tStat) || !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(), ¤tStat) && 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(), ¤tStat)) {
|
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().
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue