mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
282 lines
6.4 KiB
C++
282 lines
6.4 KiB
C++
// ---
|
|
//
|
|
// $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(Suite* suite)
|
|
{
|
|
_suites.push_back(suite);
|
|
}
|
|
|
|
/// 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
|