Skip to content

Commit facf356

Browse files
committed
testrunner: made -x work with individual tests
1 parent ee1afe9 commit facf356

File tree

6 files changed

+97
-62
lines changed

6 files changed

+97
-62
lines changed

.github/workflows/CI-unixish.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,13 @@ jobs:
679679
test -z "$(nm processexecutor.o)"
680680
# TODO: test NO_* defines
681681
682+
- name: Test testrunner inclusion/exclusion
683+
run: |
684+
! ./testrunner -d TestUtils | grep -v TestUtils > /dev/null
685+
! ./testrunner -d TestUtils::trim | grep -v TestUtils::trim > /dev/null
686+
! ./testrunner -d -x TestUtils | grep TestUtils > /dev/null
687+
! ./testrunner -d -x TestUtils:trim | grep TestUtils:trim > /dev/null
688+
682689
- name: Show all ignored files
683690
if: false # TODO: currently lists all the contents of ignored folders - we only need what actually matched
684691
run: |

test/fixture.cpp

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,22 @@ bool TestFixture::prepareTest(const char testname[])
9797
prepareTestInternal();
9898

9999
// Check if tests should be executed
100-
if (testToRun.empty() || testToRun == testname) {
101-
// Tests will be executed - prepare them
102-
mTestname = testname;
103-
++countTests;
104-
if (quiet_tests) {
105-
std::putchar('.'); // Use putchar to write through redirection of std::cout/cerr
106-
std::fflush(stdout);
107-
} else {
108-
std::cout << classname << "::" << mTestname << std::endl;
109-
}
110-
return !dry_run;
100+
if (!testsToRun.empty()) {
101+
const bool match = testsToRun.count(testname);
102+
if ((match && exclude_tests) || (!match && !exclude_tests))
103+
return false;
104+
}
105+
106+
// Tests will be executed - prepare them
107+
mTestname = testname;
108+
++countTests;
109+
if (quiet_tests) {
110+
std::putchar('.'); // Use putchar to write through redirection of std::cout/cerr
111+
std::fflush(stdout);
112+
} else {
113+
std::cout << classname << "::" << mTestname << std::endl;
111114
}
112-
return false;
115+
return !dry_run;
113116
}
114117

115118
void TestFixture::teardownTest()
@@ -350,9 +353,9 @@ void TestFixture::printHelp()
350353
" -x Exclude the specified tests.\n";
351354
}
352355

