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 | |