Allow multiple test case arguments to testrunner (#1755)

Take some care to not run the same test case twice, even if running:

    ./testrunner TestClass TestClass::TestCase
This commit is contained in:
Rikard Falkeborn 2019-03-26 20:28:40 +01:00 committed by amai2012
parent c262aeffdd
commit 6b478c362e
4 changed files with 48 additions and 33 deletions

View File

@ -19,16 +19,19 @@
#include <iterator>
options::options(int argc, const char* const argv[])
:mOptions(argv + 1, argv + argc)
,mWhichTest("")
,mQuiet(mOptions.count("-q") != 0)
,mHelp(mOptions.count("-h") != 0 || mOptions.count("--help"))
:mWhichTests(argv + 1, argv + argc)
,mQuiet(mWhichTests.count("-q") != 0)
,mHelp(mWhichTests.count("-h") != 0 || mWhichTests.count("--help"))
{
mOptions.erase("-q");
mOptions.erase("-h");
mOptions.erase("--help");
if (! mOptions.empty()) {
mWhichTest = *mOptions.rbegin();
for (std::set<std::string>::const_iterator it = mWhichTests.begin(); it != mWhichTests.end();) {
if (!(*it).empty() && (((*it)[0] == '-') || ((*it).find("::") != std::string::npos && mWhichTests.count((*it).substr(0, (*it).find("::"))))))
it = mWhichTests.erase(it);
else
++it;
}
if (mWhichTests.empty()) {
mWhichTests.insert("");
}
}
@ -42,7 +45,7 @@ bool options::help() const
return mHelp;
}
const std::string& options::which_test() const
const std::set<std::string>& options::which_test() const
{
return mWhichTest;
return mWhichTests;
}

View File

@ -34,7 +34,7 @@ public:
/** Print help. */
bool help() const;
/** Which test should be run. Empty string means 'all tests' */
const std::string& which_test() const;
const std::set<std::string>& which_test() const;
private:
options();
@ -42,8 +42,7 @@ private:
const options& operator =(const options& non_assign);
private:
std::set<std::string> mOptions;
std::string mWhichTest;
std::set<std::string> mWhichTests;
const bool mQuiet;
const bool mHelp;
};

View File

@ -36,6 +36,7 @@ private:
TEST_CASE(help);
TEST_CASE(help_long);
TEST_CASE(multiple_testcases);
TEST_CASE(multiple_testcases_ignore_duplicates);
TEST_CASE(invalid_switches);
}
@ -43,21 +44,21 @@ private:
void which_test() const {
const char* argv[] = {"./test_runner", "TestClass"};
options args(sizeof argv / sizeof argv[0], argv);
ASSERT_EQUALS("TestClass", args.which_test());
ASSERT(std::set<std::string> {"TestClass"} == args.which_test());
}
void which_test_method() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod"};
options args(sizeof argv / sizeof argv[0], argv);
ASSERT_EQUALS("TestClass::TestMethod", args.which_test());
ASSERT(std::set<std::string> {"TestClass::TestMethod"} == args.which_test());
}
void no_test_method() const {
const char* argv[] = {"./test_runner"};
options args(sizeof argv / sizeof argv[0], argv);
ASSERT_EQUALS("", args.which_test());
ASSERT(std::set<std::string> {""} == args.which_test());
}
@ -95,16 +96,24 @@ private:
}
void multiple_testcases() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "Ignore::ThisOne"};
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass::AnotherTestMethod"};
options args(sizeof argv / sizeof argv[0], argv);
ASSERT_EQUALS("TestClass::TestMethod", args.which_test());
std::set<std::string> expected {"TestClass::TestMethod", "TestClass::AnotherTestMethod"};
ASSERT(expected == args.which_test());
}
void multiple_testcases_ignore_duplicates() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass"};
options args(sizeof argv / sizeof argv[0], argv);
std::set<std::string> expected {"TestClass"};
ASSERT(expected == args.which_test());
}
void invalid_switches() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"};
options args(sizeof argv / sizeof argv[0], argv);
ASSERT_EQUALS("TestClass::TestMethod", args.which_test());
std::set<std::string> expected {"TestClass::TestMethod"};
ASSERT(expected == args.which_test());
ASSERT_EQUALS(true, args.quiet());
}
};

View File

@ -280,13 +280,15 @@ void TestFixture::printHelp()
std::cout << "Testrunner - run Cppcheck tests\n"
"\n"
"Syntax:\n"
" testrunner [OPTIONS] [TestClass::TestCase]\n"
" testrunner [OPTIONS] [TestClass::TestCase...]\n"
" run all test cases:\n"
" testrunner\n"
" run all test cases in TestClass:\n"
" testrunner TestClass\n"
" run TestClass::TestCase:\n"
" testrunner TestClass::TestCase\n"
" run all test cases in TestClass1 and TestClass2::TestCase:\n"
" testrunner TestClass1 TestClass2::TestCase\n"
"\n"
"Options:\n"
" -q Do not print the test cases that have run.\n"
@ -311,22 +313,24 @@ void TestFixture::processOptions(const options& args)
std::size_t TestFixture::runTests(const options& args)
{
std::string classname(args.which_test());
std::string testname;
if (classname.find("::") != std::string::npos) {
testname = classname.substr(classname.find("::") + 2);
classname.erase(classname.find("::"));
}
countTests = 0;
errmsg.str("");
const TestSet &tests = TestRegistry::theInstance().tests();
const std::set<std::string>& tests = args.which_test();
for (std::string classname : tests) {
std::string testname;
if (classname.find("::") != std::string::npos) {
testname = classname.substr(classname.find("::") + 2);
classname.erase(classname.find("::"));
}
for (TestFixture * test : tests) {
if (classname.empty() || test->classname == classname) {
test->processOptions(args);
test->run(testname);
const TestSet &tests = TestRegistry::theInstance().tests();
for (TestFixture * test : tests) {
if (classname.empty() || test->classname == classname) {
test->processOptions(args);
test->run(testname);
}
}
}