1 // --- 2 // 3 // $Id: suite.cpp,v 1.7 2010/03/26 04:38:25 hartwork Exp $ 4 // 5 // CppTest - A C++ Unit Testing Framework 6 // Copyright (c) 2003 Niklas Lundell 7 // 8 // --- 9 // 10 // This library is free software; you can redistribute it and/or 11 // modify it under the terms of the GNU Lesser General Public 12 // License as published by the Free Software Foundation; either 13 // version 2 of the License, or (at your option) any later version. 14 // 15 // This library is distributed in the hope that it will be useful, 16 // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 // Lesser General Public License for more details. 19 // 20 // You should have received a copy of the GNU Lesser General Public 21 // License along with this library; if not, write to the 22 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, 23 // Boston, MA 02111-1307, USA. 24 // 25 // --- 26 27 #include <algorithm> 28 #include <cassert> 29 #include <cstring> 30 #include <functional> 31 #include <numeric> 32 33 #if (defined(__WIN32__) || defined(WIN32)) 34 # include "winconfig.h" 35 #else 36 # include "config.h" 37 #endif 38 39 #include "cpptest-output.h" 40 #include "cpptest-source.h" 41 #include "cpptest-suite.h" 42 43 using namespace std; 44 45 namespace Test 46 { 47 namespace 48 { 49 // Destroys all dynamically allocated objects within the given range. 50 // 51 template <class FwdIter> 52 void destroy_range(FwdIter first,FwdIter last)53 destroy_range(FwdIter first, FwdIter last) 54 { 55 while (first != last) 56 delete *first++; 57 } 58 59 } // anonymous namespace 60 61 /// Constructs an empty test suite. 62 /// Suite()63 Suite::Suite() 64 : _cur_test(0), 65 _output(0), 66 _success(true) 67 {} 68 69 /// Destroys this suite object. 70 /// ~Suite()71 Suite::~Suite() 72 { 73 destroy_range(_suites.begin(), _suites.end()); 74 } 75 76 /// Starts the testing. All tests in this suite and embedded suites will 77 /// be executed. 78 /// 79 /// \param output Progress report destination. 80 /// \param cont_after_fail Continue functions despite failures. 81 /// 82 /// \return True if no test failed; false otherwise. 83 /// 84 bool run(Output & output,bool cont_after_fail)85 Suite::run(Output& output, bool cont_after_fail) 86 { 87 int ntests = total_tests(); 88 output.initialize(ntests); 89 do_run(&output, cont_after_fail); 90 output.finished(ntests, total_time(true)); 91 return _success; 92 } 93 94 /// \fn void Suite::setup() 95 /// 96 /// Setups a test fixture. This function is called before each test, 97 /// in this suite, is executed. 98 /// 99 /// This function should be overloaded by derived classes to provide 100 /// specialized behavior. 101 /// 102 /// \see tear_down() 103 104 /// \fn void Suite::tear_down() 105 /// 106 /// Tears down a test fixture. This function is called after each test, 107 /// in this suite, have been executed. 108 /// 109 /// This function should be overloaded by derived classes to provide 110 /// specialized behavior. 111 /// 112 /// \see setup() 113 114 /// Adds a suite to this suite. Tests in added suites will be executed 115 /// when run() of the top-level suite is called. 116 /// 117 /// \param suite %Test suite to add. 118 /// 119 void add(unique_ptr<Suite> suite)120 Suite::add(unique_ptr<Suite> suite) 121 { 122 _suites.push_back(suite.release()); 123 } 124 125 /// Registers a test function. 126 /// 127 /// \b Note: Do not call this function directly, use the TEST_ADD(func) 128 /// macro instead. 129 /// 130 /// \param func Pointer to a test function. 131 /// \param name Class and function name of the function. The format \b must 132 /// equal \e class::func. 133 /// 134 void register_test(Func func,const string & name)135 Suite::register_test(Func func, const string& name) 136 { 137 string::size_type pos = name.find_first_of(':'); 138 assert(!name.empty() && name[pos + 1] == ':' && name[pos + 2] != '\0'); 139 140 _name.assign(name, 0, pos); 141 _tests.push_back(Data(func, name.substr(pos + 2))); 142 } 143 144 /// Issues an assertment to the output handler. 145 /// 146 /// Do not call this function directly, use one of the available assertment 147 /// macros instead, see \ref asserts. 148 /// 149 /// \param s Assert point information. 150 /// 151 void assertment(Source s)152 Suite::assertment(Source s) 153 { 154 s._suite = _name; 155 s._test = *_cur_test; 156 _output->assertment(s); 157 _result = _success = false; 158 } 159 160 // Functor to execute tests for the given suite. 161 // 162 struct Suite::ExecTests 163 { 164 Suite& _suite; 165 ExecTestsTest::Suite::ExecTests166 ExecTests(Suite& s) : _suite(s) {} 167 operator ()Test::Suite::ExecTests168 void operator()(Data& data) 169 { 170 _suite._cur_test = &data._name; 171 _suite._result = true; // assume success, assert will set to false 172 _suite._output->test_start(data._name); 173 174 _suite.setup(); 175 Time start(Time::current()); 176 // FIXME Also feedback exception to user 177 try 178 { 179 (_suite.*data._func)(); 180 } catch (...) { 181 _suite._result = _suite._success = false; 182 } 183 Time end(Time::current()); 184 _suite.tear_down(); 185 186 data._time = end - start; 187 _suite._output->test_end(data._name, _suite._result, data._time); 188 } 189 }; 190 191 // Functor to execute a suite. 192 // 193 struct Suite::DoRun 194 { 195 bool _continue; 196 Output* _output; 197 DoRunTest::Suite::DoRun198 DoRun(Output* output, bool cont) : _continue(cont), _output(output) {} operator ()Test::Suite::DoRun199 void operator()(Suite* suite) { suite->do_run(_output, _continue); } 200 }; 201 202 // Execute all tests in this and added suites. 203 // 204 void do_run(Output * os,bool cont_after_fail)205 Suite::do_run(Output* os, bool cont_after_fail) 206 { 207 _continue = cont_after_fail; 208 _output = os; 209 210 _output->suite_start(_tests.size(), _name); 211 for_each(_tests.begin(), _tests.end(), ExecTests(*this)); 212 _output->suite_end(_tests.size(), _name, total_time(false)); 213 214 for_each(_suites.begin(), _suites.end(), DoRun(_output, _continue)); 215 216 // FIXME Find a cleaner way 217 Suites::const_iterator iter = _suites.begin(); 218 while (iter != _suites.end()) 219 { 220 if (!(*iter)->_success) 221 { 222 _success = false; 223 break; 224 } 225 iter++; 226 } 227 } 228 229 // Functor to count all tests in a suite. 230 // 231 struct Suite::SubSuiteTests 232 { operator ()Test::Suite::SubSuiteTests233 int operator()(size_t value, const Suite* s) const 234 { 235 return value + s->total_tests(); 236 } 237 }; 238 239 // Counts all tests in this and all its embedded suites. 240 // 241 int total_tests() const242 Suite::total_tests() const 243 { 244 return accumulate(_suites.begin(), _suites.end(), 245 _tests.size(), SubSuiteTests()); 246 } 247 248 // Functor to accumulate execution time for tests. 249 // 250 struct Suite::SuiteTime 251 { operator ()Test::Suite::SuiteTime252 Time operator()(const Time& time, const Data& data) 253 { 254 return time + data._time; 255 } 256 }; 257 258 // Functor to accumulate execution time for suites. 259 // 260 struct Suite::SubSuiteTime 261 { operator ()Test::Suite::SubSuiteTime262 Time operator()(Time time, const Suite* s) const 263 { 264 return time + s->total_time(true); 265 } 266 }; 267 268 // Counts time accumulated execution time for all tests in this and all 269 // its embedded suites. 270 // 271 Time total_time(bool recursive) const272 Suite::total_time(bool recursive) const 273 { 274 Time time = accumulate(_tests.begin(), _tests.end(), 275 Time(), SuiteTime()); 276 277 return !recursive ? time : accumulate(_suites.begin(), _suites.end(), 278 time, SubSuiteTime()); 279 } 280 281 } // namespace Test 282