Improvements to beast::unit_test framework:

* Some runner member functions are now thread-safe.
* De-inline and tidy up declarations and definitions.
* arg() interface allows command lines to be passed to suites.
This commit is contained in:
Vinnie Falco
2014-10-28 06:56:19 -07:00
committed by Nik Bougalis
parent 9ab4f7bcc6
commit f5941041d4
7 changed files with 229 additions and 153 deletions

View File

@@ -31,28 +31,36 @@ namespace unit_test {
class amount
{
private:
std::size_t n;
std::string const& what;
std::size_t n_;
std::string const& what_;
public:
amount (amount const&) = default;
amount& operator= (amount const&) = delete;
amount (std::size_t n_, std::string const& what_)
: n (n_)
, what (what_)
{
}
template <class = void>
amount (std::size_t n, std::string const& what);
friend
std::ostream&
operator<< (std::ostream& s, amount const& t)
{
s << t.n << " " << t.what << ((t.n != 1) ? "s" : "");
return s;
}
operator<< (std::ostream& s, amount const& t);
};
template <class>
amount::amount (std::size_t n, std::string const& what)
: n_ (n)
, what_ (what)
{
}
inline
std::ostream&
operator<< (std::ostream& s, amount const& t)
{
s << t.n_ << " " << t.what_ << ((t.n_ != 1) ? "s" : "");
return s;
}
} // unit_test
} // beast

View File

@@ -20,30 +20,62 @@
#include <beast/unit_test/amount.h>
#include <beast/unit_test/global_suites.h>
#include <beast/unit_test/suite.h>
#include <string>
// Include this .cpp in your project to gain access to the printing suite
namespace beast {
namespace unit_test {
namespace detail {
/** A suite that prints the list of globally defined suites. */
class print_test : public suite
{
private:
template <class = void>
void
do_run();
public:
template <class = void>
static
std::string
prefix (suite_info const& s)
prefix (suite_info const& s);
template <class = void>
void
print (suite_list &c);
void
run()
{
do_run();
}
};
template <class>
void
print_test::do_run()
{
log << "------------------------------------------";
print (global_suites());
log << "------------------------------------------";
pass();
}
template <class>
std::string
print_test::prefix (suite_info const& s)
{
if (s.manual())
return "|M| ";
return " ";
}
}
void
print (suite_list &c)
{
template <class>
void
print_test::print (suite_list &c)
{
std::size_t manual (0);
for (auto const& s : c)
{
@@ -57,21 +89,10 @@ public:
amount (c.size(), "suite") << " total, " <<
amount (manual, "manual suite")
;
}
void
run()
{
log << "------------------------------------------";
print (global_suites());
log << "------------------------------------------";
pass();
}
};
}
BEAST_DEFINE_TESTSUITE_MANUAL(print,unit_test,beast);
}
}
}

View File

@@ -27,8 +27,7 @@ namespace unit_test {
namespace detail {
// Non const container is a detail, users are not allowed to modify!
inline
template <class = void>
suite_list&
global_suites()
{
@@ -36,17 +35,22 @@ global_suites()
return s;
}
// Used to insert suites during static initialization
template <class Suite>
struct global_suite_instance
struct insert_suite
{
template <class = void>
insert_suite (char const* name, char const* module,
char const* library, bool manual);
};
template <class Suite>
template <class>
insert_suite<Suite>::insert_suite (char const* name,
char const* module, char const* library, bool manual)
{
global_suite_instance (char const* name, char const* module,
char const* library, bool manual)
{
global_suites().insert <Suite> (
name, module, library, manual);
}
};
}
} // detail
@@ -58,7 +62,7 @@ global_suites()
return detail::global_suites();
}
} // unit_test
} // beast
}
}
#endif

View File

@@ -56,18 +56,30 @@ private:
std::string m_library;
public:
template <class = void>
explicit
selector (mode_t mode, std::string const& pattern = "")
selector (mode_t mode, std::string const& pattern = "");
template <class = void>
bool
operator() (suite_info const& s);
};
//------------------------------------------------------------------------------
template <class>
selector::selector (mode_t mode, std::string const& pattern)
: m_mode (mode)
, m_pat (pattern)
{
{
if (m_mode == automatch && pattern.empty())
m_mode = all;
}
}
bool
operator() (suite_info const& s)
{
template <class>
bool
selector::operator() (suite_info const& s)
{
switch (m_mode)
{
case automatch:
@@ -114,8 +126,7 @@ public:
};
return ! s.manual();
}
};
}
//------------------------------------------------------------------------------

View File

