PSCF v1.3
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>
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 << ".";
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 << ".";
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) {
273 } else {
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.
const std::string & message()
Return the error message.
bool isIoProcessor() const
Is this the IO processor of an MPI communicator?
Definition TestRunner.h:236
const std::string & filePrefix() const
Return file prefix by const reference.
Definition TestRunner.h:230
void recordFailure()
Increment counter for failed tests, and that of parent (if any).
Definition TestRunner.h:284
void recordSuccess()
Increment counter for successful tests, and that of parent (if any).
Definition TestRunner.h:297
int nFailure() const
Return number of failed tests run.
Definition TestRunner.h:223
TestRunner()
Constructor.
Definition TestRunner.h:252
void report() const
If this object has no parent, report success and failure counters.
Definition TestRunner.h:310
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 nFailure() const
Return number of failed tests run.
Definition TestRunner.h:223
int nTestMethod()
Return the number of registered test methods.
~UnitTestRunner()
Destructor.
void method(unsigned int i)
Run test method number i.