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
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+
59+ // "Magic number" for when we're not doing allow or deny regex
60+ static constexpr int added_whole_suite = -12345 ;
61+
2062// Add Tests to runner that match user-provided regex.
2163int add_matching_tests_to_runner (CppUnit ::Test * test ,
2264 const std ::string & allow_r_str ,
2365 const std ::regex & allow_r ,
2466 const std ::string & deny_r_str ,
2567 const std ::regex & deny_r ,
26- CppUnit ::TextUi ::TestRunner & runner ,
27- CppUnit ::TestSuite & rejects )
68+ CppUnit ::TextUi ::TestRunner & runner )
2869{
2970 int n_tests_added = 0 ;
3071
@@ -34,7 +75,7 @@ int add_matching_tests_to_runner(CppUnit::Test * test,
3475 {
3576 libMesh ::out << test -> getName () << std ::endl ;
3677 runner .addTest (test );
37- return -12345 ;
78+ return added_whole_suite ;
3879 }
3980
4081 if (test -> getChildTestCount () == 0 )
@@ -46,18 +87,17 @@ int add_matching_tests_to_runner(CppUnit::Test * test,
4687 {
4788 libMesh ::out << test -> getName () << std ::endl ;
4889 n_tests_added ++ ;
49- runner .addTest (test );
90+
91+ // yes, explicit new; this is how CppUnit works
92+ runner .addTest (new TestShim (* test ));
5093 }
51- // Add the test to the rejects it can be cleaned up later
52- else
53- rejects .addTest (test );
5494 }
5595
5696 // Call this recursively on each of our children, if any.
5797 for (int i = 0 ; i < test -> getChildTestCount (); i ++ )
5898 n_tests_added +=
5999 add_matching_tests_to_runner (test -> getChildTestAt (i ), allow_r_str , allow_r ,
60- deny_r_str , deny_r , runner , rejects );
100+ deny_r_str , deny_r , runner );
61101
62102 return n_tests_added ;
63103}
@@ -116,15 +156,17 @@ int main(int argc, char ** argv)
116156 std ::string deny_regex_string = "^$" ;
117157 deny_regex_string = libMesh ::command_line_next ("--deny_re" , deny_regex_string );
118158
159+ // We might have to delete the test suite ourselves, after the
160+ // runner has deleted whatever subtests it has.
161+ std ::unique_ptr < CppUnit ::Test > owned_suite ;
162+
119163 // Recursively add tests matching the regex to the runner object.
120164 CppUnit ::TextUi ::TestRunner runner ;
121165
122- // The Cppunit registry object that knows about all the tests.
166+ // The Cppunit registry object that knows about all the tests, and
167+ // the test suite it creates.
123168 CppUnit ::TestFactoryRegistry & registry = CppUnit ::TestFactoryRegistry ::getRegistry ();
124-
125- // A test suite container for holding tests not matching the regex. When main's
126- // scope ends, this class's destructor will delete the rejected tests
127- CppUnit ::TestSuite rejects ("rejects" );
169+ CppUnit ::Test * suite = registry .makeTest ();
128170
129171#ifdef LIBMESH_HAVE_CXX11_REGEX
130172 // Make regex objects from user's input.
@@ -134,15 +176,20 @@ int main(int argc, char ** argv)
134176 // Add all tests which match the re to the runner object.
135177 libMesh ::out << "Will run the following tests:" << std ::endl ;
136178 const int n_tests_added =
137- add_matching_tests_to_runner (registry . makeTest () ,
179+ add_matching_tests_to_runner (suite ,
138180 allow_regex_string , allow_regex ,
139181 deny_regex_string , deny_regex ,
140- runner , rejects );
182+ runner );
141183 if (n_tests_added >= 0 )
142184 libMesh ::out << "--- Running " << n_tests_added << " tests in total." << std ::endl ;
185+
186+ // If we didn't add the whole suite to the runner, we need to clean
187+ // it up ourselves
188+ if (n_tests_added != added_whole_suite )
189+ owned_suite .reset (suite );
143190#else
144191 // If no C++11 <regex> just run all the tests.
145- runner .addTest (registry . makeTest () );
192+ runner .addTest (suite );
146193#endif
147194
148195 std ::unique_ptr < CppUnit ::TestResult > controller ;
0 commit comments