| 1 | // (C) Copyright Gennadiy Rozental 2001. |
| 2 | // Distributed under the Boost Software License, Version 1.0. |
| 3 | // (See accompanying file LICENSE_1_0.txt or copy at |
| 4 | // http://www.boost.org/LICENSE_1_0.txt) |
| 5 | |
| 6 | // See http://www.boost.org/libs/test for the library home page. |
| 7 | // |
| 8 | // File : $RCSfile$ |
| 9 | // |
| 10 | // Version : $Revision$ |
| 11 | // |
| 12 | // Description : main function implementation for Unit Test Framework |
| 13 | // *************************************************************************** |
| 14 | |
| 15 | #ifndef BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER |
| 16 | #define BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER |
| 17 | |
| 18 | // Boost.Test |
| 19 | #include <boost/test/framework.hpp> |
| 20 | #include <boost/test/results_collector.hpp> |
| 21 | #include <boost/test/results_reporter.hpp> |
| 22 | |
| 23 | #include <boost/test/tree/visitor.hpp> |
| 24 | #include <boost/test/tree/test_unit.hpp> |
| 25 | #include <boost/test/tree/traverse.hpp> |
| 26 | |
| 27 | #include <boost/test/unit_test_parameters.hpp> |
| 28 | |
| 29 | #include <boost/test/utils/foreach.hpp> |
| 30 | #include <boost/test/utils/basic_cstring/io.hpp> |
| 31 | |
| 32 | // Boost |
| 33 | #include <boost/core/ignore_unused.hpp> |
| 34 | #include <boost/cstdlib.hpp> |
| 35 | |
| 36 | // STL |
| 37 | #include <cstdio> |
| 38 | #include <stdexcept> |
| 39 | #include <iostream> |
| 40 | #include <iomanip> |
| 41 | #include <iterator> |
| 42 | #include <set> |
| 43 | |
| 44 | #include <boost/test/detail/suppress_warnings.hpp> |
| 45 | |
| 46 | //____________________________________________________________________________// |
| 47 | |
| 48 | namespace boost { |
| 49 | namespace unit_test { |
| 50 | |
| 51 | namespace ut_detail { |
| 52 | |
| 53 | // ************************************************************************** // |
| 54 | // ************** hrf_content_reporter ************** // |
| 55 | // ************************************************************************** // |
| 56 | |
| 57 | struct hrf_content_reporter : test_tree_visitor { |
| 58 | explicit hrf_content_reporter( std::ostream& os ) : m_os( os ), m_indent( -4 ) {} // skip master test suite |
| 59 | |
| 60 | private: |
| 61 | void report_test_unit( test_unit const& tu ) |
| 62 | { |
| 63 | m_os << std::setw( m_indent ) << "" << tu.p_name; |
| 64 | m_os << (tu.p_default_status == test_unit::RS_ENABLED ? "*" : " " ); |
| 65 | //m_os << '[' << tu.p_sibling_rank << ']'; |
| 66 | if( !tu.p_description->empty() ) |
| 67 | m_os << ": " << tu.p_description; |
| 68 | |
| 69 | m_os << "\n" ; |
| 70 | } |
| 71 | void visit( test_case const& tc ) BOOST_OVERRIDE { report_test_unit( tu: tc ); } |
| 72 | bool test_suite_start( test_suite const& ts ) BOOST_OVERRIDE |
| 73 | { |
| 74 | if( m_indent >= 0 ) |
| 75 | report_test_unit( tu: ts ); |
| 76 | m_indent += 4; |
| 77 | return true; |
| 78 | } |
| 79 | void test_suite_finish( test_suite const& ) BOOST_OVERRIDE |
| 80 | { |
| 81 | m_indent -= 4; |
| 82 | } |
| 83 | |
| 84 | // Data members |
| 85 | std::ostream& m_os; |
| 86 | int m_indent; |
| 87 | }; |
| 88 | |
| 89 | // ************************************************************************** // |
| 90 | // ************** dot_content_reporter ************** // |
| 91 | // ************************************************************************** // |
| 92 | |
| 93 | struct dot_content_reporter : test_tree_visitor { |
| 94 | explicit dot_content_reporter( std::ostream& os ) : m_os( os ) {} |
| 95 | |
| 96 | private: |
| 97 | void report_test_unit( test_unit const& tu ) |
| 98 | { |
| 99 | bool master_ts = tu.p_parent_id == INV_TEST_UNIT_ID; |
| 100 | |
| 101 | m_os << "tu" << tu.p_id; |
| 102 | |
| 103 | m_os << (master_ts ? "[shape=ellipse,peripheries=2" : "[shape=Mrecord" ); |
| 104 | |
| 105 | m_os << ",fontname=Helvetica" ; |
| 106 | |
| 107 | m_os << (tu.p_default_status == test_unit::RS_ENABLED ? ",color=green" : ",color=yellow" ); |
| 108 | |
| 109 | if( master_ts ) |
| 110 | m_os << ",label=\"" << tu.p_name << "\"];\n" ; |
| 111 | else { |
| 112 | m_os << ",label=\"" << tu.p_name << "|" << tu.p_file_name << "(" << tu.p_line_num << ")" ; |
| 113 | if( tu.p_timeout > 0 ) |
| 114 | m_os << "|timeout=" << tu.p_timeout; |
| 115 | if( tu.p_expected_failures != 0 ) |
| 116 | m_os << "|expected failures=" << tu.p_expected_failures; |
| 117 | if( !tu.p_labels->empty() ) { |
| 118 | m_os << "|labels:" ; |
| 119 | |
| 120 | BOOST_TEST_FOREACH( std::string const&, l, tu.p_labels.get() ) |
| 121 | m_os << " @" << l; |
| 122 | } |
| 123 | m_os << "\"];\n" ; |
| 124 | } |
| 125 | |
| 126 | if( !master_ts ) |
| 127 | m_os << "tu" << tu.p_parent_id << " -> " << "tu" << tu.p_id << ";\n" ; |
| 128 | |
| 129 | BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) { |
| 130 | test_unit const& dep = framework::get( id: dep_id, t: TUT_ANY ); |
| 131 | |
| 132 | m_os << "tu" << tu.p_id << " -> " << "tu" << dep.p_id << "[color=red,style=dotted,constraint=false];\n" ; |
| 133 | } |
| 134 | |
| 135 | } |
| 136 | void visit( test_case const& tc ) BOOST_OVERRIDE |
| 137 | { |
| 138 | report_test_unit( tu: tc ); |
| 139 | } |
| 140 | bool test_suite_start( test_suite const& ts ) BOOST_OVERRIDE |
| 141 | { |
| 142 | if( ts.p_parent_id == INV_TEST_UNIT_ID ) |
| 143 | m_os << "digraph G {rankdir=LR;\n" ; |
| 144 | |
| 145 | report_test_unit( tu: ts ); |
| 146 | |
| 147 | m_os << "{\n" ; |
| 148 | |
| 149 | return true; |
| 150 | } |
| 151 | void test_suite_finish( test_suite const& ts ) BOOST_OVERRIDE |
| 152 | { |
| 153 | m_os << "}\n" ; |
| 154 | if( ts.p_parent_id == INV_TEST_UNIT_ID ) |
| 155 | m_os << "}\n" ; |
| 156 | } |
| 157 | |
| 158 | std::ostream& m_os; |
| 159 | }; |
| 160 | |
| 161 | // ************************************************************************** // |
| 162 | // ************** labels_collector ************** // |
| 163 | // ************************************************************************** // |
| 164 | |
| 165 | struct labels_collector : test_tree_visitor { |
| 166 | std::set<std::string> const& labels() const { return m_labels; } |
| 167 | |
| 168 | private: |
| 169 | bool visit( test_unit const& tu ) BOOST_OVERRIDE |
| 170 | { |
| 171 | m_labels.insert( first: tu.p_labels->begin(), last: tu.p_labels->end() ); |
| 172 | return true; |
| 173 | } |
| 174 | |
| 175 | // Data members |
| 176 | std::set<std::string> m_labels; |
| 177 | }; |
| 178 | |
| 179 | struct framework_shutdown_helper { |
| 180 | ~framework_shutdown_helper() { |
| 181 | try { |
| 182 | framework::shutdown(); |
| 183 | } |
| 184 | catch(...) { |
| 185 | std::cerr << "Boost.Test shutdown exception caught" << std::endl; |
| 186 | } |
| 187 | } |
| 188 | }; |
| 189 | |
| 190 | } // namespace ut_detail |
| 191 | |
| 192 | // ************************************************************************** // |
| 193 | // ************** unit_test_main ************** // |
| 194 | // ************************************************************************** // |
| 195 | |
| 196 | |
| 197 | |
| 198 | int BOOST_TEST_DECL |
| 199 | unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) |
| 200 | { |
| 201 | int result_code = 0; |
| 202 | |
| 203 | ut_detail::framework_shutdown_helper shutdown_helper; |
| 204 | boost::ignore_unused(shutdown_helper); |
| 205 | |
| 206 | BOOST_TEST_I_TRY { |
| 207 | |
| 208 | framework::init( init_func, argc, argv ); |
| 209 | |
| 210 | if( runtime_config::get<bool>( parameter_name: runtime_config::btrt_wait_for_debugger ) ) { |
| 211 | results_reporter::get_stream() << "Press any key to continue..." << std::endl; |
| 212 | |
| 213 | // getchar is defined as a macro in uClibc. Use parenthesis to fix |
| 214 | // gcc bug 58952 for gcc <= 4.8.2. |
| 215 | (std::getchar)(); |
| 216 | results_reporter::get_stream() << "Continuing..." << std::endl; |
| 217 | } |
| 218 | |
| 219 | framework::finalize_setup_phase(); |
| 220 | |
| 221 | output_format list_cont = runtime_config::get<output_format>( parameter_name: runtime_config::btrt_list_content ); |
| 222 | if( list_cont != unit_test::OF_INVALID ) { |
| 223 | if( list_cont == unit_test::OF_DOT ) { |
| 224 | ut_detail::dot_content_reporter reporter( results_reporter::get_stream() ); |
| 225 | |
| 226 | traverse_test_tree( id: framework::master_test_suite().p_id, V&: reporter, ignore_status: true ); |
| 227 | } |
| 228 | else { |
| 229 | ut_detail::hrf_content_reporter reporter( results_reporter::get_stream() ); |
| 230 | |
| 231 | traverse_test_tree( id: framework::master_test_suite().p_id, V&: reporter, ignore_status: true ); |
| 232 | } |
| 233 | |
| 234 | return boost::exit_success; |
| 235 | } |
| 236 | |
| 237 | if( runtime_config::get<bool>( parameter_name: runtime_config::btrt_list_labels ) ) { |
| 238 | ut_detail::labels_collector collector; |
| 239 | |
| 240 | traverse_test_tree( id: framework::master_test_suite().p_id, V&: collector, ignore_status: true ); |
| 241 | |
| 242 | results_reporter::get_stream() << "Available labels:\n " ; |
| 243 | std::copy( first: collector.labels().begin(), last: collector.labels().end(), |
| 244 | result: std::ostream_iterator<std::string>( results_reporter::get_stream(), "\n " ) ); |
| 245 | results_reporter::get_stream() << "\n" ; |
| 246 | |
| 247 | return boost::exit_success; |
| 248 | } |
| 249 | |
| 250 | framework::run(); |
| 251 | |
| 252 | result_code = !runtime_config::get<bool>( parameter_name: runtime_config::btrt_result_code ) |
| 253 | ? boost::exit_success |
| 254 | : results_collector.results( id: framework::master_test_suite().p_id ).result_code(); |
| 255 | } |
| 256 | BOOST_TEST_I_CATCH( framework::nothing_to_test, ex ) { |
| 257 | result_code = ex.m_result_code; |
| 258 | } |
| 259 | BOOST_TEST_I_CATCH( framework::internal_error, ex ) { |
| 260 | results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl; |
| 261 | |
| 262 | result_code = boost::exit_exception_failure; |
| 263 | } |
| 264 | BOOST_TEST_I_CATCH( framework::setup_error, ex ) { |
| 265 | results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; |
| 266 | |
| 267 | result_code = boost::exit_exception_failure; |
| 268 | } |
| 269 | BOOST_TEST_I_CATCH( std::logic_error, ex ) { |
| 270 | results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; |
| 271 | |
| 272 | result_code = boost::exit_exception_failure; |
| 273 | } |
| 274 | BOOST_TEST_I_CATCHALL() { |
| 275 | results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; |
| 276 | |
| 277 | result_code = boost::exit_exception_failure; |
| 278 | } |
| 279 | |
| 280 | return result_code; |
| 281 | } |
| 282 | |
| 283 | } // namespace unit_test |
| 284 | } // namespace boost |
| 285 | |
| 286 | #if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN) |
| 287 | |
| 288 | // ************************************************************************** // |
| 289 | // ************** main function for tests using lib ************** // |
| 290 | // ************************************************************************** // |
| 291 | |
| 292 | int BOOST_TEST_CALL_DECL |
| 293 | main( int argc, char* argv[] ) |
| 294 | { |
| 295 | // prototype for user's unit test init function |
| 296 | #ifdef BOOST_TEST_ALTERNATIVE_INIT_API |
| 297 | extern bool init_unit_test(); |
| 298 | |
| 299 | boost::unit_test::init_unit_test_func init_func = &init_unit_test; |
| 300 | #else |
| 301 | extern ::boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ); |
| 302 | |
| 303 | boost::unit_test::init_unit_test_func init_func = &init_unit_test_suite; |
| 304 | #endif |
| 305 | |
| 306 | return ::boost::unit_test::unit_test_main( init_func, argc, argv ); |
| 307 | } |
| 308 | |
| 309 | #endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN |
| 310 | |
| 311 | //____________________________________________________________________________// |
| 312 | |
| 313 | #include <boost/test/detail/enable_warnings.hpp> |
| 314 | |
| 315 | #endif // BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER |
| 316 | |