utilize creation of working copies for tests

This commit is contained in:
Martchus 2016-02-09 02:21:42 +01:00
parent 9abe04ce06
commit af5b879506
3 changed files with 96 additions and 10 deletions

View File

@ -18,10 +18,6 @@ using namespace IoUtilities;
using namespace CPPUNIT_NS;
namespace UnitTests {
extern string testFilesPath;
}
class IoTests : public TestFixture
{
CPPUNIT_TEST_SUITE(IoTests);

View File

@ -7,6 +7,8 @@
#include <iostream>
#include <fstream>
#include <sys/stat.h>
using namespace std;
using namespace ApplicationUtilities;
@ -16,7 +18,7 @@ TestApplication *TestApplication::m_instance = nullptr;
/*!
* \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).
*/
@ -26,12 +28,16 @@ TestApplication *TestApplication::m_instance = nullptr;
*/
TestApplication::TestApplication(int argc, char **argv) :
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) {
throw runtime_error("only one TestApplication instance allowed at a time");
}
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);
@ -39,13 +45,20 @@ TestApplication::TestApplication(int argc, char **argv) :
m_testFilesPathEnvValue += '/';
}
}
// setup argument parser
m_testFilesPathArg.setRequiredValueCount(1);
m_testFilesPathArg.setValueNames({"path"});
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 {
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.values().front().empty()) {
cerr << (m_testFilesPathArgValue = m_testFilesPathArg.values().front() + '/') << endl;
@ -57,6 +70,30 @@ TestApplication::TestApplication(int argc, char **argv) :
cerr << m_testFilesPathEnvValue << 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;
cerr << "Executing test cases ..." << endl;
} 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 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()) {
file.open(path = m_testFilesPathArgValue + name, ios_base::in);
if(file.good()) {
return path;
}
}
// check the path specified by environment variable
if(!m_testFilesPathEnvValue.empty()) {
file.clear();
file.open(path = m_testFilesPathEnvValue + name, ios_base::in);
@ -93,7 +134,41 @@ string TestApplication::testFilePath(const string &name) const
return path;
}
}
// file still not found -> return default path
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(), &currentStat) || !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();
}
}

View File

@ -15,20 +15,26 @@ public:
operator bool() const;
std::string testFilePath(const std::string &name) const;
std::string workingCopyPath(const std::string &name) const;
static const TestApplication *instance();
private:
ApplicationUtilities::ArgumentParser m_parser;
ApplicationUtilities::HelpArgument m_helpArg;
ApplicationUtilities::Argument m_testFilesPathArg;
ApplicationUtilities::Argument m_workingDirArg;
std::string m_testFilesPathArgValue;
std::string m_testFilesPathEnvValue;
std::string m_workingDir;
bool m_valid;
static TestApplication *m_instance;
};
/*!
* \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
{
@ -52,6 +58,15 @@ inline LIB_EXPORT std::string testFilePath(const std::string &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