File indexing completed on 2025-01-19 09:25:01
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_UNIT_TEST_REPORTER_HPP
0011 #define BOOST_BEAST_UNIT_TEST_REPORTER_HPP
0012
0013 #include <boost/beast/_experimental/unit_test/amount.hpp>
0014 #include <boost/beast/_experimental/unit_test/recorder.hpp>
0015 #include <algorithm>
0016 #include <chrono>
0017 #include <functional>
0018 #include <iomanip>
0019 #include <iostream>
0020 #include <sstream>
0021 #include <string>
0022 #include <utility>
0023
0024 namespace boost {
0025 namespace beast {
0026 namespace unit_test {
0027
0028 namespace detail {
0029
0030
0031
0032
0033 template<class = void>
0034 class reporter : public runner
0035 {
0036 private:
0037 using clock_type = std::chrono::steady_clock;
0038
0039 struct case_results
0040 {
0041 std::string name;
0042 std::size_t total = 0;
0043 std::size_t failed = 0;
0044
0045 explicit
0046 case_results(std::string name_ = "")
0047 : name(std::move(name_))
0048 {
0049 }
0050 };
0051
0052 struct suite_results
0053 {
0054 std::string name;
0055 std::size_t cases = 0;
0056 std::size_t total = 0;
0057 std::size_t failed = 0;
0058 typename clock_type::time_point start = clock_type::now();
0059
0060 explicit
0061 suite_results(std::string name_ = "")
0062 : name(std::move(name_))
0063 {
0064 }
0065
0066 void
0067 add(case_results const& r);
0068 };
0069
0070 struct results
0071 {
0072 using run_time = std::pair<std::string,
0073 typename clock_type::duration>;
0074
0075 enum
0076 {
0077 max_top = 10
0078 };
0079
0080 std::size_t suites = 0;
0081 std::size_t cases = 0;
0082 std::size_t total = 0;
0083 std::size_t failed = 0;
0084 std::vector<run_time> top;
0085 typename clock_type::time_point start = clock_type::now();
0086
0087 void
0088 add(suite_results const& r);
0089 };
0090
0091 std::ostream& os_;
0092 results results_;
0093 suite_results suite_results_;
0094 case_results case_results_;
0095
0096 public:
0097 reporter(reporter const&) = delete;
0098 reporter& operator=(reporter const&) = delete;
0099
0100 ~reporter();
0101
0102 explicit
0103 reporter(std::ostream& os = std::cout);
0104
0105 private:
0106 static
0107 std::string
0108 fmtdur(typename clock_type::duration const& d);
0109
0110 virtual
0111 void
0112 on_suite_begin(suite_info const& info) override;
0113
0114 virtual
0115 void
0116 on_suite_end() override;
0117
0118 virtual
0119 void
0120 on_case_begin(std::string const& name) override;
0121
0122 virtual
0123 void
0124 on_case_end() override;
0125
0126 virtual
0127 void
0128 on_pass() override;
0129
0130 virtual
0131 void
0132 on_fail(std::string const& reason) override;
0133
0134 virtual
0135 void
0136 on_log(std::string const& s) override;
0137 };
0138
0139
0140
0141 template<class _>
0142 void
0143 reporter<_>::
0144 suite_results::add(case_results const& r)
0145 {
0146 ++cases;
0147 total += r.total;
0148 failed += r.failed;
0149 }
0150
0151 template<class _>
0152 void
0153 reporter<_>::
0154 results::add(suite_results const& r)
0155 {
0156 ++suites;
0157 total += r.total;
0158 cases += r.cases;
0159 failed += r.failed;
0160 auto const elapsed = clock_type::now() - r.start;
0161 if(elapsed >= std::chrono::seconds{1})
0162 {
0163 auto const iter = std::lower_bound(top.begin(),
0164 top.end(), elapsed,
0165 [](run_time const& t1,
0166 typename clock_type::duration const& t2)
0167 {
0168 return t1.second > t2;
0169 });
0170 if(iter != top.end())
0171 {
0172 top.emplace(iter, r.name, elapsed);
0173 if(top.size() > max_top)
0174 top.resize(max_top);
0175 }
0176 }
0177 }
0178
0179
0180
0181 template<class _>
0182 reporter<_>::
0183 reporter(std::ostream& os)
0184 : os_(os)
0185 {
0186 }
0187
0188 template<class _>
0189 reporter<_>::~reporter()
0190 {
0191 if(results_.top.size() > 0)
0192 {
0193 os_ << "Longest suite times:\n";
0194 for(auto const& i : results_.top)
0195 os_ << std::setw(8) <<
0196 fmtdur(i.second) << " " << i.first << '\n';
0197 }
0198 auto const elapsed = clock_type::now() - results_.start;
0199 os_ <<
0200 fmtdur(elapsed) << ", " <<
0201 amount{results_.suites, "suite"} << ", " <<
0202 amount{results_.cases, "case"} << ", " <<
0203 amount{results_.total, "test"} << " total, " <<
0204 amount{results_.failed, "failure"} <<
0205 std::endl;
0206 }
0207
0208 template<class _>
0209 std::string
0210 reporter<_>::fmtdur(typename clock_type::duration const& d)
0211 {
0212 using namespace std::chrono;
0213 auto const ms = duration_cast<milliseconds>(d);
0214 if(ms < seconds{1})
0215 return std::to_string(ms.count()) + "ms";
0216 std::stringstream ss;
0217 ss << std::fixed << std::setprecision(1) <<
0218 (ms.count()/1000.) << "s";
0219 return ss.str();
0220 }
0221
0222 template<class _>
0223 void
0224 reporter<_>::
0225 on_suite_begin(suite_info const& info)
0226 {
0227 suite_results_ = suite_results{info.full_name()};
0228 }
0229
0230 template<class _>
0231 void
0232 reporter<_>::on_suite_end()
0233 {
0234 results_.add(suite_results_);
0235 }
0236
0237 template<class _>
0238 void
0239 reporter<_>::
0240 on_case_begin(std::string const& name)
0241 {
0242 case_results_ = case_results(name);
0243 os_ << suite_results_.name <<
0244 (case_results_.name.empty() ? "" :
0245 (" " + case_results_.name)) << std::endl;
0246 }
0247
0248 template<class _>
0249 void
0250 reporter<_>::
0251 on_case_end()
0252 {
0253 suite_results_.add(case_results_);
0254 }
0255
0256 template<class _>
0257 void
0258 reporter<_>::
0259 on_pass()
0260 {
0261 ++case_results_.total;
0262 }
0263
0264 template<class _>
0265 void
0266 reporter<_>::
0267 on_fail(std::string const& reason)
0268 {
0269 ++case_results_.failed;
0270 ++case_results_.total;
0271 os_ <<
0272 "#" << case_results_.total << " failed" <<
0273 (reason.empty() ? "" : ": ") << reason << std::endl;
0274 }
0275
0276 template<class _>
0277 void
0278 reporter<_>::
0279 on_log(std::string const& s)
0280 {
0281 os_ << s;
0282 }
0283
0284 }
0285
0286 using reporter = detail::reporter<>;
0287
0288 }
0289 }
0290 }
0291
0292 #endif