353-
void TestFixture::run(const std::string &str)
356+
void TestFixture::run(const std::set<std::string> &tests)
354357
{
355-
testToRun = str;
358+
testsToRun = tests;
356359
try {
357360
if (quiet_tests) {
358361
std::cout << '\n' << classname << ':';
@@ -380,6 +383,7 @@ void TestFixture::processOptions(const options& args)
380383
{
381384
quiet_tests = args.quiet();
382385
dry_run = args.dry_run();
386+
exclude_tests = args.exclude_tests();
383387
exename = args.exe();
384388
}
385389

@@ -388,27 +392,27 @@ std::size_t TestFixture::runTests(const options& args)
388392
countTests = 0;
389393
errmsg.str("");
390394

395+
const auto& which_tests = args.which_tests();
396+
const auto exclude_tests = args.exclude_tests();
397+
391398
// TODO: bail out when given class/test is not found?
392-
for (std::string classname : args.which_test()) {
393-
std::string testname;
394-
const std::string::size_type pos = classname.find("::");
395-
if (pos != std::string::npos) {
396-
// TODO: excluding indiviual tests is not supported yet
397-
testname = classname.substr(pos + 2);
398-
classname.erase(pos);
399+
for (TestInstance * test : TestRegistry::theInstance().tests())
400+
{
401+
std::set<std::string> tests;
402+
if (!which_tests.empty()) {
403+
const auto it = which_tests.find(test->classname);
404+
const bool match = it != which_tests.cend();
405+
if (match && exclude_tests && it->second.empty()) // only bailout when the whole fixture is excluded
406+
continue;
407+
if (!match && !exclude_tests)
408+
continue;
409+
if (match)
410+
tests = it->second;
399411
}
400412

401-
for (TestInstance * test : TestRegistry::theInstance().tests()) {
402-
if (!classname.empty()) {
403-
const bool match = test->classname == classname;
404-
if ((match && args.exclude_tests()) || (!match && !args.exclude_tests()))
405-
continue;
406-
}
407-
408-
TestFixture* fixture = test->create();
409-
fixture->processOptions(args);
410-
fixture->run(testname);
411-
}
413+
TestFixture* fixture = test->create();
414+
fixture->processOptions(args);
415+
fixture->run(tests);
412416
}
413417

414418
if (args.summary() && !args.dry_run()) {

test/fixture.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <exception>
3535
#include <list>
3636
#include <memory>
37+
#include <set>
3738
#include <sstream>
3839
#include <stdexcept>
3940
#include <string>
@@ -56,9 +57,10 @@ class TestFixture : public ErrorLogger {
5657

5758
protected:
5859
std::string exename;
59-
std::string testToRun;
60+
std::set<std::string> testsToRun;
6061
bool quiet_tests{};
6162
bool dry_run{};
63+
bool exclude_tests{};
6264
bool mNewTemplate{};
6365

6466
virtual void run() = 0;
@@ -290,7 +292,7 @@ class TestFixture : public ErrorLogger {
290292
{
291293
(void) metric;
292294
}
293-
void run(const std::string &str);
295+
void run(const std::set<std::string> &tests);
294296

295297
public:
296298
static void printHelp();

test/options.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,30 @@
1717
#include "options.h"
1818

1919
options::options(int argc, const char* const argv[])
20-
: mWhichTests(argv + 1, argv + argc)
21-
,mQuiet(mWhichTests.count("-q") != 0)
22-
,mHelp(mWhichTests.count("-h") != 0 || mWhichTests.count("--help"))
23-
,mSummary(mWhichTests.count("-n") == 0)
24-
,mDryRun(mWhichTests.count("-d") != 0)
25-
,mExcludeTests(mWhichTests.count("-x") != 0)
20+
: mArgs(argv + 1, argv + argc)
21+
,mQuiet(mArgs.count("-q") != 0)
22+
,mHelp(mArgs.count("-h") != 0 || mArgs.count("--help"))
23+
,mSummary(mArgs.count("-n") == 0)
24+
,mDryRun(mArgs.count("-d") != 0)
25+
,mExcludeTests(mArgs.count("-x") != 0)
2626
,mExe(argv[0])
2727
{
28-
for (auto it = mWhichTests.cbegin(); it != mWhichTests.cend();) {
29-
if (!it->empty() && (((*it)[0] == '-') || (it->find("::") != std::string::npos && mWhichTests.count(it->substr(0, it->find("::"))))))
30-
it = mWhichTests.erase(it);
31-
else
32-
++it;
33-
}
34-
35-
if (mWhichTests.empty()) {
36-
mWhichTests.insert("");
28+
for (const auto& arg : mArgs) {
29+
if (arg.empty())
30+
continue; // empty argument
31+
if (arg[0] == '-')
32+
continue; // command-line switch
33+
const auto pos = arg.find("::");
34+
if (pos == std::string::npos) {
35+
mWhichTests[arg] = {}; // run whole fixture
36+
continue;
37+
}
38+
const std::string fixture = arg.substr(0, pos);
39+
const auto it = mWhichTests.find(fixture);
40+
if (it != mWhichTests.cend() && it->second.empty())
41+
continue; // whole fixture is already included
42+
const std::string test = arg.substr(pos+2);
43+
mWhichTests[fixture].emplace(test); // run individual test
3744
}
3845
}
3946

@@ -57,7 +64,7 @@ bool options::dry_run() const
5764
return mDryRun;
5865
}
5966

60-
const std::set<std::string>& options::which_test() const
67+
const std::map<std::string, std::set<std::string>>& options::which_tests() const
6168
{
6269
return mWhichTests;
6370
}

test/options.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef OPTIONS_H
1818
#define OPTIONS_H
1919

20+
#include <map>
2021
#include <set>
2122
#include <string>
2223

@@ -39,8 +40,8 @@ class options {
3940
bool dry_run() const;
4041
/** Exclude provided lists of tests. */
4142
bool exclude_tests() const;
42-
/** Which test should be run. Empty string means 'all tests' */
43-
const std::set<std::string>& which_test() const;
43+
/** Which tests should be run. */
44+
const std::map<std::string, std::set<std::string>>& which_tests() const;
4445

4546
const std::string& exe() const;
4647

@@ -49,7 +50,8 @@ class options {
4950
options& operator =(const options&) = delete;
5051

5152
private:
52-
std::set<std::string> mWhichTests;
53+
std::set<std::string> mArgs;
54+
std::map<std::string, std::set<std::string>> mWhichTests;
5355
const bool mQuiet;
5456
const bool mHelp;
5557
const bool mSummary;

test/testoptions.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,28 @@ class TestOptions : public TestFixture {
5151
void which_test() const {
5252
const char* argv[] = {"./test_runner", "TestClass"};
5353
options args(getArrayLength(argv), argv);
54-
ASSERT(std::set<std::string> {"TestClass"} == args.which_test());
54+
const std::map<std::string, std::set<std::string>> expected{
55+
{ "TestClass", {} }
56+
};
57+
ASSERT(expected == args.which_tests());
5558
}
5659

5760

5861
void which_test_method() const {
5962
const char* argv[] = {"./test_runner", "TestClass::TestMethod"};
6063
options args(getArrayLength(argv), argv);
61-
ASSERT(std::set<std::string> {"TestClass::TestMethod"} == args.which_test());
64+
const std::map<std::string, std::set<std::string>> expected{
65+
{ "TestClass", {"TestMethod"} }
66+
};
67+
ASSERT(expected == args.which_tests());
6268
}
6369

6470

6571
void no_test_method() const {
6672
const char* argv[] = {"./test_runner"};
6773
options args(getArrayLength(argv), argv);
68-
ASSERT(std::set<std::string> {""} == args.which_test());
74+
const std::map<std::string, std::set<std::string>> expected{};
75+
ASSERT(expected == args.which_tests());
6976
}
7077

7178

@@ -105,22 +112,28 @@ class TestOptions : public TestFixture {
105112
void multiple_testcases() const {
106113
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass::AnotherTestMethod"};
107114
options args(getArrayLength(argv), argv);
108-
std::set<std::string> expected {"TestClass::TestMethod", "TestClass::AnotherTestMethod"};
109-
ASSERT(expected == args.which_test());
115+
const std::map<std::string, std::set<std::string>> expected{
116+
{ "TestClass", { "TestMethod", "AnotherTestMethod" } }
117+
};
118+
ASSERT(expected == args.which_tests());
110119
}
111120

112121
void multiple_testcases_ignore_duplicates() const {
113122
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass"};
114123
options args(getArrayLength(argv), argv);
115-
std::set<std::string> expected {"TestClass"};
116-
ASSERT(expected == args.which_test());
124+
const std::map<std::string, std::set<std::string>> expected{
125+
{ "TestClass", {} }
126+
};
127+
ASSERT(expected == args.which_tests());
117128
}
118129

119130
void invalid_switches() const {
120131
const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"};
121132
options args(getArrayLength(argv), argv);
122-
std::set<std::string> expected {"TestClass::TestMethod"};
123-
ASSERT(expected == args.which_test());
133+
const std::map<std::string, std::set<std::string>> expected {
134+
{ "TestClass", { "TestMethod" } }
135+
};
136+
ASSERT(expected == args.which_tests());
124137
ASSERT_EQUALS(true, args.quiet());
125138
}
126139

0 commit comments

Comments
 (0)