From e47811bef2e919f80f6a12c497fb19d869c3f39e Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 10 May 2016 07:09:57 -0400 Subject: [PATCH] Refactor unit_test logging: The log member is changed to derive from std::ostream. A new class dstream is derived from std::ostream to support redirection to the Visual Studio Output Window if a debugger is attached. Obsolete classes abstract_ostream and its derived variants are removed. --- extras/beast/unit_test/abstract_ostream.hpp | 20 -- .../unit_test/basic_abstract_ostream.hpp | 85 ------ .../beast/unit_test/basic_scoped_ostream.hpp | 136 ---------- extras/beast/unit_test/basic_std_ostream.hpp | 60 ----- extras/beast/unit_test/debug_ostream.hpp | 78 ------ extras/beast/unit_test/dstream.hpp | 10 +- extras/beast/unit_test/global_suites.hpp | 25 +- extras/beast/unit_test/main.cpp | 36 +-- extras/beast/unit_test/print.hpp | 67 ----- extras/beast/unit_test/reporter.hpp | 176 ++++++------ extras/beast/unit_test/runner.hpp | 83 ++---- extras/beast/unit_test/suite.hpp | 251 ++++++++---------- extras/beast/unit_test/suite_info.hpp | 103 +++---- extras/beast/unit_test/suite_list.hpp | 22 +- test/http/parser_bench.cpp | 8 +- 15 files changed, 316 insertions(+), 844 deletions(-) delete mode 100644 extras/beast/unit_test/abstract_ostream.hpp delete mode 100644 extras/beast/unit_test/basic_abstract_ostream.hpp delete mode 100644 extras/beast/unit_test/basic_scoped_ostream.hpp delete mode 100644 extras/beast/unit_test/basic_std_ostream.hpp delete mode 100644 extras/beast/unit_test/debug_ostream.hpp delete mode 100644 extras/beast/unit_test/print.hpp diff --git a/extras/beast/unit_test/abstract_ostream.hpp b/extras/beast/unit_test/abstract_ostream.hpp deleted file mode 100644 index 8a41841a..00000000 --- a/extras/beast/unit_test/abstract_ostream.hpp +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_ABSTRACT_OSTREAM_HPP -#define BEAST_UNIT_TEST_ABSTRACT_OSTREAM_HPP - -#include - -namespace beast { - -/** An abstract ostream for `char`. */ -using abstract_ostream = basic_abstract_ostream ; - -} // beast - -#endif diff --git a/extras/beast/unit_test/basic_abstract_ostream.hpp b/extras/beast/unit_test/basic_abstract_ostream.hpp deleted file mode 100644 index 6a3a7222..00000000 --- a/extras/beast/unit_test/basic_abstract_ostream.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP -#define BEAST_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP - -#include -#include -#include -#include - -namespace beast { - -/** Abstraction for an output stream similar to std::basic_ostream. */ -template < - class CharT, - class Traits = std::char_traits -> -class basic_abstract_ostream -{ -public: - using string_type = std::basic_string ; - using scoped_stream_type = basic_scoped_ostream ; - - basic_abstract_ostream() = default; - - virtual - ~basic_abstract_ostream() = default; - - basic_abstract_ostream (basic_abstract_ostream const&) = default; - basic_abstract_ostream& operator= ( - basic_abstract_ostream const&) = default; - - /** Returns `true` if the stream is active. - Inactive streams do not produce output. - */ - /** @{ */ - virtual - bool - active() const - { - return true; - } - - explicit - operator bool() const - { - return active(); - } - /** @} */ - - /** Called to output each string. */ - virtual - void - write (string_type const& s) = 0; - - scoped_stream_type - operator<< (std::ostream& manip (std::ostream&)) - { - return scoped_stream_type (manip, - [this](string_type const& s) - { - this->write (s); - }); - } - - template - scoped_stream_type - operator<< (T const& t) - { - return scoped_stream_type (t, - [this](string_type const& s) - { - this->write (s); - }); - } -}; - -} // beast - -#endif diff --git a/extras/beast/unit_test/basic_scoped_ostream.hpp b/extras/beast/unit_test/basic_scoped_ostream.hpp deleted file mode 100644 index c8283a52..00000000 --- a/extras/beast/unit_test/basic_scoped_ostream.hpp +++ /dev/null @@ -1,136 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP -#define BEAST_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP - -#include -#include -#include - -// gcc libstd++ doesn't have move constructors for basic_ostringstream -// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316 -// -#ifndef BEAST_NO_STDLIB_STREAM_MOVE -# ifdef __GLIBCXX__ -# define BEAST_NO_STDLIB_STREAM_MOVE 1 -# else -# define BEAST_NO_STDLIB_STREAM_MOVE 0 -# endif -#endif - -namespace beast { - -template < - class CharT, - class Traits -> -class basic_abstract_ostream; - -/** Scoped output stream that forwards to a functor upon destruction. */ -template < - class CharT, - class Traits = std::char_traits , - class Allocator = std::allocator -> -class basic_scoped_ostream -{ -private: - using handler_t = std::function const&)>; - - using stream_type = std::basic_ostringstream < - CharT, Traits, Allocator>; - - handler_t m_handler; - -#if BEAST_NO_STDLIB_STREAM_MOVE - std::unique_ptr m_ss; - - stream_type& stream() - { - return *m_ss; - } - -#else - stream_type m_ss; - - stream_type& stream() - { - return m_ss; - } - -#endif - -public: - using string_type = std::basic_string ; - - // Disallow copy since that would duplicate the output - basic_scoped_ostream (basic_scoped_ostream const&) = delete; - basic_scoped_ostream& operator= (basic_scoped_ostream const) = delete; - - template - explicit basic_scoped_ostream (Handler&& handler) - : m_handler (std::forward (handler)) - #if BEAST_NO_STDLIB_STREAM_MOVE - , m_ss (new stream_type()) - #endif - { - } - - template - basic_scoped_ostream (T const& t, Handler&& handler) - : m_handler (std::forward (handler)) - #if BEAST_NO_STDLIB_STREAM_MOVE - , m_ss (new stream_type()) - #endif - { - stream() << t; - } - - basic_scoped_ostream (basic_abstract_ostream < - CharT, Traits>& ostream) - : m_handler ( - [&](string_type const& s) - { - ostream.write (s); - }) - { - } - - basic_scoped_ostream (basic_scoped_ostream&& other) - : m_handler (std::move (other.m_handler)) - , m_ss (std::move (other.m_ss)) - { - } - - ~basic_scoped_ostream() - { - auto const& s (stream().str()); - if (! s.empty()) - m_handler (s); - } - - basic_scoped_ostream& - operator<< (std::ostream& manip (std::ostream&)) - { - stream() << manip; - return *this; - } - - template - basic_scoped_ostream& - operator<< (T const& t) - { - stream() << t; - return *this; - } -}; - -} // beast - -#endif diff --git a/extras/beast/unit_test/basic_std_ostream.hpp b/extras/beast/unit_test/basic_std_ostream.hpp deleted file mode 100644 index 62b21966..00000000 --- a/extras/beast/unit_test/basic_std_ostream.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_BASIC_STD_OSTREAM_HPP -#define BEAST_UNIT_TEST_BASIC_STD_OSTREAM_HPP - -#include -#include - -namespace beast { - -/** Wraps an existing std::basic_ostream as an abstract_ostream. */ -template < - class CharT, - class Traits = std::char_traits -> -class basic_std_ostream - : public basic_abstract_ostream -{ -private: - using typename basic_abstract_ostream ::string_type; - - std::reference_wrapper m_stream; - -public: - explicit basic_std_ostream ( - std::basic_ostream & stream) - : m_stream (stream) - { - } - - void - write (string_type const& s) override - { - m_stream.get() << s << std::endl; - } -}; - -using std_ostream = basic_std_ostream ; - -//------------------------------------------------------------------------------ - -/** Returns a basic_std_ostream using template argument deduction. */ -template < - class CharT, - class Traits = std::char_traits -> -basic_std_ostream -make_std_ostream (std::basic_ostream & stream) -{ - return basic_std_ostream (stream); -} - -} // beast - -#endif diff --git a/extras/beast/unit_test/debug_ostream.hpp b/extras/beast/unit_test/debug_ostream.hpp deleted file mode 100644 index 60d19f8e..00000000 --- a/extras/beast/unit_test/debug_ostream.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_DEBUG_OSTREAM_HPP -#define BEAST_UNIT_TEST_DEBUG_OSTREAM_HPP - -#include -#include - -#ifdef _MSC_VER -# ifndef WIN32_LEAN_AND_MEAN // VC_EXTRALEAN -# define WIN32_LEAN_AND_MEAN -#include -# undef WIN32_LEAN_AND_MEAN -# else -#include -# endif -# ifdef min -# undef min -# endif -# ifdef max -# undef max -# endif -#endif - -namespace beast { - -#ifdef _MSC_VER -/** A basic_abstract_ostream that redirects output to an attached debugger. */ -class debug_ostream - : public abstract_ostream -{ -private: - bool m_debugger; - -public: - debug_ostream() - : m_debugger (IsDebuggerPresent() != FALSE) - { - // Note that the check for an attached debugger is made only - // during construction time, for efficiency. A stream created before - // the debugger is attached will not have output redirected. - } - - void - write (string_type const& s) override - { - if (m_debugger) - { - OutputDebugStringA ((s + "\n").c_str()); - return; - } - - std::cout << s << std::endl; - } -}; - -#else -class debug_ostream - : public abstract_ostream -{ -public: - void - write (string_type const& s) override - { - std::cout << s << std::endl; - } -}; - -#endif - -} // beast - -#endif diff --git a/extras/beast/unit_test/dstream.hpp b/extras/beast/unit_test/dstream.hpp index a42fd6f4..2bd8e590 100644 --- a/extras/beast/unit_test/dstream.hpp +++ b/extras/beast/unit_test/dstream.hpp @@ -73,8 +73,8 @@ public: int sync() override { - write(str().c_str()); - str(""); + write(this->str().c_str()); + this->str(""); return 0; } }; @@ -107,8 +107,8 @@ public: int sync() override { - write(str().c_str()); - str(""); + write(this->str().c_str()); + this->str(""); return 0; } }; @@ -130,7 +130,7 @@ class basic_dstream { public: basic_dstream() - : std::basic_ostream(&member) + : std::basic_ostream(&this->member) { } }; diff --git a/extras/beast/unit_test/global_suites.hpp b/extras/beast/unit_test/global_suites.hpp index c1f85252..f6e1ab2c 100644 --- a/extras/beast/unit_test/global_suites.hpp +++ b/extras/beast/unit_test/global_suites.hpp @@ -15,7 +15,8 @@ namespace unit_test { namespace detail { -template +/// Holds test suites registered during static initialization. +inline suite_list& global_suites() { @@ -23,26 +24,20 @@ global_suites() return s; } -template +template struct insert_suite { - template - insert_suite (char const* name, char const* module, - char const* library, bool manual); + insert_suite(char const* name, char const* module, + char const* library, bool manual) + { + global_suites().insert( + name, module, library, manual); + } }; -template -template -insert_suite::insert_suite (char const* name, - char const* module, char const* library, bool manual) -{ - global_suites().insert ( - name, module, library, manual); -} - } // detail -/** Holds suites registered during static initialization. */ +/// Holds test suites registered during static initialization. inline suite_list const& global_suites() diff --git a/extras/beast/unit_test/main.cpp b/extras/beast/unit_test/main.cpp index 8cdf803e..d461ea83 100644 --- a/extras/beast/unit_test/main.cpp +++ b/extras/beast/unit_test/main.cpp @@ -6,12 +6,13 @@ // #include +#include #include #include #include #include -#include #include +#include #include #include @@ -25,11 +26,10 @@ # endif #endif -#include - namespace beast { namespace unit_test { +static std::string prefix(suite_info const& s) { @@ -38,32 +38,34 @@ prefix(suite_info const& s) return " "; } -template +static void -print(Log& log, suite_list const& c) +print(std::ostream& os, suite_list const& c) { std::size_t manual = 0; for(auto const& s : c) { - log << - prefix (s) << - s.full_name(); + os << prefix (s) << s.full_name() << '\n'; if(s.manual()) ++manual; } - log << + os << amount(c.size(), "suite") << " total, " << - amount(manual, "manual suite") + amount(manual, "manual suite") << + '\n' ; } -template +// Print the list of suites +// Used with the --print command line option +static void -print(Log& log) +print(std::ostream& os) { - log << "------------------------------------------"; - print(log, global_suites()); - log << "------------------------------------------"; + os << "------------------------------------------\n"; + print(os, global_suites()); + os << "------------------------------------------" << + std::endl; } } // unit_test @@ -97,11 +99,11 @@ int main(int ac, char const* av[]) po::store(po::parse_command_line(ac, av, desc), vm); po::notify(vm); - beast::debug_ostream log; + dstream log; if(vm.count("help")) { - log << desc; + log << desc << std::endl; } else if(vm.count("print")) { diff --git a/extras/beast/unit_test/print.hpp b/extras/beast/unit_test/print.hpp deleted file mode 100644 index 0651e64b..00000000 --- a/extras/beast/unit_test/print.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_PRINT_H_INCLUDED -#define BEAST_UNIT_TEST_PRINT_H_INCLUDED - -#include -#include -#include -#include - -#include -#include - -namespace beast { -namespace unit_test { - -/** Write test results to the specified output stream. */ -/** @{ */ -template -void -print (results const& r, abstract_ostream& stream) -{ - for (auto const& s : r) - { - for (auto const& c : s) - { - stream << - s.name() << - (c.name().empty() ? "" : ("." + c.name())); - - std::size_t i (1); - for (auto const& t : c.tests) - { - if (! t.pass) - stream << - "#" << i << - " failed: " << t.reason; - ++i; - } - } - } - - stream << - amount (r.size(), "suite") << ", " << - amount (r.cases(), "case") << ", " << - amount (r.total(), "test") << " total, " << - amount (r.failed(), "failure") - ; -} - -template -void -print (results const& r, std::ostream& stream = std::cout) -{ - auto s (make_std_ostream (stream)); - print (r, s); -} - -} // unit_test -} // beast - -#endif diff --git a/extras/beast/unit_test/reporter.hpp b/extras/beast/unit_test/reporter.hpp index b5e27ef4..13e332b2 100644 --- a/extras/beast/unit_test/reporter.hpp +++ b/extras/beast/unit_test/reporter.hpp @@ -10,8 +10,6 @@ #include #include -#include -#include #include #include #include @@ -30,7 +28,7 @@ namespace detail { /** A simple test runner that writes everything to a stream in real time. The totals are output when the object is destroyed. */ -template +template class reporter : public runner { private: @@ -42,7 +40,11 @@ private: std::size_t total = 0; std::size_t failed = 0; - case_results (std::string const& name_ = ""); + explicit + case_results(std::string name_ = "") + : name(std::move(name_)) + { + } }; struct suite_results @@ -51,14 +53,16 @@ private: std::size_t cases = 0; std::size_t total = 0; std::size_t failed = 0; - typename clock_type::time_point start = - clock_type::now(); + typename clock_type::time_point start = clock_type::now(); explicit - suite_results (std::string const& name_ = ""); + suite_results(std::string const& name_ = "") + : name(std::move(name_)) + { + } void - add (case_results const& r); + add(case_results const& r); }; struct results @@ -76,35 +80,30 @@ private: std::size_t total = 0; std::size_t failed = 0; std::vector top; - typename clock_type::time_point start = - clock_type::now(); + typename clock_type::time_point start = clock_type::now(); void add (suite_results const& r); }; - boost::optional std_ostream_; - std::reference_wrapper stream_; + std::ostream& os_; results results_; suite_results suite_results_; case_results case_results_; public: - reporter (reporter const&) = delete; - reporter& operator= (reporter const&) = delete; + reporter(reporter const&) = delete; + reporter& operator=(reporter const&) = delete; ~reporter(); explicit - reporter (std::ostream& stream = std::cout); - - explicit - reporter (beast::abstract_ostream& stream); + reporter(std::ostream& os = std::cout); private: static std::string - fmtdur (typename clock_type::duration const& d); + fmtdur(typename clock_type::duration const& d); virtual void @@ -137,42 +136,27 @@ private: //------------------------------------------------------------------------------ -template -reporter<_>::case_results::case_results ( - std::string const& name_) - : name (name_) -{ -} - -template -reporter<_>::suite_results::suite_results ( - std::string const& name_) - : name (name_) -{ -} - -template +template void -reporter<_>::suite_results::add (case_results const& r) +reporter<_>:: +suite_results::add(case_results const& r) { ++cases; total += r.total; failed += r.failed; } -template +template void -reporter<_>::results::add ( - suite_results const& r) +reporter<_>:: +results::add(suite_results const& r) { ++suites; total += r.total; cases += r.cases; failed += r.failed; - - auto const elapsed = - clock_type::now() - r.start; - if (elapsed >= std::chrono::seconds(1)) + auto const elapsed = clock_type::now() - r.start; + if (elapsed >= std::chrono::seconds{1}) { auto const iter = std::lower_bound(top.begin(), top.end(), elapsed, @@ -196,50 +180,40 @@ reporter<_>::results::add ( //------------------------------------------------------------------------------ -template -reporter<_>::reporter ( - std::ostream& stream) - : std_ostream_ (std::ref (stream)) - , stream_ (*std_ostream_) +template +reporter<_>:: +reporter(std::ostream& os) + : os_(os) { } -template +template reporter<_>::~reporter() { - if (results_.top.size() > 0) + if(results_.top.size() > 0) { - stream_.get() << "Longest suite times:"; - for (auto const& i : results_.top) - stream_.get() << std::setw(8) << - fmtdur(i.second) << " " << i.first; + os_ << "Longest suite times:\n"; + for(auto const& i : results_.top) + os_ << std::setw(8) << + fmtdur(i.second) << " " << i.first << '\n'; } - auto const elapsed = - clock_type::now() - results_.start; - stream_.get() << + auto const elapsed = clock_type::now() - results_.start; + os_ << fmtdur(elapsed) << ", " << - amount (results_.suites, "suite") << ", " << - amount (results_.cases, "case") << ", " << - amount (results_.total, "test") << " total, " << - amount (results_.failed, "failure"); + amount{results_.suites, "suite"} << ", " << + amount{results_.cases, "case"} << ", " << + amount{results_.total, "test"} << " total, " << + amount{results_.failed, "failure"} << + std::endl; } -template -reporter<_>::reporter ( - abstract_ostream& stream) - : stream_ (stream) -{ -} - -template +template std::string -reporter<_>::fmtdur ( - typename clock_type::duration const& d) +reporter<_>::fmtdur(typename clock_type::duration const& d) { using namespace std::chrono; - auto const ms = - duration_cast(d); - if (ms < seconds(1)) + auto const ms = duration_cast(d); + if (ms < seconds{1}) return std::to_string(ms.count()) + "ms"; std::stringstream ss; ss << std::fixed << std::setprecision(1) << @@ -247,67 +221,67 @@ reporter<_>::fmtdur ( return ss.str(); } -template +template void -reporter<_>::on_suite_begin ( - suite_info const& info) +reporter<_>:: +on_suite_begin(suite_info const& info) { - suite_results_ = suite_results (info.full_name()); + suite_results_ = suite_results{info.full_name()}; } -template +template void reporter<_>::on_suite_end() { - results_.add (suite_results_); + results_.add(suite_results_); } -template +template void -reporter<_>::on_case_begin ( - std::string const& name) +reporter<_>:: +on_case_begin(std::string const& name) { case_results_ = case_results (name); - - stream_.get() << + os_ << suite_results_.name << (case_results_.name.empty() ? - "" : (" " + case_results_.name)); + "" : (" " + case_results_.name)) << std::endl; } -template +template void -reporter<_>::on_case_end() +reporter<_>:: +on_case_end() { - suite_results_.add (case_results_); + suite_results_.add(case_results_); } -template +template void -reporter<_>::on_pass() +reporter<_>:: +on_pass() { ++case_results_.total; } -template +template void -reporter<_>::on_fail ( - std::string const& reason) +reporter<_>:: +on_fail(std::string const& reason) { ++case_results_.failed; ++case_results_.total; - stream_.get() << - "#" << case_results_.total << - " failed" << - (reason.empty() ? "" : ": ") << reason; + os_ << + "#" << case_results_.total << " failed" << + (reason.empty() ? "" : ": ") << reason << std::endl; } -template +template void -reporter<_>::on_log ( - std::string const& s) +reporter<_>:: +on_log(std::string const& s) { - stream_.get() << s; + os_ << s; } } // detail diff --git a/extras/beast/unit_test/runner.hpp b/extras/beast/unit_test/runner.hpp index 1ff085df..03898565 100644 --- a/extras/beast/unit_test/runner.hpp +++ b/extras/beast/unit_test/runner.hpp @@ -9,9 +9,9 @@ #define BEAST_UNIT_TEST_RUNNER_H_INCLUDED #include -#include #include #include +#include #include namespace beast { @@ -23,28 +23,6 @@ namespace unit_test { */ class runner { -private: - // Reroutes log output to the runner - class stream_t : public abstract_ostream - { - private: - runner& owner_; - - public: - stream_t() = delete; - stream_t& operator= (stream_t const&) = delete; - - template - stream_t (runner& owner); - - void - write (string_type const& s) override - { - owner_.log (s); - } - }; - - stream_t stream_; std::string arg_; bool default_ = false; bool failed_ = false; @@ -52,21 +30,20 @@ private: std::recursive_mutex mutex_; public: + runner() = default; virtual ~runner() = default; - runner (runner const&) = default; - runner& operator= (runner const&) = default; - - template - runner(); + runner(runner const&) = delete; + runner& operator=(runner const&) = delete; /** 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(std::string const& s) { arg_ = s; } @@ -81,7 +58,7 @@ public: /** Run the specified suite. @return `true` if any conditions failed. */ - template + template bool run (suite_info const& s); @@ -124,69 +101,63 @@ public: bool run_each_if (SequenceContainer const& c, Pred pred = Pred{}); -private: +protected: // // Overrides // - /** Called when a new suite starts. */ + /// Called when a new suite starts. virtual void - on_suite_begin (suite_info const&) + on_suite_begin(suite_info const&) { } - /** Called when a suite ends. */ + /// Called when a suite ends. virtual void on_suite_end() { } - /** Called when a new case starts. */ + /// Called when a new case starts. virtual void - on_case_begin (std::string const&) + on_case_begin(std::string const&) { } - /** Called when a new case ends. */ + /// Called when a new case ends. virtual void on_case_end() { } - /** Called for each passing condition. */ + /// Called for each passing condition. virtual void - on_pass () + on_pass() { } - /** Called for each failing condition. */ + /// Called for each failing condition. virtual void - on_fail (std::string const&) + on_fail(std::string const&) { } - /** Called when a test logs output. */ + /// Called when a test logs output. virtual void - on_log (std::string const&) + on_log(std::string const&) { } private: friend class suite; - abstract_ostream& - stream() - { - return stream_; - } - // Start a new testcase. template void @@ -207,20 +178,6 @@ private: //------------------------------------------------------------------------------ -template -runner::stream_t::stream_t (runner& owner) - : owner_ (owner) -{ -} - -//------------------------------------------------------------------------------ - -template -runner::runner() - : stream_ (*this) -{ -} - template bool runner::run (suite_info const& s) diff --git a/extras/beast/unit_test/suite.hpp b/extras/beast/unit_test/suite.hpp index 6ffa6eb2..476c0b0a 100644 --- a/extras/beast/unit_test/suite.hpp +++ b/extras/beast/unit_test/suite.hpp @@ -9,15 +9,23 @@ #define BEAST_UNIT_TEST_SUITE_HPP #include -#include +#include #include +#include namespace beast { namespace unit_test { class thread; +enum abort_t +{ + no_abort_on_fail, + abort_on_fail +}; + /** A testsuite class. + Derived classes execute a series of testcases, where each testcase is a series of pass/fail tests. To provide a unit test using this class, derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a @@ -25,13 +33,6 @@ class thread; */ class suite { -public: - enum abort_t - { - no_abort_on_fail, - abort_on_fail - }; - private: bool abort_ = false; bool aborted_ = false; @@ -44,95 +45,100 @@ private: char const* what() const noexcept override { - return "suite aborted"; + return "test suite aborted"; } }; -public: - // Memberspace - class log_t + template + class log_buf + : public std::basic_stringbuf { - private: - friend class suite; - suite* suite_ = nullptr; + suite& suite_; public: - log_t () = default; + explicit + log_buf(suite& self) + : suite_(self) + { + } - template - abstract_ostream::scoped_stream_type - operator<< (T const& t); + ~log_buf() + { + sync(); + } - /** Returns the raw stream used for output. */ - abstract_ostream& - stream(); + int + sync() override + { + auto const& s = this->str(); + if(s.size() > 0) + suite_.runner_->on_log(s); + this->str(""); + return 0; + } + }; + + template< + class CharT, + class Traits = std::char_traits, + class Allocator = std::allocator + > + class log_os : public std::basic_ostream + { + log_buf buf_; + + public: + explicit + log_os(suite& self) + : std::basic_ostream(&buf_) + , buf_(self) + { + } }; -private: class scoped_testcase; - // Memberspace class testcase_t { - private: - friend class suite; - suite* suite_ = nullptr; + suite& suite_; std::stringstream ss_; public: - testcase_t() = default; + explicit + testcase_t(suite& self) + : suite_(self) + { + } /** Open a new testcase. - A testcase is a series of evaluated test conditions. A test suite - may have multiple test cases. A test is associated with the last - opened testcase. When the test first runs, a default unnamed - case is opened. Tests with only one case may omit the call - to testcase. - @param abort If `true`, the suite will be stopped on first failure. + + A testcase is a series of evaluated test conditions. A test + suite may have multiple test cases. A test is associated with + the last opened testcase. When the test first runs, a default + unnamed case is opened. Tests with only one case may omit the + call to testcase. + + @param abort Determines if suite continues running after a failure. */ void - operator() (std::string const& name, + operator()(std::string const& name, abort_t abort = no_abort_on_fail); - /** Stream style composition of testcase names. */ - /** @{ */ scoped_testcase - operator() (abort_t abort); + operator()(abort_t abort); template scoped_testcase - operator<< (T const& t); - /** @} */ + operator<<(T const& t); }; public: - /** Type for scoped stream logging. - To use this type, declare a local variable of the type - on the stack in derived class member function and construct - it from log.stream(); + /** Logging output stream. - @code - - scoped_stream ss (log.stream(); - - ss << "Hello" << std::endl; - ss << "world" << std::endl; - - @endcode - - Streams constructed in this fashion will not have the line - ending automatically appended. - - Thread safety: - - The scoped_stream may only be used by one thread. - Multiline output sent to the stream will be atomically - written to the underlying abstract_Ostream + Text sent to the log output stream will be forwarded to + the output stream associated with the runner. */ - using scoped_stream = abstract_ostream::scoped_stream_type; - - /** Memberspace for logging. */ - log_t log; + log_os log; /** Memberspace for declaring test cases. */ testcase_t testcase; @@ -145,6 +151,12 @@ public: return *p_this_suite(); } + suite() + : log(*this) + , testcase(*this) + { + } + /** Invokes the test using the specified runner. Data members are set up here instead of the constructor as a convenience to writing the derived class to avoid repetition of @@ -272,84 +284,51 @@ private: //------------------------------------------------------------------------------ -template -inline -abstract_ostream::scoped_stream_type -suite::log_t::operator<< (T const& t) -{ - return suite_->runner_->stream() << t; -} - -/** Returns the raw stream used for output. */ -inline -abstract_ostream& -suite::log_t::stream() -{ - return suite_->runner_->stream(); -} - -//------------------------------------------------------------------------------ - // Helper for streaming testcase names class suite::scoped_testcase { private: - suite* suite_; - std::stringstream* ss_; + suite& suite_; + std::stringstream& ss_; public: - ~scoped_testcase(); + scoped_testcase& operator=(scoped_testcase const&) = delete; - scoped_testcase (suite* s, std::stringstream* ss); + ~scoped_testcase() + { + auto const& name = ss_.str(); + if(! name.empty()) + suite_.runner_->testcase (name); + } - template - scoped_testcase (suite* s, std::stringstream* ss, T const& t); + scoped_testcase(suite& self, std::stringstream& ss) + : suite_(self) + , ss_(ss) + { + ss_.clear(); + ss_.str({}); + } - scoped_testcase& operator= (scoped_testcase const&) = delete; + template + scoped_testcase(suite& self, + std::stringstream& ss, T const& t) + : suite_(self) + , ss_(ss) + { + ss_.clear(); + ss_.str({}); + ss_ << t; + } - template + template scoped_testcase& - operator<< (T const& t); + operator<<(T const& t) + { + ss_ << t; + return *this; + } }; -inline -suite::scoped_testcase::~scoped_testcase() -{ - auto const& name (ss_->str()); - if (! name.empty()) - suite_->runner_->testcase (name); -} - -inline -suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss) - : suite_ (s) - , ss_ (ss) -{ - ss_->clear(); - ss_->str({}); - -} - -template -inline -suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss, T const& t) - : suite_ (s) - , ss_ (ss) -{ - ss_->clear(); - ss_->str({}); - *ss_ << t; -} - -template -inline -suite::scoped_testcase& -suite::scoped_testcase::operator<< (T const& t) -{ - *ss_ << t; - return *this; -} - //------------------------------------------------------------------------------ inline @@ -357,16 +336,16 @@ void suite::testcase_t::operator() (std::string const& name, abort_t abort) { - suite_->abort_ = abort == abort_on_fail; - suite_->runner_->testcase (name); + suite_.abort_ = abort == abort_on_fail; + suite_.runner_->testcase (name); } inline suite::scoped_testcase suite::testcase_t::operator() (abort_t abort) { - suite_->abort_ = abort == abort_on_fail; - return { suite_, &ss_ }; + suite_.abort_ = abort == abort_on_fail; + return { suite_, ss_ }; } template @@ -374,7 +353,7 @@ inline suite::scoped_testcase suite::testcase_t::operator<< (T const& t) { - return { suite_, &ss_, t }; + return { suite_, ss_, t }; } //------------------------------------------------------------------------------ @@ -511,8 +490,6 @@ void suite::run (runner& r) { runner_ = &r; - log.suite_ = this; - testcase.suite_ = this; try { diff --git a/extras/beast/unit_test/suite_info.hpp b/extras/beast/unit_test/suite_info.hpp index 530ac008..428d81ee 100644 --- a/extras/beast/unit_test/suite_info.hpp +++ b/extras/beast/unit_test/suite_info.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP #define BEAST_UNIT_TEST_SUITE_INFO_HPP +#include #include #include #include @@ -20,19 +21,28 @@ class runner; /** Associates a unit test type with metadata. */ class suite_info { -private: - using run_type = std::function ; + using run_type = std::function; std::string name_; std::string module_; std::string library_; - bool m_manual; - run_type m_run; + bool manual_; + run_type run_; public: - template - suite_info (std::string const& name, std::string const& module, - std::string const& library, bool manual, run_type run); + suite_info( + std::string name, + std::string module, + std::string library, + bool manual, + run_type run) + : name_(std::move(name)) + , module_(std::move(module)) + , library_(std::move(library)) + , manual_(manual) + , run_(std::move(run)) + { + } std::string const& name() const @@ -52,61 +62,58 @@ public: return library_; } - /** Returns `true` if this suite only runs manually. */ + /// Returns `true` if this suite only runs manually. bool manual() const { - return m_manual; + return manual_; } - /** Return the canonical suite name as a string. */ - template + /// Return the canonical suite name as a string. std::string - full_name() const; - - /** Run a new instance of the associated test suite. */ - void - run (runner& r) const + full_name() const { - m_run (r); + return library_ + "." + module_ + "." + name_; + } + + /// Run a new instance of the associated test suite. + void + run(runner& r) const + { + run_ (r); + } + + friend + bool + operator<(suite_info const& lhs, suite_info const& rhs) + { + return + std::tie(lhs.library_, lhs.module_, lhs.name_) < + std::tie(rhs.library_, rhs.module_, rhs.name_); } }; //------------------------------------------------------------------------------ -template -suite_info::suite_info (std::string const& name, std::string const& module, - std::string const& library, bool manual, run_type run) - : name_ (name) - , module_ (module) - , library_ (library) - , m_manual (manual) - , m_run (std::move (run)) -{ -} - -template -std::string -suite_info::full_name() const -{ - return library_ + "." + module_ + "." + name_; -} - -inline -bool -operator< (suite_info const& lhs, suite_info const& rhs) -{ - return lhs.full_name() < rhs.full_name(); -} - -/** Convenience for producing suite_info for a given test type. */ -template +/// Convenience for producing suite_info for a given test type. +template suite_info -make_suite_info (std::string const& name, std::string const& module, - std::string const& library, bool manual) +make_suite_info( + std::string name, + std::string module, + std::string library, + bool manual) { - return suite_info(name, module, library, manual, - [](runner& r) { return Suite{}(r); }); + return suite_info( + std::move(name), + std::move(module), + std::move(library), + manual, + [](runner& r) + { + Suite{}(r); + } + ); } } // unit_test diff --git a/extras/beast/unit_test/suite_list.hpp b/extras/beast/unit_test/suite_list.hpp index 5feacf26..d8f62c5d 100644 --- a/extras/beast/unit_test/suite_list.hpp +++ b/extras/beast/unit_test/suite_list.hpp @@ -18,23 +18,27 @@ namespace beast { namespace unit_test { -/** A container of test suites. */ +/// A container of test suites. class suite_list : public detail::const_container > { private: #ifndef NDEBUG - std::unordered_set names_; - std::unordered_set classes_; + std::unordered_set names_; + std::unordered_set classes_; #endif public: /** Insert a suite into the set. + The suite must not already exist. */ template void - insert (char const* name, char const* module, char const* library, + insert( + char const* name, + char const* module, + char const* library, bool manual); }; @@ -42,7 +46,10 @@ public: template void -suite_list::insert (char const* name, char const* module, char const* library, +suite_list::insert( + char const* name, + char const* module, + char const* library, bool manual) { #ifndef NDEBUG @@ -59,9 +66,8 @@ suite_list::insert (char const* name, char const* module, char const* library, assert (result.second); // Duplicate type } #endif - - cont().emplace (std::move (make_suite_info ( - name, module, library, manual))); + cont().emplace(make_suite_info( + name, module, library, manual)); } } // unit_test diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index 086d96ed..aacda98d 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -85,7 +85,7 @@ public: { using namespace std::chrono; using clock_type = std::chrono::high_resolution_clock; - log << name; + log << name << std::endl; for(std::size_t trial = 1; trial <= repeat; ++trial) { auto const t0 = clock_type::now(); @@ -93,7 +93,7 @@ public: auto const elapsed = clock_type::now() - t0; log << "Trial " << trial << ": " << - duration_cast(elapsed).count() << " ms"; + duration_cast(elapsed).count() << " ms" << std::endl; } } @@ -109,10 +109,10 @@ public: static std::size_t constexpr Repeat = 50; log << "sizeof(request parser) == " << - sizeof(basic_parser_v1>); + sizeof(basic_parser_v1>) << '\n'; log << "sizeof(response parser) == " << - sizeof(basic_parser_v1>); + sizeof(basic_parser_v1>)<< '\n'; testcase << "Parser speed test, " << ((Repeat * size_ + 512) / 1024) << "KB in " <<