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> #include <iterator>
options::options(int argc, const char* const argv[]) options::options(int argc, const char* const argv[])
:mOptions(argv + 1, argv + argc) :mWhichTests(argv + 1, argv + argc)
,mWhichTest("") ,mQuiet(mWhichTests.count("-q") != 0)
,mQuiet(mOptions.count("-q") != 0) ,mHelp(mWhichTests.count("-h") != 0 || mWhichTests.count("--help"))
,mHelp(mOptions.count("-h") != 0 || mOptions.count("--help"))
{ {
mOptions.erase("-q"); for (std::set<std::string>::const_iterator it = mWhichTests.begin(); it != mWhichTests.end();) {
mOptions.erase("-h"); if (!(*it).empty() && (((*it)[0] == '-') || ((*it).find("::") != std::string::npos && mWhichTests.count((*it).substr(0, (*it).find("::"))))))
mOptions.erase("--help"); it = mWhichTests.erase(it);
if (! mOptions.empty()) { else
mWhichTest = *mOptions.rbegin(); ++it;
}
if (mWhichTests.empty()) {
mWhichTests.insert("");
} }
} }
@ -42,7 +45,7 @@ bool options::help() const
return mHelp; 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. */ /** Print help. */
bool help() const; bool help() const;
/** Which test should be run. Empty string means 'all tests' */ /** 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: private:
options(); options();
@ -42,8 +42,7 @@ private:
const options& operator =(const options& non_assign); const options& operator =(const options& non_assign);
private: private:
std::set<std::string> mOptions; std::set<std::string> mWhichTests;
std::string mWhichTest;
const bool mQuiet; const bool mQuiet;
const bool mHelp; const bool mHelp;
}; };

View File

@ -36,6 +36,7 @@ private:
TEST_CASE(help); TEST_CASE(help);
TEST_CASE(help_long); TEST_CASE(help_long);
TEST_CASE(multiple_testcases); TEST_CASE(multiple_testcases);
TEST_CASE(multiple_testcases_ignore_duplicates);
TEST_CASE(invalid_switches); TEST_CASE(invalid_switches);
} }
@ -43,21 +44,21 @@ private:
void which_test() const { void which_test() const {
const char* argv[] = {"./test_runner", "TestClass"}; const char* argv[] = {"./test_runner", "TestClass"};
options args(sizeof argv / sizeof argv[0], argv); 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 { void which_test_method() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod"}; const char* argv[] = {"./test_runner", "TestClass::TestMethod"};
options args(sizeof argv / sizeof argv[0], argv); 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 { void no_test_method() const {
const char* argv[] = {"./test_runner"}; const char* argv[] = {"./test_runner"};
options args(sizeof argv / sizeof argv[0], argv); 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 { 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); 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 { void invalid_switches() const {
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"}; const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"};
options args(sizeof argv / sizeof argv[0], argv); 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()); ASSERT_EQUALS(true, args.quiet());
} }
}; };

View File

@ -280,13 +280,15 @@ void TestFixture::printHelp()
std::cout << "Testrunner - run Cppcheck tests\n" std::cout << "Testrunner - run Cppcheck tests\n"
"\n" "\n"
"Syntax:\n" "Syntax:\n"
" testrunner [OPTIONS] [TestClass::TestCase]\n" " testrunner [OPTIONS] [TestClass::TestCase...]\n"
" run all test cases:\n" " run all test cases:\n"
" testrunner\n" " testrunner\n"
" run all test cases in TestClass:\n" " run all test cases in TestClass:\n"
" testrunner TestClass\n" " testrunner TestClass\n"
" run TestClass::TestCase:\n" " run TestClass::TestCase:\n"
" testrunner TestClass::TestCase\n" " testrunner TestClass::TestCase\n"
" run all test cases in TestClass1 and TestClass2::TestCase:\n"
" testrunner TestClass1 TestClass2::TestCase\n"
"\n" "\n"
"Options:\n" "Options:\n"
" -q Do not print the test cases that have run.\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::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; countTests = 0;
errmsg.str(""); 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) { const TestSet &tests = TestRegistry::theInstance().tests();
if (classname.empty() || test->classname == classname) {
test->processOptions(args); for (TestFixture * test : tests) {
test->run(testname); if (classname.empty() || test->classname == classname) {
test->processOptions(args);
test->run(testname);
}
} }
} }