summaryrefslogtreecommitdiff
path: root/boost/beast/_experimental/unit_test/reporter.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/_experimental/unit_test/reporter.hpp')
-rw-r--r--boost/beast/_experimental/unit_test/reporter.hpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/boost/beast/_experimental/unit_test/reporter.hpp b/boost/beast/_experimental/unit_test/reporter.hpp
new file mode 100644
index 0000000000..12a94f88dc
--- /dev/null
+++ b/boost/beast/_experimental/unit_test/reporter.hpp
@@ -0,0 +1,292 @@
+//
+// Copyright (c) 2016-2019 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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_UNIT_TEST_REPORTER_HPP
+#define BOOST_BEAST_UNIT_TEST_REPORTER_HPP
+
+#include <boost/beast/_experimental/unit_test/amount.hpp>
+#include <boost/beast/_experimental/unit_test/recorder.hpp>
+#include <algorithm>
+#include <chrono>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace unit_test {
+
+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<class = void>
+class reporter : public runner
+{
+private:
+ using clock_type = std::chrono::steady_clock;
+
+ struct case_results
+ {
+ std::string name;
+ std::size_t total = 0;
+ std::size_t failed = 0;
+
+ explicit
+ case_results(std::string name_ = "")
+ : name(std::move(name_))
+ {
+ }
+ };
+
+ struct suite_results
+ {
+ std::string name;
+ std::size_t cases = 0;
+ std::size_t total = 0;
+ std::size_t failed = 0;
+ typename clock_type::time_point start = clock_type::now();
+
+ explicit
+ suite_results(std::string name_ = "")
+ : name(std::move(name_))
+ {
+ }
+
+ void
+ add(case_results const& r);
+ };
+
+ struct results
+ {
+ using run_time = std::pair<std::string,
+ typename clock_type::duration>;
+
+ enum
+ {
+ max_top = 10
+ };
+
+ std::size_t suites = 0;
+ std::size_t cases = 0;
+ std::size_t total = 0;
+ std::size_t failed = 0;
+ std::vector<run_time> top;
+ typename clock_type::time_point start = clock_type::now();
+
+ void
+ add(suite_results const& r);
+ };
+
+ std::ostream& os_;
+ results results_;
+ suite_results suite_results_;
+ case_results case_results_;
+
+public:
+ reporter(reporter const&) = delete;
+ reporter& operator=(reporter const&) = delete;
+
+ ~reporter();
+
+ explicit
+ reporter(std::ostream& os = std::cout);
+
+private:
+ static
+ std::string
+ fmtdur(typename clock_type::duration const& d);
+
+ virtual
+ void
+ on_suite_begin(suite_info const& info) override;
+
+ virtual
+ void
+ on_suite_end() override;
+
+ virtual
+ void
+ on_case_begin(std::string const& name) override;
+
+ virtual
+ void
+ on_case_end() override;
+
+ virtual
+ void
+ on_pass() override;
+
+ virtual
+ void
+ on_fail(std::string const& reason) override;
+
+ virtual
+ void
+ on_log(std::string const& s) override;
+};
+
+//------------------------------------------------------------------------------
+
+template<class _>
+void
+reporter<_>::
+suite_results::add(case_results const& r)
+{
+ ++cases;
+ total += r.total;
+ failed += r.failed;
+}
+
+template<class _>
+void
+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 iter = std::lower_bound(top.begin(),
+ top.end(), elapsed,
+ [](run_time const& t1,
+ typename clock_type::duration const& t2)
+ {
+ return t1.second > t2;
+ });
+ if(iter != top.end())
+ {
+ top.emplace(iter, r.name, elapsed);
+ if(top.size() > max_top)
+ top.resize(max_top);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+template<class _>
+reporter<_>::
+reporter(std::ostream& os)
+ : os_(os)
+{
+}
+
+template<class _>
+reporter<_>::~reporter()
+{
+ if(results_.top.size() > 0)
+ {
+ 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;
+ os_ <<
+ fmtdur(elapsed) << ", " <<
+ amount{results_.suites, "suite"} << ", " <<
+ amount{results_.cases, "case"} << ", " <<
+ amount{results_.total, "test"} << " total, " <<
+ amount{results_.failed, "failure"} <<
+ std::endl;
+}
+
+template<class _>
+std::string
+reporter<_>::fmtdur(typename clock_type::duration const& d)
+{
+ using namespace std::chrono;
+ auto const ms = duration_cast<milliseconds>(d);
+ if(ms < seconds{1})
+ return std::to_string(ms.count()) + "ms";
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(1) <<
+ (ms.count()/1000.) << "s";
+ return ss.str();
+}
+
+template<class _>
+void
+reporter<_>::
+on_suite_begin(suite_info const& info)
+{
+ suite_results_ = suite_results{info.full_name()};
+}
+
+template<class _>
+void
+reporter<_>::on_suite_end()
+{
+ results_.add(suite_results_);
+}
+
+template<class _>
+void
+reporter<_>::
+on_case_begin(std::string const& name)
+{
+ case_results_ = case_results(name);
+ os_ << suite_results_.name <<
+ (case_results_.name.empty() ? "" :
+ (" " + case_results_.name)) << std::endl;
+}
+
+template<class _>
+void
+reporter<_>::
+on_case_end()
+{
+ suite_results_.add(case_results_);
+}
+
+template<class _>
+void
+reporter<_>::
+on_pass()
+{
+ ++case_results_.total;
+}
+
+template<class _>
+void
+reporter<_>::
+on_fail(std::string const& reason)
+{
+ ++case_results_.failed;
+ ++case_results_.total;
+ os_ <<
+ "#" << case_results_.total << " failed" <<
+ (reason.empty() ? "" : ": ") << reason << std::endl;
+}
+
+template<class _>
+void
+reporter<_>::
+on_log(std::string const& s)
+{
+ os_ << s;
+}
+
+} // detail
+
+using reporter = detail::reporter<>;
+
+} // unit_test
+} // beast
+} // boost
+
+#endif