utilize creation of working copies for tests
This commit is contained in:
parent
9abe04ce06
commit
af5b879506
|
@ -18,10 +18,6 @@ using namespace IoUtilities;
|
||||||
|
|
||||||
using namespace CPPUNIT_NS;
|
using namespace CPPUNIT_NS;
|
||||||
|
|
||||||
namespace UnitTests {
|
|
||||||
extern string testFilesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
class IoTests : public TestFixture
|
class IoTests : public TestFixture
|
||||||
{
|
{
|
||||||
CPPUNIT_TEST_SUITE(IoTests);
|
CPPUNIT_TEST_SUITE(IoTests);
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ApplicationUtilities;
|
using namespace ApplicationUtilities;
|
||||||
|
|
||||||
|
@ -16,7 +18,7 @@ TestApplication *TestApplication::m_instance = nullptr;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \class TestApplication
|
* \class TestApplication
|
||||||
* \brief The TestApplication class simplifies writing test applications.
|
* \brief The TestApplication class simplifies writing test applications that require opening test files.
|
||||||
* \remarks Only one instance is allowed at a time (singletone class).
|
* \remarks Only one instance is allowed at a time (singletone class).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -26,12 +28,16 @@ TestApplication *TestApplication::m_instance = nullptr;
|
||||||
*/
|
*/
|
||||||
TestApplication::TestApplication(int argc, char **argv) :
|
TestApplication::TestApplication(int argc, char **argv) :
|
||||||
m_helpArg(m_parser),
|
m_helpArg(m_parser),
|
||||||
m_testFilesPathArg("test-files-path", "p", "specifies the path of the directory with test files")
|
m_testFilesPathArg("test-files-path", "p", "specifies the path of the directory with test files"),
|
||||||
|
m_workingDirArg("working-dir", "w", "specifies the directory to store working copies of test files")
|
||||||
{
|
{
|
||||||
|
// check whether there is already an instance
|
||||||
if(m_instance) {
|
if(m_instance) {
|
||||||
throw runtime_error("only one TestApplication instance allowed at a time");
|
throw runtime_error("only one TestApplication instance allowed at a time");
|
||||||
}
|
}
|
||||||
m_instance = this;
|
m_instance = this;
|
||||||
|
|
||||||
|
// read TEST_FILE_PATH environment variable
|
||||||
if(const char *testFilesPathEnv = getenv("TEST_FILE_PATH")) {
|
if(const char *testFilesPathEnv = getenv("TEST_FILE_PATH")) {
|
||||||
if(const auto len = strlen(testFilesPathEnv)) {
|
if(const auto len = strlen(testFilesPathEnv)) {
|
||||||
m_testFilesPathEnvValue.reserve(len + 1);
|
m_testFilesPathEnvValue.reserve(len + 1);
|
||||||
|
@ -39,13 +45,20 @@ TestApplication::TestApplication(int argc, char **argv) :
|
||||||
m_testFilesPathEnvValue += '/';
|
m_testFilesPathEnvValue += '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup argument parser
|
||||||
m_testFilesPathArg.setRequiredValueCount(1);
|
m_testFilesPathArg.setRequiredValueCount(1);
|
||||||
m_testFilesPathArg.setValueNames({"path"});
|
m_testFilesPathArg.setValueNames({"path"});
|
||||||
m_testFilesPathArg.setCombinable(true);
|
m_testFilesPathArg.setCombinable(true);
|
||||||
m_parser.setMainArguments({&m_testFilesPathArg, &m_helpArg});
|
m_workingDirArg.setRequiredValueCount(1);
|
||||||
|
m_workingDirArg.setValueNames({"path"});
|
||||||
|
m_workingDirArg.setCombinable(true);
|
||||||
|
m_parser.setMainArguments({&m_testFilesPathArg, &m_workingDirArg, &m_helpArg});
|
||||||
|
|
||||||
|
// parse arguments
|
||||||
try {
|
try {
|
||||||
m_parser.parseArgs(argc, argv);
|
m_parser.parseArgs(argc, argv);
|
||||||
cerr << "Directories used to search for testfiles: " << endl;
|
cerr << "Directories used to search for testfiles:" << endl;
|
||||||
if(m_testFilesPathArg.isPresent()) {
|
if(m_testFilesPathArg.isPresent()) {
|
||||||
if(!m_testFilesPathArg.values().front().empty()) {
|
if(!m_testFilesPathArg.values().front().empty()) {
|
||||||
cerr << (m_testFilesPathArgValue = m_testFilesPathArg.values().front() + '/') << endl;
|
cerr << (m_testFilesPathArgValue = m_testFilesPathArg.values().front() + '/') << endl;
|
||||||
|
@ -57,6 +70,30 @@ TestApplication::TestApplication(int argc, char **argv) :
|
||||||
cerr << m_testFilesPathEnvValue << endl;
|
cerr << m_testFilesPathEnvValue << endl;
|
||||||
}
|
}
|
||||||
cerr << "./testfiles/" << endl << endl;
|
cerr << "./testfiles/" << endl << endl;
|
||||||
|
cerr << "Directory used to store working copies:" << endl;
|
||||||
|
if(m_workingDirArg.isPresent()) {
|
||||||
|
if(!m_workingDirArg.values().front().empty()) {
|
||||||
|
m_workingDir = m_workingDirArg.values().front() + '/';
|
||||||
|
} else {
|
||||||
|
m_workingDir = "./";
|
||||||
|
}
|
||||||
|
} else if(const char *workingDirEnv = getenv("WORKING_DIR")) {
|
||||||
|
if(const auto len = strlen(workingDirEnv)) {
|
||||||
|
m_workingDir.reserve(len + 1);
|
||||||
|
m_workingDir += workingDirEnv;
|
||||||
|
m_workingDir += '/';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(m_testFilesPathArg.isPresent()) {
|
||||||
|
m_workingDir = m_testFilesPathArgValue + "workingdir/";
|
||||||
|
} else if(!m_testFilesPathEnvValue.empty()) {
|
||||||
|
m_workingDir = m_testFilesPathEnvValue + "workingdir/";
|
||||||
|
} else {
|
||||||
|
m_workingDir = "./testfiles/workingdir/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cerr << m_workingDir << endl << endl;
|
||||||
|
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
cerr << "Executing test cases ..." << endl;
|
cerr << "Executing test cases ..." << endl;
|
||||||
} catch(const Failure &failure) {
|
} catch(const Failure &failure) {
|
||||||
|
@ -74,18 +111,22 @@ TestApplication::~TestApplication()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the full path of tbe test file with the specified \a name.
|
* \brief Returns the full path of the test file with the specified \a name.
|
||||||
*/
|
*/
|
||||||
string TestApplication::testFilePath(const string &name) const
|
string TestApplication::testFilePath(const string &name) const
|
||||||
{
|
{
|
||||||
string path;
|
string path;
|
||||||
fstream file;
|
fstream file; // used to check whether the file is present
|
||||||
|
|
||||||
|
// check the path specified by command line argument
|
||||||
if(m_testFilesPathArg.isPresent()) {
|
if(m_testFilesPathArg.isPresent()) {
|
||||||
file.open(path = m_testFilesPathArgValue + name, ios_base::in);
|
file.open(path = m_testFilesPathArgValue + name, ios_base::in);
|
||||||
if(file.good()) {
|
if(file.good()) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check the path specified by environment variable
|
||||||
if(!m_testFilesPathEnvValue.empty()) {
|
if(!m_testFilesPathEnvValue.empty()) {
|
||||||
file.clear();
|
file.clear();
|
||||||
file.open(path = m_testFilesPathEnvValue + name, ios_base::in);
|
file.open(path = m_testFilesPathEnvValue + name, ios_base::in);
|
||||||
|
@ -93,7 +134,41 @@ string TestApplication::testFilePath(const string &name) const
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// file still not found -> return default path
|
||||||
return "./testfiles/" + name;
|
return "./testfiles/" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the full path to a working copy of the test file with the specified \a name.
|
||||||
|
*/
|
||||||
|
string TestApplication::workingCopyPath(const string &name) const
|
||||||
|
{
|
||||||
|
// create file streams
|
||||||
|
fstream origFile, workingCopy;
|
||||||
|
origFile.exceptions(ios_base::badbit | ios_base::failbit);
|
||||||
|
workingCopy.exceptions(ios_base::badbit | ios_base::failbit);
|
||||||
|
|
||||||
|
// ensure working directory is present
|
||||||
|
struct stat currentStat;
|
||||||
|
if(stat(m_workingDir.c_str(), ¤tStat) || !S_ISDIR(currentStat.st_mode)) {
|
||||||
|
if(mkdir(m_workingDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
|
||||||
|
cerr << "Unable to create working copy for \"" << name << "\": can't create working directory." << endl;
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy file
|
||||||
|
try {
|
||||||
|
origFile.open(testFilePath(name), ios_base::in | ios_base::binary);
|
||||||
|
string path = m_workingDir + name;
|
||||||
|
workingCopy.open(path, ios_base::out | ios_base::binary | ios_base::trunc);
|
||||||
|
workingCopy << origFile.rdbuf();
|
||||||
|
return path;
|
||||||
|
} catch(const ios_base::failure &) {
|
||||||
|
cerr << "Unable to create working copy for \"" << name << "\": an IO error occured." << endl;
|
||||||
|
}
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,20 +15,26 @@ public:
|
||||||
|
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
std::string testFilePath(const std::string &name) const;
|
std::string testFilePath(const std::string &name) const;
|
||||||
|
std::string workingCopyPath(const std::string &name) const;
|
||||||
static const TestApplication *instance();
|
static const TestApplication *instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ApplicationUtilities::ArgumentParser m_parser;
|
ApplicationUtilities::ArgumentParser m_parser;
|
||||||
ApplicationUtilities::HelpArgument m_helpArg;
|
ApplicationUtilities::HelpArgument m_helpArg;
|
||||||
ApplicationUtilities::Argument m_testFilesPathArg;
|
ApplicationUtilities::Argument m_testFilesPathArg;
|
||||||
|
ApplicationUtilities::Argument m_workingDirArg;
|
||||||
std::string m_testFilesPathArgValue;
|
std::string m_testFilesPathArgValue;
|
||||||
std::string m_testFilesPathEnvValue;
|
std::string m_testFilesPathEnvValue;
|
||||||
|
std::string m_workingDir;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
static TestApplication *m_instance;
|
static TestApplication *m_instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns whether the TestApplication instance is valid.
|
* \brief Returns whether the TestApplication instance is valid.
|
||||||
|
*
|
||||||
|
* An instance is considered invalid if an error occured when
|
||||||
|
* parsing the command line arguments.
|
||||||
*/
|
*/
|
||||||
inline TestApplication::operator bool() const
|
inline TestApplication::operator bool() const
|
||||||
{
|
{
|
||||||
|
@ -52,6 +58,15 @@ inline LIB_EXPORT std::string testFilePath(const std::string &name)
|
||||||
return TestApplication::instance()->testFilePath(name);
|
return TestApplication::instance()->testFilePath(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.
|
||||||
|
*/
|
||||||
|
inline LIB_EXPORT std::string workingCopyPath(const std::string &name)
|
||||||
|
{
|
||||||
|
return TestApplication::instance()->workingCopyPath(name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TESTUTILS_H
|
#endif // TESTUTILS_H
|
||||||
|
|
Loading…
Reference in New Issue