libMesh
Loading...
Searching...
No Matches
driver.C
Go to the documentation of this file.
1// Ignore overloaded-virtual warnings coming from cppunit headers
2#include <libmesh/ignore_warnings.h>
3#include <cppunit/extensions/TestFactoryRegistry.h>
4#include <cppunit/ui/text/TestRunner.h>
5#include <cppunit/BriefTestProgressListener.h>
6#include <cppunit/TestPath.h>
7#include <cppunit/TestResult.h>
8#include <cppunit/TestListener.h>
9#include <cppunit/TestFailure.h>
10#include <cppunit/Exception.h>
11#include <libmesh/restore_warnings.h>
12
13// libMesh includes
14#include <libmesh/libmesh.h>
15#include <libmesh/libmesh_abort.h>
16
17#include "libmesh_cppunit.h"
18#include "test_comm.h"
19
20// CppUnit catches the exceptions that escape a test and reports them
21// only at the end of the run, through std::cout, which libMesh
22// discards on processors other than 0 unless --keep-cout is given.
23// CppUnit distinguishes two kinds, both passed to
24// TestListener::addFailure():
25//
26// - a failure is a CppUnit::Exception, thrown when one of CppUnit's
27// own checks such as CPPUNIT_ASSERT fails;
28// - an error is any other exception, including every exception
29// libMesh throws, e.g. from libmesh_error_msg() or a failed
30// libmesh_assert().
31//
32// This listener writes each failure and error to libMesh::err as soon
33// as it is caught, on every processor.
34//
35// Whether an error occurs usually depends on data that differs
36// between processors, so in a parallel run an error often happens on
37// only some of them. Those processors move on to the next test while
38// the others are still in the current one, so the run hangs or fails
39// elsewhere; the listener therefore aborts the whole run on an error.
40// Failures typically come from checks on replicated data that fail on
41// every processor together, so the run continues past them.
42class FailureReporter : public CppUnit::TestListener
43{
44public:
45 virtual void addFailure(const CppUnit::TestFailure & failure) override;
46};
47
48void FailureReporter::addFailure(const CppUnit::TestFailure & failure)
49{
51 << failure.failedTestName()
52 << (failure.isError() ? " error" : " failure");
53
54 const CppUnit::SourceLine source_line = failure.sourceLine();
55 if (source_line.isValid())
56 libMesh::err << " at " << source_line.fileName()
57 << ":" << source_line.lineNumber();
58
59 libMesh::err << ":\n" << failure.thrownException()->what() << std::endl;
60
61 if (failure.isError() && libMesh::global_n_processors() > 1)
63}
64
65#ifdef LIBMESH_HAVE_CXX11_REGEX
66
67// C++ includes
68#include <regex>
69
70// We want to be able to add a selection of tests from our full suite
71// to our test runner. But then the test runner will want to destruct
72// those tests afterward, so we can't destruct the suite without it
73// *also* trying to destruct all its tests (undefined behavior), and
74// we can't not destruct the suite without the suite and its
75// unselected tests being leaked (which would be fine since just exit
76// afterward, except valgrind sees the leaks and screams).
77//
78// So, instead of adding selected tests, we add shims of selected
79// tests that can be deleted without deleting the tests they shim.
80class TestShim : public CppUnit::Test
81{
82public:
83 TestShim (CppUnit::Test & shimmed_test) : _shimmed_test(shimmed_test) {}
84
85 virtual void run(CppUnit::TestResult * result) override { _shimmed_test.run(result); }
86
87 virtual int countTestCases () const override { return _shimmed_test.countTestCases(); }
88
89 virtual int getChildTestCount () const override { return _shimmed_test.getChildTestCount(); }
90
91 virtual std::string getName () const override { return _shimmed_test.getName(); }
92
93 virtual bool findTestPath (const std::string & testName, CppUnit::TestPath & testPath) const override { return _shimmed_test.findTestPath(testName, testPath); }
94
95 virtual bool findTestPath (const CppUnit::Test * test, CppUnit::TestPath & testPath) const override { return _shimmed_test.findTestPath(test, testPath); }
96
97 virtual CppUnit::Test * findTest(const std::string & testName) const override { return _shimmed_test.findTest(testName); }
98
99 virtual CppUnit::TestPath resolveTestPath(const std::string & testPath) const override { return _shimmed_test.resolveTestPath(testPath); }
100
101protected:
102 virtual CppUnit::Test * doGetChildTestAt(int index) const override { return _shimmed_test.getChildTestAt(index); }
103
104private:
105 CppUnit::Test & _shimmed_test;
106};
107
108// "Magic number" for when we're not doing allow or deny regex
109static constexpr int added_whole_suite = -12345;
110
111// Add Tests to runner that match user-provided regex.
112int add_matching_tests_to_runner(CppUnit::Test * test,
113 const std::string & allow_r_str,
114 const std::regex & allow_r,
115 const std::string & deny_r_str,
116 const std::regex & deny_r,
117 CppUnit::TextUi::TestRunner & runner)
118{
119 int n_tests_added = 0;
120
121 // If running all tests, just add the "All Tests" test and return
122 if (test->getName() == "All Tests" && allow_r_str == "All Tests" &&
123 deny_r_str == "^$")
124 {
125 libMesh::out << test->getName() << std::endl;
126 runner.addTest(test);
127 return added_whole_suite;
128 }
129
130 if (test->getChildTestCount() == 0)
131 {
132 // Add the test to the runner
133 if ((allow_r_str == "All Tests" ||
134 std::regex_search(test->getName(), allow_r)) &&
135 !std::regex_search(test->getName(), deny_r))
136 {
137 libMesh::out << test->getName() << std::endl;
138 n_tests_added ++;
139
140 // yes, explicit new; this is how CppUnit works
141 runner.addTest(new TestShim(*test));
142 }
143 }
144
145 // Call this recursively on each of our children, if any.
146 for (int i = 0; i < test->getChildTestCount(); i++)
147 n_tests_added +=
148 add_matching_tests_to_runner(test->getChildTestAt(i), allow_r_str, allow_r,
149 deny_r_str, deny_r, runner);
150
151 return n_tests_added;
152}
153
154#endif
155
156
157int main(int argc, char ** argv)
158{
159 // Initialize the library. This is necessary because the library
160 // may depend on a number of other libraries (i.e. MPI and Petsc)
161 // that require initialization before use.
162 libMesh::LibMeshInit init(argc, argv);
163 TestCommWorld = &init.comm();
164
165 // See how long each of our tests are taking to run. This should be
166 // coarse-grained enough to enable even if we're not performance
167 // logging inside the library itself. We need to do this early, so
168 // we can query unitlog when first initializing tests.
169 libMesh::PerfLog driver_unitlog ("Unit Tests");
170 unitlog = &driver_unitlog;
171
172 // Print just logs summarized by test suite, not every test
173 // individually
174 if (!libMesh::on_command_line("--full-logs"))
175 driver_unitlog.enable_summarized_logs();
176
177 // We can now run all tests that match a regular expression, for
178 // example, "--re PartitionerTest" will match all the Partitioner
179 // unit tests. If the user does not specify a regex, we run all the
180 // tests returned by makeTest().
181
182 // An example regex_string that would _exactly_ match a _single_ test is:
183 // "PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh::testPartition2"
184 // On the other hand, the regex "HilbertSFC" would match all of the
185 // following tests:
186 //
187 // PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh
188 // PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh::testPartitionEmpty
189 // PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh::testPartition1
190 // PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh::testPartition2
191 // PartitionerTest_HilbertSFCPartitioner_ReplicatedMesh::testPartitionNProc
192 //
193 // If the user does not provide a a regex, the default re is "All Tests",
194 // which runs all the unit tests.
195
196 // We can also skip tests that match a regular expression, with e.g.
197 // "--deny_re PartitionerTest" to skip all the Partitioner unit
198 // tests (even if a "--re" option would have included them.)
199
200 // Read command line argument specifying the allowlist regular expression.
201 std::string allow_regex_string = "All Tests";
202 allow_regex_string = libMesh::command_line_next("--re", allow_regex_string);
203
204 // Read command line argument specifying the allowlist regular expression.
205 std::string deny_regex_string = "^$";
206 deny_regex_string = libMesh::command_line_next("--deny_re", deny_regex_string);
207
208 // We might have to delete the test suite ourselves, after the
209 // runner has deleted whatever subtests it has.
210 std::unique_ptr<CppUnit::Test> owned_suite;
211
212 // Recursively add tests matching the regex to the runner object.
213 CppUnit::TextUi::TestRunner runner;
214
215 // The Cppunit registry object that knows about all the tests, and
216 // the test suite it creates.
217 CppUnit::TestFactoryRegistry & registry = CppUnit::TestFactoryRegistry::getRegistry();
218 CppUnit::Test * suite = registry.makeTest();
219
220#ifdef LIBMESH_HAVE_CXX11_REGEX
221 // Make regex objects from user's input.
222 const std::regex allow_regex(allow_regex_string);
223 const std::regex deny_regex(deny_regex_string);
224
225 // Add all tests which match the re to the runner object.
226 libMesh::out << "Will run the following tests:" << std::endl;
227 const int n_tests_added =
229 allow_regex_string, allow_regex,
230 deny_regex_string, deny_regex,
231 runner);
232 if (n_tests_added >= 0)
233 libMesh::out << "--- Running " << n_tests_added << " tests in total." << std::endl;
234
235 // If we didn't add the whole suite to the runner, we need to clean
236 // it up ourselves
237 if (n_tests_added != added_whole_suite)
238 owned_suite.reset(suite);
239#else
240 // If no C++11 <regex> just run all the tests.
241 runner.addTest(suite);
242#endif
243
244 std::unique_ptr<CppUnit::TestResult> controller;
245 std::unique_ptr<CppUnit::BriefTestProgressListener> listener;
246
247 // Actually run all the requested tests, possibly with verbose
248 // output of test names as they are run
249 if (libMesh::on_command_line("--verbose"))
250 {
251 listener = std::make_unique<CppUnit::BriefTestProgressListener>();
252 runner.eventManager().addListener(listener.get());
253 }
254
255 FailureReporter failure_reporter;
256 runner.eventManager().addListener(&failure_reporter);
257
258 bool succeeded = runner.run();
259
260 // Many users won't care at all about the PerfLog
261#ifndef LIBMESH_ENABLE_PERFORMANCE_LOGGING
262 if (!libMesh::on_command_line("--full-logs"))
263 driver_unitlog.clear();
264#endif
265
266 // 1 for failure, 0 for success
267 return !succeeded;
268}
269
271
virtual void addFailure(const CppUnit::TestFailure &failure) override
Definition driver.C:48
virtual int getChildTestCount() const override
Definition driver.C:89
virtual std::string getName() const override
Definition driver.C:91
virtual void run(CppUnit::TestResult *result) override
Definition driver.C:85
virtual int countTestCases() const override
Definition driver.C:87
virtual bool findTestPath(const CppUnit::Test *test, CppUnit::TestPath &testPath) const override
Definition driver.C:95
TestShim(CppUnit::Test &shimmed_test)
Definition driver.C:83
virtual CppUnit::TestPath resolveTestPath(const std::string &testPath) const override
Definition driver.C:99
virtual CppUnit::Test * findTest(const std::string &testName) const override
Definition driver.C:97
virtual CppUnit::Test * doGetChildTestAt(int index) const override
Definition driver.C:102
CppUnit::Test & _shimmed_test
Definition driver.C:105
virtual bool findTestPath(const std::string &testName, CppUnit::TestPath &testPath) const override
Definition driver.C:93
void reset(streamT &target)
Reset the proxy to point to a different target.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
The PerfLog class allows monitoring of specific events.
Definition perf_log.h:154
void clear()
Clears all the internal data and restores the data structures to a pristine state.
Definition perf_log.C:78
void enable_summarized_logs()
Tells the PerfLog to only print log results summarized by header.
Definition perf_log.h:199
static constexpr int added_whole_suite
Definition driver.C:109
libMesh::PerfLog * unitlog
Definition driver.C:272
libMesh::Parallel::Communicator * TestCommWorld
Definition driver.C:270
int add_matching_tests_to_runner(CppUnit::Test *test, const std::string &allow_r_str, const std::regex &allow_r, const std::string &deny_r_str, const std::regex &deny_r, CppUnit::TextUi::TestRunner &runner)
Definition driver.C:112
OStreamProxy err
processor_id_type global_processor_id()
OStreamProxy out
T command_line_next(std::string name, T default_value)
Use GetPot's search()/next() functions to get following arguments from the command line.
Definition libmesh.C:1025
processor_id_type global_n_processors()
void libmesh_abort()
Abort as soon as possible.
Definition libmesh.C:338
bool on_command_line(std::string arg)
Definition libmesh.C:934
int main()