mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-09 22:20:24 +00:00
Unit tests + cleanup
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
// ---
|
||||
//
|
||||
// $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
|
||||
Reference in New Issue
Block a user