PSCF v1.1
UnitTestRunner.h
1#ifndef UNIT_TEST_RUNNER_H
2#define UNIT_TEST_RUNNER_H
3
4/*
5* Simpatico - Simulation Package for Polymeric and Molecular Liquids
6*
7* Copyright 2010 - 2017, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "TestRunner.h"
12#include "TestException.h"
13#include <vector>
14
109template <class UnitTestClass>
111{
112
113public:
114
117
121 typedef void (UnitTestClass::*MethodPtr)();
122
127
132
133 // Use compiler generated destructor.
134
138 void addTestMethod(MethodPtr methodPtr);
139
143 int nTestMethod();
144
150 void method(unsigned int i);
151
155 virtual int run();
156
157private:
158
159 std::vector<MethodPtr> methodPtrs_;
160
161 #ifdef TEST_MPI
162 std::vector<int> results_;
163 #endif
164
165};
166
167
168/*
169* Constructor.
170*/
171template <class UnitTestClass>
173 : TestRunner()
174{
175 #ifdef TEST_MPI
176 if (isIoProcessor()) {
177 results_.reserve(mpiSize());
178 for (int i=0; i < mpiSize(); ++i) {
179 results_.push_back(false);
180 }
181 }
182 #endif
183}
184
185/*
186* Destructor.
187*/
188template <class UnitTestClass>
190{}
191
192/*
193* Register a test method of the associated unit test class.
194*/
195template <class UnitTestClass>
197{ methodPtrs_.push_back(methodPtr); }
198
199/*
200* Return the number of registered test methods.
201*/
202template <class UnitTestClass>
204{ return methodPtrs_.size(); }
205
206/*
207* Run test method number i.
208*
209* \param i index of test method
210*/
211template <class UnitTestClass>
213{
214 UnitTestClass testCase;
215 #ifdef TEST_MPI
216 TestException exception;
217 int result;
218 #endif
219
220 testCase.setFilePrefix(filePrefix());
221
222 // Run test method (try / catch)
223 try {
224 testCase.setUp();
225 (testCase.*methodPtrs_[i])();
226 #ifndef TEST_MPI
227 std::cout << ".";
228 recordSuccess();
229 #else
230 result = 1;
231 #endif
232 } catch (TestException &e) {
233 #ifndef TEST_MPI
234 std::cout << std::endl;
235 std::cout << " Failure " << std::endl << std::endl;
236 std::cout << e.message() << std::endl;
237 std::cout << ".";
238 recordFailure();
239 #else
240 result = 0;
241 exception = e;
242 #endif
243 }
244 testCase.tearDown();
245
246 #ifdef TEST_MPI
247 // Process MPI Tests from all processors
248 MPI::COMM_WORLD.Barrier();
249 if (mpiRank() == 0) {
250 results_[0] = result; // Result on processor 0
251 if (results_[0] == 0) {
252 std::cout << std::endl;
253 std::cout << " Failure on Processor 0"
254 << std::endl << std::endl;
255 std::cout << exception.message() << std::endl;
256 std::cout.flush();
257 }
258 for (int i=1; i < mpiSize(); ++i) {
259 // Receive result results_[i] of test on processor i.
260 MPI::COMM_WORLD.Recv(&(results_[i]), 1, MPI_INT, i, i);
261 // If the test failed on processor i
262 if (results_[i] == 0) {
263 result = 0; // fails (==0) if failure on any processor
264 // Send permission to print failure on processor i
265 MPI::COMM_WORLD.Send(&(results_[i]), 1, MPI_INT, i, mpiSize() + i);
266 // Receive confirmation that processor i completed printing
267 MPI::COMM_WORLD.Recv(&(results_[i]), 1, MPI_INT, i, 2*mpiSize() + i);
268 }
269 }
270 // Record success on master (rank == 0) iff success on all processors
271 if (result) {
272 recordSuccess();
273 } else {
274 recordFailure();
275 }
276 std::cout << ".";
277 std::cout.flush();
278 } else { // Slave node
279 // Send result of test on this processor to master, tag = mpiRank().
280 MPI::COMM_WORLD.Send(&result, 1, MPI_INT, 0, mpiRank());
281 // If test failed on this processor
282 if (result == 0) {
283 // Receive permission to print failure statement
284 MPI::COMM_WORLD.Recv(&result, 1, MPI_INT, 0,
285 mpiSize() + mpiRank());
286 std::cout.flush();
287 std::cout << std::endl;
288 std::cout << " Failure on Processor " << mpiRank()
289 << std::endl << std::endl;
290 std::cout << exception.message() << std::endl;
291 std::cout.flush();
292 // Confirm completion of print.
293 MPI::COMM_WORLD.Send(&result, 1, MPI_INT, 0,
294 2*mpiSize() + mpiRank());
295 }
296 }
297 MPI::COMM_WORLD.Barrier();
298 #endif // ifdef TEST_MPI
299
300}
301
302/*
303* Run all registered test methods in the order added.
304*/
305template <class UnitTestClass>
307{
308 for (unsigned int i = 0; i < methodPtrs_.size(); ++i) {
309 method(i);
310 }
311 report();
312 return nFailure();
313}
314
315// Preprocessor Macros -------------------------------------------------
316
320#define TEST_RUNNER(UnitTestClass) UnitTestClass##_Runner
321
328#define TEST_BEGIN(UnitTestClass) \
329 class TEST_RUNNER(UnitTestClass) \
330 : public UnitTestRunner<UnitTestClass> \
331 { public: TEST_RUNNER(UnitTestClass)() {
332
336#define TEST_ADD(UnitTestClass, Method) \
337 addTestMethod(&UnitTestClass::Method);
338
344#define TEST_END(UnitTestClass) } };
345
346#endif
An exception thrown by a failed unit test.
Definition: TestException.h:20
const std::string & message()
Return the error message.
Abstract base class for classes that run tests.
Definition: TestRunner.h:74
bool isIoProcessor() const
Is this the IO processor of an MPI communicator?
Definition: TestRunner.h:236
int nFailure() const
Return number of failed tests run.
Definition: TestRunner.h:223
Template for a TestRunner that runs test methods of an associated UnitTest.
bool isIoProcessor() const
Is this the IO processor of an MPI communicator?
Definition: TestRunner.h:236
void(UnitTestClass::* MethodPtr)()
Pointer to a test method of the associated UnitTest class.
UnitTestRunner()
Constructor.
void addTestMethod(MethodPtr methodPtr)
Register a test method of the associated unit test class.
virtual int run()
Run all registered test methods in the order added.
int nTestMethod()
Return the number of registered test methods.
~UnitTestRunner()
Destructor.
void method(unsigned int i)
Run test method number i.