2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_UNIT_TEST_REPORTER_HPP
11 #define BOOST_BEAST_UNIT_TEST_REPORTER_HPP
13 #include <boost/beast/unit_test/amount.hpp>
14 #include <boost/beast/unit_test/recorder.hpp>
30 /** A simple test runner that writes everything to a stream in real time.
31 The totals are output when the object is destroyed.
33 template<class = void>
34 class reporter : public runner
37 using clock_type = std::chrono::steady_clock;
42 std::size_t total = 0;
43 std::size_t failed = 0;
46 case_results(std::string name_ = "")
47 : name(std::move(name_))
55 std::size_t cases = 0;
56 std::size_t total = 0;
57 std::size_t failed = 0;
58 typename clock_type::time_point start = clock_type::now();
61 suite_results(std::string name_ = "")
62 : name(std::move(name_))
67 add(case_results const& r);
72 using run_time = std::pair<std::string,
73 typename clock_type::duration>;
80 std::size_t suites = 0;
81 std::size_t cases = 0;
82 std::size_t total = 0;
83 std::size_t failed = 0;
84 std::vector<run_time> top;
85 typename clock_type::time_point start = clock_type::now();
88 add(suite_results const& r);
93 suite_results suite_results_;
94 case_results case_results_;
97 reporter(reporter const&) = delete;
98 reporter& operator=(reporter const&) = delete;
103 reporter(std::ostream& os = std::cout);
108 fmtdur(typename clock_type::duration const& d);
112 on_suite_begin(suite_info const& info) override;
116 on_suite_end() override;
120 on_case_begin(std::string const& name) override;
124 on_case_end() override;
132 on_fail(std::string const& reason) override;
136 on_log(std::string const& s) override;
139 //------------------------------------------------------------------------------
144 suite_results::add(case_results const& r)
154 results::add(suite_results const& r)
160 auto const elapsed = clock_type::now() - r.start;
161 if(elapsed >= std::chrono::seconds{1})
163 auto const iter = std::lower_bound(top.begin(),
165 [](run_time const& t1,
166 typename clock_type::duration const& t2)
168 return t1.second > t2;
170 if(iter != top.end())
172 top.emplace(iter, r.name, elapsed);
173 if(top.size() > max_top)
179 //------------------------------------------------------------------------------
183 reporter(std::ostream& os)
189 reporter<_>::~reporter()
191 if(results_.top.size() > 0)
193 os_ << "Longest suite times:\n";
194 for(auto const& i : results_.top)
195 os_ << std::setw(8) <<
196 fmtdur(i.second) << " " << i.first << '\n';
198 auto const elapsed = clock_type::now() - results_.start;
200 fmtdur(elapsed) << ", " <<
201 amount{results_.suites, "suite"} << ", " <<
202 amount{results_.cases, "case"} << ", " <<
203 amount{results_.total, "test"} << " total, " <<
204 amount{results_.failed, "failure"} <<
210 reporter<_>::fmtdur(typename clock_type::duration const& d)
212 using namespace std::chrono;
213 auto const ms = duration_cast<milliseconds>(d);
215 return std::to_string(ms.count()) + "ms";
216 std::stringstream ss;
217 ss << std::fixed << std::setprecision(1) <<
218 (ms.count()/1000.) << "s";
225 on_suite_begin(suite_info const& info)
227 suite_results_ = suite_results{info.full_name()};
232 reporter<_>::on_suite_end()
234 results_.add(suite_results_);
240 on_case_begin(std::string const& name)
242 case_results_ = case_results(name);
243 os_ << suite_results_.name <<
244 (case_results_.name.empty() ? "" :
245 (" " + case_results_.name)) << std::endl;
253 suite_results_.add(case_results_);
261 ++case_results_.total;
267 on_fail(std::string const& reason)
269 ++case_results_.failed;
270 ++case_results_.total;
272 "#" << case_results_.total << " failed" <<
273 (reason.empty() ? "" : ": ") << reason << std::endl;
279 on_log(std::string const& s)
286 using reporter = detail::reporter<>;