@@ -83,6 +83,7 @@ export import std;
8383#include < utility>
8484#include < variant>
8585#include < vector>
86+ #include < fstream>
8687#if __has_include(<unistd.h>) and __has_include(<sys/wait.h>)
8788#include < sys/wait.h>
8889#include < unistd.h>
@@ -1840,11 +1841,17 @@ class reporter_junit {
18401841 auto on (events::summary) -> void {
18411842 std::cout.flush ();
18421843 std::cout.rdbuf (cout_save);
1844+ std::ofstream maybe_of;
1845+ if (detail::cfg::output_filename != " " ) { maybe_of = std::ofstream (detail::cfg::output_filename); }
1846+
18431847 if (report_type_ == JUNIT) {
1844- print_junit_summary ();
1848+ print_junit_summary (detail::cfg::output_filename != " " ? maybe_of : std::cout );
18451849 return ;
18461850 }
1847- print_console_summary ();
1851+ print_console_summary (
1852+ detail::cfg::output_filename != " " ? maybe_of : std::cout,
1853+ detail::cfg::output_filename != " " ? maybe_of : std::cerr
1854+ );
18481855 }
18491856
18501857 protected:
@@ -1860,10 +1867,10 @@ class reporter_junit {
18601867 }
18611868 }
18621869
1863- void print_console_summary () {
1870+ void print_console_summary (std::ostream &out_stream, std::ostream &err_stream ) {
18641871 for (const auto & [suite_name, suite_result] : results_) {
18651872 if (suite_result.fails ) {
1866- std::cerr
1873+ err_stream
18671874 << " \n ========================================================"
18681875 " =======================\n "
18691876 << " Suite " << suite_name //
@@ -1875,7 +1882,7 @@ class reporter_junit {
18751882 << color_.none << ' \n ' ;
18761883 std::cerr << std::endl;
18771884 } else {
1878- std::cout << color_.pass << " Suite '" << suite_name
1885+ out_stream << color_.pass << " Suite '" << suite_name
18791886 << " ': all tests passed" << color_.none << " ("
18801887 << suite_result.assertions << " asserts in "
18811888 << suite_result.n_tests << " tests)\n " ;
@@ -1889,58 +1896,77 @@ class reporter_junit {
18891896 }
18901897 }
18911898
1892- void print_junit_summary () {
1893- // mock junit output:
1894- std::cout << " <?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n " ;
1895- for (const auto & [suite_name, suite_result] : results_) {
1896- std::cout << " <testsuites" ;
1897- std::cout << " classname=\" " << detail::cfg::executable_name << ' \" ' ;
1898- std::cout << " name=\" " << suite_name << ' \" ' ;
1899- std::cout << " tests=\" " << suite_result.n_tests << ' \" ' ;
1900- std::cout << " errors=\" " << suite_result.fails << ' \" ' ;
1901- std::cout << " failures=\" " << suite_result.fails << ' \" ' ;
1902- std::cout << " skipped=\" " << suite_result.skipped << ' \" ' ;
1899+ void print_junit_summary (std::ostream &stream) {
1900+ // aggregate results
1901+ size_t n_tests=0 , n_fails=0 ;
1902+ double total_time = 0.0 ;
1903+ auto suite_time = [](auto const & suite_result) {
19031904 std::int64_t time_ms =
19041905 std::chrono::duration_cast<std::chrono::milliseconds>(
19051906 suite_result.run_stop - suite_result.run_start )
19061907 .count ();
1907- std::cout << " time= \" " << ( static_cast <double >(time_ms) / 1000.0 )
1908- << ' \" ' ;
1909- std::cout << " version= \" " << BOOST_UT_VERSION << " \" /> \n " ;
1910- print_result (suite_name, " " , suite_result) ;
1911- std::cout << " </testsuites> \n " ;
1912- std::cout. flush ( );
1908+ return static_cast <double >(time_ms) / 1000.0 ;
1909+ } ;
1910+ for ( const auto & [suite_name, suite_result] : results_) {
1911+ n_tests += suite_result. assertions ;
1912+ n_fails += suite_result. fails ;
1913+ total_time += suite_time (suite_result );
19131914 }
1914- }
1915- void print_result (const std::string& suite_name, std::string indent,
1915+
1916+ // mock junit output:
1917+ stream << " <?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n " ;
1918+ stream << " <testsuites" ;
1919+ stream << " name=\" all\" " ;
1920+ stream << " tests=\" " << n_tests << ' \" ' ;
1921+ stream << " failures=\" " << n_fails << ' \" ' ;
1922+ stream << " time=\" " << total_time << ' \" ' ;
1923+ stream << " >\n " ;
1924+
1925+ for (const auto & [suite_name, suite_result] : results_) {
1926+ stream << " <testsuite" ;
1927+ stream << " classname=\" " << detail::cfg::executable_name << ' \" ' ;
1928+ stream << " name=\" " << suite_name << ' \" ' ;
1929+ stream << " tests=\" " << suite_result.assertions << ' \" ' ;
1930+ stream << " errors=\" " << suite_result.fails << ' \" ' ;
1931+ stream << " failures=\" " << suite_result.fails << ' \" ' ;
1932+ stream << " skipped=\" " << suite_result.skipped << ' \" ' ;
1933+ stream << " time=\" " << suite_time (suite_result) << ' \" ' ;
1934+ stream << " version=\" " << BOOST_UT_VERSION << " \" >\n " ;
1935+ print_result (stream, suite_name, " " , suite_result);
1936+ stream << " </testsuite>\n " ;
1937+ stream.flush ();
1938+ }
1939+ stream << " </testsuites>" ;
1940+ }
1941+ void print_result (std::ostream &stream, const std::string& suite_name, std::string indent,
19161942 const test_result& parent) {
19171943 for (const auto & [name, result] : *parent.nested_tests ) {
1918- std::cout << indent;
1919- std::cout << " <testcase classname=\" " << result.suite_name << ' \" ' ;
1920- std::cout << " name=\" " << name << ' \" ' ;
1921- std::cout << " tests=\" " << result.assertions << ' \" ' ;
1922- std::cout << " errors=\" " << result.fails << ' \" ' ;
1923- std::cout << " failures=\" " << result.fails << ' \" ' ;
1924- std::cout << " skipped=\" " << result.skipped << ' \" ' ;
1944+ stream << indent;
1945+ stream << " <testcase classname=\" " << result.suite_name << ' \" ' ;
1946+ stream << " name=\" " << name << ' \" ' ;
1947+ stream << " tests=\" " << result.assertions << ' \" ' ;
1948+ stream << " errors=\" " << result.fails << ' \" ' ;
1949+ stream << " failures=\" " << result.fails << ' \" ' ;
1950+ stream << " skipped=\" " << result.skipped << ' \" ' ;
19251951 std::int64_t time_ms =
19261952 std::chrono::duration_cast<std::chrono::milliseconds>(
19271953 result.run_stop - result.run_start )
19281954 .count ();
1929- std::cout << " time=\" " << (static_cast <double >(time_ms) / 1000.0 )
1955+ stream << " time=\" " << (static_cast <double >(time_ms) / 1000.0 )
19301956 << " \" " ;
1931- std::cout << " status=\" " << result.status << ' \" ' ;
1957+ stream << " status=\" " << result.status << ' \" ' ;
19321958 if (result.report_string .empty () && result.nested_tests ->empty ()) {
1933- std::cout << " />\n " ;
1959+ stream << " />\n " ;
19341960 } else if (!result.nested_tests ->empty ()) {
1935- std::cout << " />\n " ;
1936- print_result (suite_name, indent + " " , result);
1937- std::cout << indent << " </testcase>\n " ;
1961+ stream << " />\n " ;
1962+ print_result (stream, suite_name, indent + " " , result);
1963+ stream << indent << " </testcase>\n " ;
19381964 } else if (!result.report_string .empty ()) {
1939- std::cout << " >\n " ;
1940- std::cout << indent << indent << " <system-out>\n " ;
1941- std::cout << result.report_string << " \n " ;
1942- std::cout << indent << indent << " </system-out>\n " ;
1943- std::cout << indent << " </testcase>\n " ;
1965+ stream << " >\n " ;
1966+ stream << indent << indent << " <system-out>\n " ;
1967+ stream << result.report_string << " \n " ;
1968+ stream << indent << indent << " </system-out>\n " ;
1969+ stream << indent << " </testcase>\n " ;
19441970 }
19451971 }
19461972 }
0 commit comments