Skip to content

Commit 0d0d8d1

Browse files
committed
TestShim to ensure every test is destructed once
1 parent 9a61447 commit 0d0d8d1

1 file changed

Lines changed: 48 additions & 12 deletions

File tree

tests/driver.C

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <cppunit/extensions/TestFactoryRegistry.h>
44
#include <cppunit/ui/text/TestRunner.h>
55
#include <cppunit/BriefTestProgressListener.h>
6+
#include <cppunit/TestPath.h>
67
#include <cppunit/TestResult.h>
78
#include <libmesh/restore_warnings.h>
89

@@ -17,14 +18,51 @@
1718
// C++ includes
1819
#include <regex>
1920

21+
// We want to be able to add a selection of tests from our full suite
22+
// to our test runner. But then the test runner will want to destruct
23+
// those tests afterward, so we can't destruct the suite without it
24+
// *also* trying to destruct all its tests (undefined behavior), and
25+
// we can't not destruct the suite without the suite and its
26+
// unselected tests being leaked (which would be fine since just exit
27+
// afterward, except valgrind sees the leaks and screams).
28+
//
29+
// So, instead of adding selected tests, we add shims of selected
30+
// tests that can be deleted without deleting the tests they shim.
31+
class TestShim : public CppUnit::Test
32+
{
33+
public:
34+
TestShim (CppUnit::Test & shimmed_test) : _shimmed_test(shimmed_test) {}
35+
36+
virtual void run(CppUnit::TestResult * result) override { _shimmed_test.run(result); }
37+
38+
virtual int countTestCases () const override { return _shimmed_test.countTestCases(); }
39+
40+
virtual int getChildTestCount () const override { return _shimmed_test.getChildTestCount(); }
41+
42+
virtual std::string getName () const override { return _shimmed_test.getName(); }
43+
44+
virtual bool findTestPath (const std::string & testName, CppUnit::TestPath & testPath) const override { return _shimmed_test.findTestPath(testName, testPath); }
45+
46+
virtual bool findTestPath (const CppUnit::Test * test, CppUnit::TestPath & testPath) const override { return _shimmed_test.findTestPath(test, testPath); }
47+
48+
virtual CppUnit::Test * findTest(const std::string & testName) const override { return _shimmed_test.findTest(testName); }
49+
50+
virtual CppUnit::TestPath resolveTestPath(const std::string & testPath) const override { return _shimmed_test.resolveTestPath(testPath); }
51+
52+
protected:
53+
virtual CppUnit::Test * doGetChildTestAt(int index) const override { return _shimmed_test.getChildTestAt(index); }
54+
55+
private:
56+
CppUnit::Test & _shimmed_test;
57+
};
58+
2059
// Add Tests to runner that match user-provided regex.
2160
int add_matching_tests_to_runner(CppUnit::Test * test,
2261
const std::string & allow_r_str,
2362
const std::regex & allow_r,
2463
const std::string & deny_r_str,
2564
const std::regex & deny_r,
26-
CppUnit::TextUi::TestRunner & runner,
27-
CppUnit::TestSuite & rejects)
65+
CppUnit::TextUi::TestRunner & runner)
2866
{
2967
int n_tests_added = 0;
3068

@@ -46,18 +84,17 @@ int add_matching_tests_to_runner(CppUnit::Test * test,
4684
{
4785
libMesh::out << test->getName() << std::endl;
4886
n_tests_added ++;
49-
runner.addTest(test);
87+
88+
// yes, explicit new; this is how CppUnit works
89+
runner.addTest(new TestShim(*test));
5090
}
51-
// Add the test to the rejects it can be cleaned up later
52-
else
53-
rejects.addTest(test);
5491
}
5592

5693
// Call this recursively on each of our children, if any.
5794
for (int i = 0; i < test->getChildTestCount(); i++)
5895
n_tests_added +=
5996
add_matching_tests_to_runner(test->getChildTestAt(i), allow_r_str, allow_r,
60-
deny_r_str, deny_r, runner, rejects);
97+
deny_r_str, deny_r, runner);
6198

6299
return n_tests_added;
63100
}
@@ -128,10 +165,6 @@ int main(int argc, char ** argv)
128165
CppUnit::TestFactoryRegistry & registry = CppUnit::TestFactoryRegistry::getRegistry();
129166
CppUnit::Test * suite = registry.makeTest();
130167

131-
// A test suite container for holding tests not matching the regex. When main's
132-
// scope ends, this class's destructor will delete the rejected tests
133-
CppUnit::TestSuite rejects("rejects");
134-
135168
#ifdef LIBMESH_HAVE_CXX11_REGEX
136169
// Make regex objects from user's input.
137170
const std::regex allow_regex(allow_regex_string);
@@ -143,9 +176,12 @@ int main(int argc, char ** argv)
143176
add_matching_tests_to_runner(suite,
144177
allow_regex_string, allow_regex,
145178
deny_regex_string, deny_regex,
146-
runner, rejects);
179+
runner);
147180
if (n_tests_added >= 0)
148181
libMesh::out << "--- Running " << n_tests_added << " tests in total." << std::endl;
182+
183+
// If we didn't add the whole suite to the runner, we need to clean
184+
// it up ourselves
149185
if (n_tests_added != -12345)
150186
owned_suite.reset(suite);
151187
#else

0 commit comments

Comments
 (0)