Improve test application for cppunit
* Allow to list available tests * Fail the test if at least one explicitely specified unit is not available
This commit is contained in:
parent
fd531bdd6a
commit
428a67d68b
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "./testutils.h"
|
#include "./testutils.h"
|
||||||
|
|
||||||
|
#include "../application/commandlineutils.h"
|
||||||
|
|
||||||
#include <cppunit/TestPath.h>
|
#include <cppunit/TestPath.h>
|
||||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
#include <cppunit/ui/text/TestRunner.h>
|
#include <cppunit/ui/text/TestRunner.h>
|
||||||
|
@ -13,6 +15,18 @@ using namespace std;
|
||||||
using namespace CppUtilities;
|
using namespace CppUtilities;
|
||||||
using namespace CPPUNIT_NS;
|
using namespace CPPUNIT_NS;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Prints the names of all child tests of the specified \a test.
|
||||||
|
*/
|
||||||
|
void printTestNames(Test *test, Indentation indentation)
|
||||||
|
{
|
||||||
|
for (int index = 0, count = test->getChildTestCount(); index != count; ++index) {
|
||||||
|
const auto childTest = test->getChildTestAt(index);
|
||||||
|
cerr << '\n' << indentation << " - " << childTest->getName();
|
||||||
|
printTestNames(childTest, indentation + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Performs unit tests using cppunit.
|
* \brief Performs unit tests using cppunit.
|
||||||
*/
|
*/
|
||||||
|
@ -23,22 +37,41 @@ int main(int argc, char **argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// list tests
|
||||||
|
TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry();
|
||||||
|
if (testApp.onlyListUnits()) {
|
||||||
|
cerr << "Available tests:";
|
||||||
|
printTestNames(registry.makeTest(), Indentation(0));
|
||||||
|
cerr << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// run tests
|
// run tests
|
||||||
TextUi::TestRunner runner;
|
TextUi::TestRunner runner;
|
||||||
TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry();
|
|
||||||
if (!testApp.unitsSpecified() || testApp.units().empty()) {
|
if (!testApp.unitsSpecified() || testApp.units().empty()) {
|
||||||
// no units specified -> test all
|
// no units specified -> test all
|
||||||
runner.addTest(registry.makeTest());
|
runner.addTest(registry.makeTest());
|
||||||
} else {
|
} else {
|
||||||
// pick specified units from overall test
|
// pick specified units from overall test
|
||||||
Test *overallTest = registry.makeTest();
|
Test *overallTest = registry.makeTest();
|
||||||
|
vector<const char *> unavailableUnits;
|
||||||
for (const char *unit : testApp.units()) {
|
for (const char *unit : testApp.units()) {
|
||||||
try {
|
try {
|
||||||
runner.addTest(overallTest->findTest(unit));
|
runner.addTest(overallTest->findTest(unit));
|
||||||
} catch (const invalid_argument &) {
|
} catch (const invalid_argument &) {
|
||||||
cerr << "The specified test unit \"" << unit << "\" is not available and will be ignored.\n";
|
unavailableUnits.emplace_back(unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!unavailableUnits.empty()) {
|
||||||
|
cerr << "The following tests specified via --unit are not available:";
|
||||||
|
for (const char *unitName : unavailableUnits) {
|
||||||
|
cerr << "\n - " << unitName;
|
||||||
|
}
|
||||||
|
cerr << "\nAvailable tests:";
|
||||||
|
printTestNames(overallTest, Indentation(0));
|
||||||
|
cerr << '\n';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto ok = runner.run(string(), false);
|
const auto ok = runner.run(string(), false);
|
||||||
cerr << (ok ? "Tests successful\n" : "Tests failed\n");
|
cerr << (ok ? "Tests successful\n" : "Tests failed\n");
|
||||||
|
|
|
@ -115,10 +115,12 @@ TestApplication::TestApplication()
|
||||||
* \throws Throws std::runtime_error if an instance has already been created.
|
* \throws Throws std::runtime_error if an instance has already been created.
|
||||||
*/
|
*/
|
||||||
TestApplication::TestApplication(int argc, const char *const *argv)
|
TestApplication::TestApplication(int argc, const char *const *argv)
|
||||||
: m_testFilesPathArg("test-files-path", 'p', "specifies the path of the directory with test files")
|
: m_listArg("list", 'l', "lists available test units")
|
||||||
, m_applicationPathArg("app-path", 'a', "specifies the path of the application to be tested")
|
, m_runArg("run", 'r', "runs the tests")
|
||||||
, m_workingDirArg("working-dir", 'w', "specifies the directory to store working copies of test files")
|
, m_testFilesPathArg("test-files-path", 'p', "specifies the path of the directory with test files", { "path" })
|
||||||
, m_unitsArg("units", 'u', "specifies the units to test; omit to test all units")
|
, m_applicationPathArg("app-path", 'a', "specifies the path of the application to be tested", { "path" })
|
||||||
|
, m_workingDirArg("working-dir", 'w', "specifies the directory to store working copies of test files", { "path" })
|
||||||
|
, m_unitsArg("units", 'u', "specifies the units to test; omit to test all units", { "unit1", "unit2", "unit3" })
|
||||||
{
|
{
|
||||||
// check whether there is already an instance
|
// check whether there is already an instance
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
|
@ -129,17 +131,11 @@ TestApplication::TestApplication(int argc, const char *const *argv)
|
||||||
// handle specified arguments (if present)
|
// handle specified arguments (if present)
|
||||||
if (argc && argv) {
|
if (argc && argv) {
|
||||||
// setup argument parser
|
// setup argument parser
|
||||||
for (Argument *arg : initializer_list<Argument *>{ &m_testFilesPathArg, &m_applicationPathArg, &m_workingDirArg }) {
|
|
||||||
arg->setRequiredValueCount(1);
|
|
||||||
arg->setValueNames({ "path" });
|
|
||||||
arg->setCombinable(true);
|
|
||||||
}
|
|
||||||
m_testFilesPathArg.setRequiredValueCount(Argument::varValueCount);
|
m_testFilesPathArg.setRequiredValueCount(Argument::varValueCount);
|
||||||
m_unitsArg.setRequiredValueCount(Argument::varValueCount);
|
m_unitsArg.setRequiredValueCount(Argument::varValueCount);
|
||||||
m_unitsArg.setValueNames({ "unit1", "unit2", "unit3" });
|
m_runArg.setImplicit(true);
|
||||||
m_unitsArg.setCombinable(true);
|
m_runArg.setSubArguments({ &m_testFilesPathArg, &m_applicationPathArg, &m_workingDirArg, &m_unitsArg });
|
||||||
m_parser.setMainArguments(
|
m_parser.setMainArguments({&m_listArg, &m_runArg, &m_parser.noColorArg(), &m_parser.helpArg()});
|
||||||
{ &m_testFilesPathArg, &m_applicationPathArg, &m_workingDirArg, &m_unitsArg, &m_parser.noColorArg(), &m_parser.helpArg() });
|
|
||||||
|
|
||||||
// parse arguments
|
// parse arguments
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
const char *applicationPath();
|
const char *applicationPath();
|
||||||
bool unitsSpecified() const;
|
bool unitsSpecified() const;
|
||||||
const std::vector<const char *> &units() const;
|
const std::vector<const char *> &units() const;
|
||||||
|
bool onlyListUnits() const;
|
||||||
|
|
||||||
// static read-only accessors
|
// static read-only accessors
|
||||||
static const TestApplication *instance();
|
static const TestApplication *instance();
|
||||||
|
@ -51,10 +52,12 @@ private:
|
||||||
static std::string readTestfilePathFromSrcRef();
|
static std::string readTestfilePathFromSrcRef();
|
||||||
|
|
||||||
ArgumentParser m_parser;
|
ArgumentParser m_parser;
|
||||||
Argument m_testFilesPathArg;
|
OperationArgument m_listArg;
|
||||||
Argument m_applicationPathArg;
|
OperationArgument m_runArg;
|
||||||
Argument m_workingDirArg;
|
ConfigValueArgument m_testFilesPathArg;
|
||||||
Argument m_unitsArg;
|
ConfigValueArgument m_applicationPathArg;
|
||||||
|
ConfigValueArgument m_workingDirArg;
|
||||||
|
ConfigValueArgument m_unitsArg;
|
||||||
std::vector<std::string> m_testFilesPaths;
|
std::vector<std::string> m_testFilesPaths;
|
||||||
std::string m_workingDir;
|
std::string m_workingDir;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
@ -129,6 +132,14 @@ inline const std::vector<const char *> &TestApplication::units() const
|
||||||
return m_unitsArg.values();
|
return m_unitsArg.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the test application should only list available units and not actually run any tests.
|
||||||
|
*/
|
||||||
|
inline bool TestApplication::onlyListUnits() const
|
||||||
|
{
|
||||||
|
return m_listArg.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Convenience function to invoke TestApplication::testFilePath().
|
* \brief Convenience function to invoke TestApplication::testFilePath().
|
||||||
* \remarks A TestApplication must be present.
|
* \remarks A TestApplication must be present.
|
||||||
|
|
Loading…
Reference in New Issue