make test code public to simplify creation of tests in other projects
This commit is contained in:
parent
df9c0573bf
commit
9abe04ce06
|
@ -26,6 +26,8 @@ set(HEADER_FILES
|
||||||
math/math.h
|
math/math.h
|
||||||
misc/memory.h
|
misc/memory.h
|
||||||
misc/random.h
|
misc/random.h
|
||||||
|
tests/testutils.h
|
||||||
|
tests/cppunit.h
|
||||||
)
|
)
|
||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
application/argumentparser.cpp
|
application/argumentparser.cpp
|
||||||
|
@ -45,6 +47,7 @@ set(SRC_FILES
|
||||||
io/path.cpp
|
io/path.cpp
|
||||||
math/math.cpp
|
math/math.cpp
|
||||||
misc/random.cpp
|
misc/random.cpp
|
||||||
|
tests/testutils.cpp
|
||||||
)
|
)
|
||||||
set(TEST_HEADER_FILES
|
set(TEST_HEADER_FILES
|
||||||
|
|
||||||
|
@ -126,7 +129,7 @@ if(NOT TARGET check)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
endif()
|
endif()
|
||||||
add_executable(${META_PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TEST_HEADER_FILES} ${TEST_SRC_FILES})
|
add_executable(${META_PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TEST_HEADER_FILES} ${TEST_SRC_FILES})
|
||||||
target_link_libraries(${META_PROJECT_NAME}_tests c++utilities cppunit)
|
target_link_libraries(${META_PROJECT_NAME}_tests ${META_PROJECT_NAME} cppunit)
|
||||||
set_target_properties(${META_PROJECT_NAME}_tests PROPERTIES CXX_STANDARD 11)
|
set_target_properties(${META_PROJECT_NAME}_tests PROPERTIES CXX_STANDARD 11)
|
||||||
add_test(NAME ${META_PROJECT_NAME}_cppunit COMMAND ${META_PROJECT_NAME}_tests -p "${CMAKE_CURRENT_SOURCE_DIR}/testfiles")
|
add_test(NAME ${META_PROJECT_NAME}_cppunit COMMAND ${META_PROJECT_NAME}_tests -p "${CMAKE_CURRENT_SOURCE_DIR}/testfiles")
|
||||||
add_dependencies(check ${META_PROJECT_NAME}_tests)
|
add_dependencies(check ${META_PROJECT_NAME}_tests)
|
||||||
|
|
|
@ -42,7 +42,9 @@ HEADERS += \
|
||||||
io/path.h \
|
io/path.h \
|
||||||
math/math.h \
|
math/math.h \
|
||||||
misc/memory.h \
|
misc/memory.h \
|
||||||
misc/random.h
|
misc/random.h \
|
||||||
|
tests/testutils.h \
|
||||||
|
tests/cppunit.h \
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
application/argumentparser.cpp \
|
application/argumentparser.cpp \
|
||||||
|
@ -61,7 +63,8 @@ SOURCES += \
|
||||||
io/inifile.cpp \
|
io/inifile.cpp \
|
||||||
io/path.cpp \
|
io/path.cpp \
|
||||||
math/math.cpp \
|
math/math.cpp \
|
||||||
misc/random.cpp
|
misc/random.cpp \
|
||||||
|
tests/testutils.cpp
|
||||||
|
|
||||||
OTHER_FILES += \
|
OTHER_FILES += \
|
||||||
README.md \
|
README.md \
|
||||||
|
@ -82,7 +85,7 @@ mingw-w64-install {
|
||||||
target.path = $$(INSTALL_ROOT)/lib
|
target.path = $$(INSTALL_ROOT)/lib
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
}
|
}
|
||||||
for(dir, $$list(application io conversion chrono math misc)) {
|
for(dir, $$list(application io conversion chrono math misc tests)) {
|
||||||
eval(inc_$${dir} = $${dir})
|
eval(inc_$${dir} = $${dir})
|
||||||
inc_$${dir}.path = $$(INSTALL_ROOT)/include/$$projectname/$${dir}
|
inc_$${dir}.path = $$(INSTALL_ROOT)/include/$$projectname/$${dir}
|
||||||
inc_$${dir}.files = $${dir}/*.h
|
inc_$${dir}.files = $${dir}/*.h
|
||||||
|
|
|
@ -1,49 +1 @@
|
||||||
#include "../application/argumentparser.h"
|
#include "cppunit.h"
|
||||||
#include "../application/failure.h"
|
|
||||||
|
|
||||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
|
||||||
#include <cppunit/ui/text/TestRunner.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace ApplicationUtilities;
|
|
||||||
using namespace CPPUNIT_NS;
|
|
||||||
|
|
||||||
namespace UnitTests {
|
|
||||||
|
|
||||||
string testFilesPath("tests");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
// setup argument parser
|
|
||||||
ArgumentParser parser;
|
|
||||||
HelpArgument helpArg(parser);
|
|
||||||
Argument testFilesPathArg("test-files-path", "p", "specifies the path to the directory with test files");
|
|
||||||
testFilesPathArg.setRequiredValueCount(1);
|
|
||||||
testFilesPathArg.setValueNames({"path"});
|
|
||||||
testFilesPathArg.setCombinable(true);
|
|
||||||
parser.setMainArguments({&testFilesPathArg, &helpArg});
|
|
||||||
|
|
||||||
try {
|
|
||||||
// parse arguments
|
|
||||||
parser.parseArgs(argc, argv);
|
|
||||||
if(testFilesPathArg.isPresent()) {
|
|
||||||
UnitTests::testFilesPath = testFilesPathArg.values().front();
|
|
||||||
}
|
|
||||||
cerr << "Direcoty for test files: " << UnitTests::testFilesPath << endl;
|
|
||||||
|
|
||||||
// run tests
|
|
||||||
TextUi::TestRunner runner;
|
|
||||||
TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry();
|
|
||||||
runner.addTest(registry.makeTest());
|
|
||||||
return !runner.run(string(), false);
|
|
||||||
} catch(const Failure &failure) {
|
|
||||||
cerr << "Invalid arguments specified: " << failure.what() << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef CPPUNIT_H
|
||||||
|
#define CPPUNIT_H
|
||||||
|
|
||||||
|
#include "./testutils.h"
|
||||||
|
|
||||||
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
|
#include <cppunit/ui/text/TestRunner.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace TestUtilities;
|
||||||
|
using namespace CPPUNIT_NS;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Performs unit tests using cppunit.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
TestApplication testApp(argc, argv);
|
||||||
|
if(testApp) {
|
||||||
|
// run tests
|
||||||
|
TextUi::TestRunner runner;
|
||||||
|
TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry();
|
||||||
|
runner.addTest(registry.makeTest());
|
||||||
|
return !runner.run(string(), false);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPPUNIT_H
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "./testutils.h"
|
||||||
|
|
||||||
#include "../io/binaryreader.h"
|
#include "../io/binaryreader.h"
|
||||||
#include "../io/binarywriter.h"
|
#include "../io/binarywriter.h"
|
||||||
#include "../io/bitreader.h"
|
#include "../io/bitreader.h"
|
||||||
|
@ -71,7 +73,7 @@ void IoTests::testBinaryReader()
|
||||||
{
|
{
|
||||||
// read test file
|
// read test file
|
||||||
fstream testFile;
|
fstream testFile;
|
||||||
testFile.open(UnitTests::testFilesPath + "/some_data", ios_base::in | ios_base::binary);
|
testFile.open(TestUtilities::testFilePath("some_data"), ios_base::in | ios_base::binary);
|
||||||
BinaryReader reader(&testFile);
|
BinaryReader reader(&testFile);
|
||||||
CPPUNIT_ASSERT(reader.readUInt16LE() == 0x0102u);
|
CPPUNIT_ASSERT(reader.readUInt16LE() == 0x0102u);
|
||||||
CPPUNIT_ASSERT(reader.readUInt16BE() == 0x0102u);
|
CPPUNIT_ASSERT(reader.readUInt16BE() == 0x0102u);
|
||||||
|
@ -116,7 +118,7 @@ void IoTests::testBinaryWriter()
|
||||||
{
|
{
|
||||||
// prepare reading expected data
|
// prepare reading expected data
|
||||||
fstream testFile;
|
fstream testFile;
|
||||||
testFile.open(UnitTests::testFilesPath + "/some_data", ios_base::in | ios_base::binary);
|
testFile.open(TestUtilities::testFilePath("some_data"), ios_base::in | ios_base::binary);
|
||||||
|
|
||||||
// prepare output stream
|
// prepare output stream
|
||||||
stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
|
stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
|
||||||
|
@ -214,7 +216,7 @@ void IoTests::testIniFile()
|
||||||
// prepare reading test file
|
// prepare reading test file
|
||||||
fstream inputFile;
|
fstream inputFile;
|
||||||
inputFile.exceptions(ios_base::failbit | ios_base::badbit);
|
inputFile.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
inputFile.open(UnitTests::testFilesPath + "/test.ini", ios_base::in);
|
inputFile.open(TestUtilities::testFilePath("test.ini"), ios_base::in);
|
||||||
|
|
||||||
IniFile ini;
|
IniFile ini;
|
||||||
ini.parse(inputFile);
|
ini.parse(inputFile);
|
||||||
|
@ -236,12 +238,12 @@ void IoTests::testIniFile()
|
||||||
// write values to another file
|
// write values to another file
|
||||||
fstream outputFile;
|
fstream outputFile;
|
||||||
outputFile.exceptions(ios_base::failbit | ios_base::badbit);
|
outputFile.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
outputFile.open(UnitTests::testFilesPath + "/output.ini", ios_base::out | ios_base::trunc);
|
outputFile.open(TestUtilities::testFilePath("output.ini"), ios_base::out | ios_base::trunc);
|
||||||
ini.make(outputFile);
|
ini.make(outputFile);
|
||||||
|
|
||||||
// parse written values (again)
|
// parse written values (again)
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
outputFile.open(UnitTests::testFilesPath + "/output.ini", ios_base::in);
|
outputFile.open(TestUtilities::testFilePath("output.ini"), ios_base::in);
|
||||||
IniFile ini2;
|
IniFile ini2;
|
||||||
ini2.parse(outputFile);
|
ini2.parse(outputFile);
|
||||||
CPPUNIT_ASSERT(ini.data() == ini2.data());
|
CPPUNIT_ASSERT(ini.data() == ini2.data());
|
||||||
|
@ -254,7 +256,7 @@ void IoTests::testCopy()
|
||||||
{
|
{
|
||||||
// prepare streams
|
// prepare streams
|
||||||
fstream testFile;
|
fstream testFile;
|
||||||
testFile.open(UnitTests::testFilesPath + "/some_data", ios_base::in | ios_base::binary);
|
testFile.open(TestUtilities::testFilePath("some_data"), ios_base::in | ios_base::binary);
|
||||||
testFile.exceptions(ios_base::failbit | ios_base::badbit);
|
testFile.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
|
stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
|
||||||
outputStream.exceptions(ios_base::failbit | ios_base::badbit);
|
outputStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
#include "./testutils.h"
|
||||||
|
|
||||||
|
#include "../application/failure.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ApplicationUtilities;
|
||||||
|
|
||||||
|
namespace TestUtilities {
|
||||||
|
|
||||||
|
TestApplication *TestApplication::m_instance = nullptr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class TestApplication
|
||||||
|
* \brief The TestApplication class simplifies writing test applications.
|
||||||
|
* \remarks Only one instance is allowed at a time (singletone class).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a TestApplication instance.
|
||||||
|
* \throws Throws std::runtime_error if an instance has already been created.
|
||||||
|
*/
|
||||||
|
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")
|
||||||
|
{
|
||||||
|
if(m_instance) {
|
||||||
|
throw runtime_error("only one TestApplication instance allowed at a time");
|
||||||
|
}
|
||||||
|
m_instance = this;
|
||||||
|
if(const char *testFilesPathEnv = getenv("TEST_FILE_PATH")) {
|
||||||
|
if(const auto len = strlen(testFilesPathEnv)) {
|
||||||
|
m_testFilesPathEnvValue.reserve(len + 1);
|
||||||
|
m_testFilesPathEnvValue += testFilesPathEnv;
|
||||||
|
m_testFilesPathEnvValue += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_testFilesPathArg.setRequiredValueCount(1);
|
||||||
|
m_testFilesPathArg.setValueNames({"path"});
|
||||||
|
m_testFilesPathArg.setCombinable(true);
|
||||||
|
m_parser.setMainArguments({&m_testFilesPathArg, &m_helpArg});
|
||||||
|
try {
|
||||||
|
m_parser.parseArgs(argc, argv);
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
cerr << (m_testFilesPathArgValue = "./") << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!m_testFilesPathEnvValue.empty()) {
|
||||||
|
cerr << m_testFilesPathEnvValue << endl;
|
||||||
|
}
|
||||||
|
cerr << "./testfiles/" << endl << endl;
|
||||||
|
m_valid = true;
|
||||||
|
cerr << "Executing test cases ..." << endl;
|
||||||
|
} catch(const Failure &failure) {
|
||||||
|
cerr << "Invalid arguments specified: " << failure.what() << endl;
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Destroys the TestApplication.
|
||||||
|
*/
|
||||||
|
TestApplication::~TestApplication()
|
||||||
|
{
|
||||||
|
m_instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the full path of tbe test file with the specified \a name.
|
||||||
|
*/
|
||||||
|
string TestApplication::testFilePath(const string &name) const
|
||||||
|
{
|
||||||
|
string path;
|
||||||
|
fstream file;
|
||||||
|
if(m_testFilesPathArg.isPresent()) {
|
||||||
|
file.open(path = m_testFilesPathArgValue + name, ios_base::in);
|
||||||
|
if(file.good()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!m_testFilesPathEnvValue.empty()) {
|
||||||
|
file.clear();
|
||||||
|
file.open(path = m_testFilesPathEnvValue + name, ios_base::in);
|
||||||
|
if(file.good()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "./testfiles/" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef TESTUTILS_H
|
||||||
|
#define TESTUTILS_H
|
||||||
|
|
||||||
|
#include "../application/argumentparser.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace TestUtilities {
|
||||||
|
|
||||||
|
class LIB_EXPORT TestApplication
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestApplication(int argc, char **argv);
|
||||||
|
~TestApplication();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
std::string testFilePath(const std::string &name) const;
|
||||||
|
static const TestApplication *instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ApplicationUtilities::ArgumentParser m_parser;
|
||||||
|
ApplicationUtilities::HelpArgument m_helpArg;
|
||||||
|
ApplicationUtilities::Argument m_testFilesPathArg;
|
||||||
|
std::string m_testFilesPathArgValue;
|
||||||
|
std::string m_testFilesPathEnvValue;
|
||||||
|
bool m_valid;
|
||||||
|
static TestApplication *m_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the TestApplication instance is valid.
|
||||||
|
*/
|
||||||
|
inline TestApplication::operator bool() const
|
||||||
|
{
|
||||||
|
return m_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the current TestApplication instance.
|
||||||
|
*/
|
||||||
|
inline const TestApplication *TestApplication::instance()
|
||||||
|
{
|
||||||
|
return TestApplication::m_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Convenience function which returns the full path of the test file with the specified \a name.
|
||||||
|
* \remarks A TestApplication must be present.
|
||||||
|
*/
|
||||||
|
inline LIB_EXPORT std::string testFilePath(const std::string &name)
|
||||||
|
{
|
||||||
|
return TestApplication::instance()->testFilePath(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TESTUTILS_H
|
Loading…
Reference in New Issue