--- /dev/null
+// ---
+//
+// $Id: suite.cpp,v 1.7 2010/03/26 04:38:25 hartwork Exp $
+//
+// CppTest - A C++ Unit Testing Framework
+// Copyright (c) 2003 Niklas Lundell
+//
+// ---
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+//
+// ---
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <functional>
+#include <numeric>
+
+#if (defined(__WIN32__) || defined(WIN32))
+# include "winconfig.h"
+#else
+# include "config.h"
+#endif
+
+#include "cpptest-output.h"
+#include "cpptest-source.h"
+#include "cpptest-suite.h"
+
+using namespace std;
+
+namespace Test
+{
+ namespace
+ {
+ // Destroys all dynamically allocated objects within the given range.
+ //
+ template <class FwdIter>
+ void
+ destroy_range(FwdIter first, FwdIter last)
+ {
+ while (first != last)
+ delete *first++;
+ }
+
+ } // anonymous namespace
+
+ /// Constructs an empty test suite.
+ ///
+ Suite::Suite()
+ : _cur_test(0),
+ _output(0),
+ _success(true)
+ {}
+
+ /// Destroys this suite object.
+ ///
+ Suite::~Suite()
+ {
+ destroy_range(_suites.begin(), _suites.end());
+ }
+
+ /// Starts the testing. All tests in this suite and embedded suites will
+ /// be executed.
+ ///
+ /// \param output Progress report destination.
+ /// \param cont_after_fail Continue functions despite failures.
+ ///
+ /// \return True if no test failed; false otherwise.
+ ///
+ bool
+ Suite::run(Output& output, bool cont_after_fail)
+ {
+ int ntests = total_tests();
+ output.initialize(ntests);
+ do_run(&output, cont_after_fail);
+ output.finished(ntests, total_time(true));
+ return _success;
+ }
+
+ /// \fn void Suite::setup()
+ ///
+ /// Setups a test fixture. This function is called before each test,
+ /// in this suite, is executed.
+ ///
+ /// This function should be overloaded by derived classes to provide
+ /// specialized behavior.
+ ///
+ /// \see tear_down()
+
+ /// \fn void Suite::tear_down()
+ ///
+ /// Tears down a test fixture. This function is called after each test,
+ /// in this suite, have been executed.
+ ///
+ /// This function should be overloaded by derived classes to provide
+ /// specialized behavior.
+ ///
+ /// \see setup()
+
+ /// Adds a suite to this suite. Tests in added suites will be executed
+ /// when run() of the top-level suite is called.
+ ///
+ /// \param suite %Test suite to add.
+ ///
+ void
+ Suite::add(auto_ptr<Suite> suite)
+ {
+ _suites.push_back(suite.release());
+ }
+
+ /// Registers a test function.
+ ///
+ /// \b Note: Do not call this function directly, use the TEST_ADD(func)
+ /// macro instead.
+ ///
+ /// \param func Pointer to a test function.
+ /// \param name Class and function name of the function. The format \b must
+ /// equal \e class::func.
+ ///
+ void
+ Suite::register_test(Func func, const string& name)
+ {
+ string::size_type pos = name.find_first_of(':');
+ assert(!name.empty() && name[pos + 1] == ':' && name[pos + 2] != '\0');
+
+ _name.assign(name, 0, pos);
+ _tests.push_back(Data(func, name.substr(pos + 2)));
+ }
+
+ /// Issues an assertment to the output handler.
+ ///
+ /// Do not call this function directly, use one of the available assertment
+ /// macros instead, see \ref asserts.
+ ///
+ /// \param s Assert point information.
+ ///
+ void
+ Suite::assertment(Source s)
+ {
+ s._suite = _name;
+ s._test = *_cur_test;
+ _output->assertment(s);
+ _result = _success = false;
+ }
+
+ // Functor to execute tests for the given suite.
+ //
+ struct Suite::ExecTests
+ {
+ Suite& _suite;
+
+ ExecTests(Suite& s) : _suite(s) {}
+
+ void operator()(Data& data)
+ {
+ _suite._cur_test = &data._name;
+ _suite._result = true; // assume success, assert will set to false
+ _suite._output->test_start(data._name);
+
+ _suite.setup();
+ Time start(Time::current());
+ // FIXME Also feedback exception to user
+ try
+ {
+ (_suite.*data._func)();
+ } catch (...) {
+ _suite._result = _suite._success = false;
+ }
+ Time end(Time::current());
+ _suite.tear_down();
+
+ data._time = end - start;
+ _suite._output->test_end(data._name, _suite._result, data._time);
+ }
+ };
+
+ // Functor to execute a suite.
+ //
+ struct Suite::DoRun
+ {
+ bool _continue;
+ Output* _output;
+
+ DoRun(Output* output, bool cont) : _continue(cont), _output(output) {}
+ void operator()(Suite* suite) { suite->do_run(_output, _continue); }
+ };
+
+ // Execute all tests in this and added suites.
+ //
+ void
+ Suite::do_run(Output* os, bool cont_after_fail)
+ {
+ _continue = cont_after_fail;
+ _output = os;
+
+ _output->suite_start(_tests.size(), _name);
+ for_each(_tests.begin(), _tests.end(), ExecTests(*this));
+ _output->suite_end(_tests.size(), _name, total_time(false));
+
+ for_each(_suites.begin(), _suites.end(), DoRun(_output, _continue));
+
+ // FIXME Find a cleaner way
+ Suites::const_iterator iter = _suites.begin();
+ while (iter != _suites.end())
+ {
+ if (!(*iter)->_success)
+ {
+ _success = false;
+ break;
+ }
+ iter++;
+ }
+ }
+
+ // Functor to count all tests in a suite.
+ //
+ struct Suite::SubSuiteTests
+ {
+ int operator()(size_t value, const Suite* s) const
+ {
+ return value + s->total_tests();
+ }
+ };
+
+ // Counts all tests in this and all its embedded suites.
+ //
+ int
+ Suite::total_tests() const
+ {
+ return accumulate(_suites.begin(), _suites.end(),
+ _tests.size(), SubSuiteTests());
+ }
+
+ // Functor to accumulate execution time for tests.
+ //
+ struct Suite::SuiteTime
+ {
+ Time operator()(const Time& time, const Data& data)
+ {
+ return time + data._time;
+ }
+ };
+
+ // Functor to accumulate execution time for suites.
+ //
+ struct Suite::SubSuiteTime
+ {
+ Time operator()(Time time, const Suite* s) const
+ {
+ return time + s->total_time(true);
+ }
+ };
+
+ // Counts time accumulated execution time for all tests in this and all
+ // its embedded suites.
+ //
+ Time
+ Suite::total_time(bool recursive) const
+ {
+ Time time = accumulate(_tests.begin(), _tests.end(),
+ Time(), SuiteTime());
+
+ return !recursive ? time : accumulate(_suites.begin(), _suites.end(),
+ time, SubSuiteTime());
+ }
+
+} // namespace Test