@@ -55,11 +55,11 @@ private:
: public const_container <std::vector <test>>
{
private:
std::size_t m_failed;
std::size_t failed_;
public:
tests_t ()
: m_failed (0)
: failed_ (0)
{
}
@@ -74,7 +74,7 @@ private:
std::size_t
failed() const
{
return m_failed;
return failed_;
}
/** Register a successful test condition. */
@@ -88,7 +88,7 @@ private:
void
fail (std::string const& reason = "")
{
++m_failed;
++failed_;
cont().emplace_back (false, reason);
}
};
@@ -105,11 +105,11 @@ private:
}
};
std::string m_name;
std::string name_;
public:
explicit case_results (std::string const& name = "")
: m_name (name)
: name_ (name)
{
}
@@ -117,7 +117,7 @@ public:
std::string const&
name() const
{
return m_name;
return name_;
}
/** Memberspace for a container of test condition outcomes. */
@@ -134,15 +134,13 @@ class suite_results
: public const_container <std::vector <case_results>>
{
private:
std::string m_name;
std::size_t m_total;
std::size_t m_failed;
std::string name_;
std::size_t total_ = 0;
std::size_t failed_ = 0;
public:
explicit suite_results (std::string const& name = "")
: m_name (name)
, m_total (0)
, m_failed (0)
: name_ (name)
{
}
@@ -150,21 +148,21 @@ public:
std::string const&
name() const
{
return m_name;
return name_;
}
/** Returns the total number of test conditions. */
std::size_t
total() const
{
return m_total;
return total_;
}
/** Returns the number of failures. */
std::size_t
failed() const
{
return m_failed;
return failed_;
}
/** Insert a set of testcase results. */
@@ -173,16 +171,16 @@ public:
insert (case_results&& r)
{
cont().emplace_back (std::move (r));
m_total += r.tests.total();
m_failed += r.tests.failed();
total_ += r.tests.total();
failed_ += r.tests.failed();
}
void
insert (case_results const& r)
{
cont().push_back (r);
m_total += r.tests.total();
m_failed += r.tests.failed();
total_ += r.tests.total();
failed_ += r.tests.failed();
}
/** @} */
};
@@ -196,14 +194,14 @@ class results
{
private:
std::size_t m_cases;
std::size_t m_total;
std::size_t m_failed;
std::size_t total_;
std::size_t failed_;
public:
results()
: m_cases (0)
, m_total (0)
, m_failed (0)
, total_ (0)
, failed_ (0)
{
}
@@ -218,14 +216,14 @@ public:
std::size_t
total() const
{
return m_total;
return total_;
}
/** Returns the number of failures. */
std::size_t
failed() const
{
return m_failed;
return failed_;
}
/** Insert a set of suite results. */
@@ -234,8 +232,8 @@ public:
insert (suite_results&& r)
{
m_cases += r.size();
m_total += r.total();
m_failed += r.failed();
total_ += r.total();
failed_ += r.failed();
cont().emplace_back (std::move (r));
}
@@ -243,8 +241,8 @@ public:
insert (suite_results const& r)
{
m_cases += r.size();
m_total += r.total();
m_failed += r.failed();
total_ += r.total();
failed_ += r.failed();
cont().push_back (r);
}
/** @} */

View File

@@ -21,10 +21,9 @@
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
#include <beast/unit_test/suite_info.h>
#include <beast/streams/abstract_ostream.h>
#include <cassert>
#include <mutex>
#include <string>
namespace beast {
@@ -47,22 +46,22 @@ private:
stream_t() = delete;
stream_t& operator= (stream_t const&) = delete;
stream_t (runner& owner)
: owner_ (owner)
{
}
template <class = void>
stream_t (runner& owner);
void
write (string_type const& s)
write (string_type const& s) override
{
owner_.log (s);
}
};
stream_t stream_;
bool default_;
bool failed_;
bool cond_;
std::string arg_;
bool default_ = false;
bool failed_ = false;
bool cond_ = false;
std::recursive_mutex mutex_;
public:
virtual ~runner() = default;
@@ -72,6 +71,25 @@ public:
template <class = void>
runner();
/** Set the argument string.
The argument string is available to suites and
allows for customization of the test. Each suite
defines its own syntax for the argumnet string.
The same argument is passed to all suites.
*/
void
arg (std::string const& s)
{
arg_ = s;
}
/** Returns the argument string. */
std::string const&
arg() const
{
return arg_;
}
/** Run the specified suite.
@return `true` if any conditions failed.
*/
@@ -201,12 +219,17 @@ private:
//------------------------------------------------------------------------------
template <class>
runner::stream_t::stream_t (runner& owner)
: owner_ (owner)
{
}
//------------------------------------------------------------------------------
template <class>
runner::runner()
: stream_ (*this)
, default_ (false)
, failed_ (false)
, cond_ (false)
{
}
@@ -272,6 +295,7 @@ template <class>
void
runner::testcase (std::string const& name)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
// Name may not be empty
assert (default_ || ! name.empty());
// Forgot to call pass or fail
@@ -287,6 +311,7 @@ template <class>
void
runner::pass()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (default_)
testcase ("");
on_pass();
@@ -297,6 +322,7 @@ template <class>
void
runner::fail (std::string const& reason)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (default_)
testcase ("");
on_fail (reason);
@@ -308,6 +334,7 @@ template <class>
void
runner::log (std::string const& s)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (default_)
testcase ("");
on_log (s);

View File

@@ -166,6 +166,13 @@ public:
bool
expect (Condition shouldBeTrue, std::string const& reason = "");
/** Return the argument associated with the runner. */
std::string const&
arg() const
{
return runner_->arg();
}
// DEPRECATED
// @return `true` if the test condition indicates success (a false value)
template <class Condition>
@@ -398,7 +405,7 @@ suite::fail (std::string const& reason)
// detail:
// This inserts the suite with the given manual flag
#define BEAST_DEFINE_TESTSUITE_INSERT(Class,Module,Library,manual) \
static beast::unit_test::detail::global_suite_instance <Class##_test> \
static beast::unit_test::detail::insert_suite <Class##_test> \
Library ## Module ## Class ## _test_instance ( \
#Class, #Module, #Library, manual);