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 48namespace boost { 49namespace unit_test { 50 51namespace ut_detail { 52 53// ************************************************************************** // 54// ************** hrf_content_reporter ************** // 55// ************************************************************************** // 56 57struct 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 60private: 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( tc ); } 72 bool test_suite_start( test_suite const& ts ) BOOST_OVERRIDE 73 { 74 if( m_indent >= 0 ) 75 report_test_unit( 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 93struct dot_content_reporter : test_tree_visitor { 94 explicit dot_content_reporter( std::ostream& os ) : m_os( os ) {} 95 96private: 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( dep_id, 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( 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( 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 165struct labels_collector : test_tree_visitor { 166 std::set<std::string> const& labels() const { return m_labels; } 167 168private: 169 bool visit( test_unit const& tu ) BOOST_OVERRIDE 170 { 171 m_labels.insert( tu.p_labels->begin(), tu.p_labels->end() ); 172 return true; 173 } 174 175 // Data members 176 std::set<std::string> m_labels; 177}; 178 179struct 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 198int BOOST_TEST_DECL 199unit_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>( 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>( 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( framework::master_test_suite().p_id, reporter, true ); 227 } 228 else { 229 ut_detail::hrf_content_reporter reporter( results_reporter::get_stream() ); 230 231 traverse_test_tree( framework::master_test_suite().p_id, reporter, true ); 232 } 233 234 return boost::exit_success; 235 } 236 237 if( runtime_config::get<bool>( runtime_config::btrt_list_labels ) ) { 238 ut_detail::labels_collector collector; 239 240 traverse_test_tree( framework::master_test_suite().p_id, collector, true ); 241 242 results_reporter::get_stream() << "Available labels:\n "; 243 std::copy( collector.labels().begin(), collector.labels().end(), 244 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>( runtime_config::btrt_result_code ) 253 ? boost::exit_success 254 : results_collector.results( 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 292int BOOST_TEST_CALL_DECL 293main( 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