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