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 : implemets Unit Test Log |
13 | // *************************************************************************** |
14 | |
15 | #ifndef BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER |
16 | #define BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER |
17 | |
18 | // Boost.Test |
19 | #include <boost/test/unit_test_log.hpp> |
20 | #include <boost/test/unit_test_log_formatter.hpp> |
21 | #include <boost/test/execution_monitor.hpp> |
22 | #include <boost/test/framework.hpp> |
23 | #include <boost/test/unit_test_parameters.hpp> |
24 | |
25 | #include <boost/test/utils/basic_cstring/compare.hpp> |
26 | |
27 | #include <boost/test/output/compiler_log_formatter.hpp> |
28 | #include <boost/test/output/xml_log_formatter.hpp> |
29 | |
30 | // Boost |
31 | #include <boost/scoped_ptr.hpp> |
32 | #include <boost/io/ios_state.hpp> |
33 | typedef ::boost::io::ios_base_all_saver io_saver_type; |
34 | |
35 | #include <boost/test/detail/suppress_warnings.hpp> |
36 | |
37 | //____________________________________________________________________________// |
38 | |
39 | namespace boost { |
40 | namespace unit_test { |
41 | |
42 | // ************************************************************************** // |
43 | // ************** entry_value_collector ************** // |
44 | // ************************************************************************** // |
45 | |
46 | namespace ut_detail { |
47 | |
48 | entry_value_collector const& |
49 | entry_value_collector::operator<<( lazy_ostream const& v ) const |
50 | { |
51 | unit_test_log << v; |
52 | |
53 | return *this; |
54 | } |
55 | |
56 | //____________________________________________________________________________// |
57 | |
58 | entry_value_collector const& |
59 | entry_value_collector::operator<<( const_string v ) const |
60 | { |
61 | unit_test_log << v; |
62 | |
63 | return *this; |
64 | } |
65 | |
66 | //____________________________________________________________________________// |
67 | |
68 | entry_value_collector::~entry_value_collector() |
69 | { |
70 | if( m_last ) |
71 | unit_test_log << log::end(); |
72 | } |
73 | |
74 | //____________________________________________________________________________// |
75 | |
76 | } // namespace ut_detail |
77 | |
78 | // ************************************************************************** // |
79 | // ************** unit_test_log ************** // |
80 | // ************************************************************************** // |
81 | |
82 | namespace { |
83 | |
84 | struct unit_test_log_impl { |
85 | // Constructor |
86 | unit_test_log_impl() |
87 | : m_stream( &std::cout ) |
88 | , m_stream_state_saver( new io_saver_type( std::cout ) ) |
89 | , m_threshold_level( log_all_errors ) |
90 | , m_log_formatter( new output::compiler_log_formatter ) |
91 | { |
92 | } |
93 | |
94 | // log data |
95 | typedef scoped_ptr<unit_test_log_formatter> formatter_ptr; |
96 | typedef scoped_ptr<io_saver_type> saver_ptr; |
97 | |
98 | std::ostream* m_stream; |
99 | saver_ptr m_stream_state_saver; |
100 | log_level m_threshold_level; |
101 | formatter_ptr m_log_formatter; |
102 | |
103 | // entry data |
104 | bool m_entry_in_progress; |
105 | bool m_entry_started; |
106 | log_entry_data m_entry_data; |
107 | |
108 | // check point data |
109 | log_checkpoint_data m_checkpoint_data; |
110 | |
111 | // helper functions |
112 | std::ostream& stream() |
113 | { |
114 | return *m_stream; |
115 | } |
116 | void set_checkpoint( const_string file, std::size_t line_num, const_string msg ) |
117 | { |
118 | assign_op( target&: m_checkpoint_data.m_message, src: msg, 0 ); |
119 | m_checkpoint_data.m_file_name = file; |
120 | m_checkpoint_data.m_line_num = line_num; |
121 | } |
122 | }; |
123 | |
124 | unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; } |
125 | |
126 | } // local namespace |
127 | |
128 | //____________________________________________________________________________// |
129 | |
130 | void |
131 | unit_test_log_t::test_start( counter_t test_cases_amount ) |
132 | { |
133 | if( s_log_impl().m_threshold_level == log_nothing ) |
134 | return; |
135 | |
136 | s_log_impl().m_log_formatter->log_start( os&: s_log_impl().stream(), test_cases_amount ); |
137 | |
138 | if( runtime_config::get<bool>( parameter_name: runtime_config::BUILD_INFO ) ) |
139 | s_log_impl().m_log_formatter->log_build_info( os&: s_log_impl().stream() ); |
140 | |
141 | s_log_impl().m_entry_in_progress = false; |
142 | } |
143 | |
144 | //____________________________________________________________________________// |
145 | |
146 | void |
147 | unit_test_log_t::test_finish() |
148 | { |
149 | if( s_log_impl().m_threshold_level == log_nothing ) |
150 | return; |
151 | |
152 | s_log_impl().m_log_formatter->log_finish( os&: s_log_impl().stream() ); |
153 | |
154 | s_log_impl().stream().flush(); |
155 | } |
156 | |
157 | //____________________________________________________________________________// |
158 | |
159 | void |
160 | unit_test_log_t::test_aborted() |
161 | { |
162 | BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted" ; |
163 | } |
164 | |
165 | //____________________________________________________________________________// |
166 | |
167 | void |
168 | unit_test_log_t::test_unit_start( test_unit const& tu ) |
169 | { |
170 | if( s_log_impl().m_threshold_level > log_test_units ) |
171 | return; |
172 | |
173 | if( s_log_impl().m_entry_in_progress ) |
174 | *this << log::end(); |
175 | |
176 | s_log_impl().m_log_formatter->test_unit_start( os&: s_log_impl().stream(), tu ); |
177 | } |
178 | |
179 | //____________________________________________________________________________// |
180 | |
181 | void |
182 | unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed ) |
183 | { |
184 | if( s_log_impl().m_threshold_level > log_test_units ) |
185 | return; |
186 | |
187 | s_log_impl().m_checkpoint_data.clear(); |
188 | |
189 | if( s_log_impl().m_entry_in_progress ) |
190 | *this << log::end(); |
191 | |
192 | s_log_impl().m_log_formatter->test_unit_finish( os&: s_log_impl().stream(), tu, elapsed ); |
193 | } |
194 | |
195 | //____________________________________________________________________________// |
196 | |
197 | void |
198 | unit_test_log_t::test_unit_skipped( test_unit const& tu, const_string reason ) |
199 | { |
200 | if( s_log_impl().m_threshold_level > log_test_units ) |
201 | return; |
202 | |
203 | if( s_log_impl().m_entry_in_progress ) |
204 | *this << log::end(); |
205 | |
206 | s_log_impl().m_log_formatter->test_unit_skipped( os&: s_log_impl().stream(), tu, reason ); |
207 | } |
208 | |
209 | //____________________________________________________________________________// |
210 | |
211 | void |
212 | unit_test_log_t::exception_caught( execution_exception const& ex ) |
213 | { |
214 | log_level l = |
215 | ex.code() <= execution_exception::cpp_exception_error ? log_cpp_exception_errors : |
216 | (ex.code() <= execution_exception::timeout_error ? log_system_errors |
217 | : log_fatal_errors ); |
218 | |
219 | if( l >= s_log_impl().m_threshold_level ) { |
220 | if( s_log_impl().m_entry_in_progress ) |
221 | *this << log::end(); |
222 | |
223 | s_log_impl().m_log_formatter->log_exception_start( os&: s_log_impl().stream(), lcd: s_log_impl().m_checkpoint_data, ex ); |
224 | |
225 | log_entry_context( l ); |
226 | |
227 | s_log_impl().m_log_formatter->log_exception_finish( os&: s_log_impl().stream() ); |
228 | } |
229 | |
230 | clear_entry_context(); |
231 | } |
232 | |
233 | //____________________________________________________________________________// |
234 | |
235 | void |
236 | unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg ) |
237 | { |
238 | s_log_impl().set_checkpoint( file, line_num, msg ); |
239 | } |
240 | |
241 | //____________________________________________________________________________// |
242 | |
243 | char |
244 | set_unix_slash( char in ) |
245 | { |
246 | return in == '\\' ? '/' : in; |
247 | } |
248 | |
249 | unit_test_log_t& |
250 | unit_test_log_t::operator<<( log::begin const& b ) |
251 | { |
252 | if( s_log_impl().m_entry_in_progress ) |
253 | *this << log::end(); |
254 | |
255 | s_log_impl().m_stream_state_saver->restore(); |
256 | |
257 | s_log_impl().m_entry_data.clear(); |
258 | |
259 | assign_op( target&: s_log_impl().m_entry_data.m_file_name, src: b.m_file_name, 0 ); |
260 | |
261 | // normalize file name |
262 | std::transform( first: s_log_impl().m_entry_data.m_file_name.begin(), last: s_log_impl().m_entry_data.m_file_name.end(), |
263 | result: s_log_impl().m_entry_data.m_file_name.begin(), |
264 | unary_op: &set_unix_slash ); |
265 | |
266 | s_log_impl().m_entry_data.m_line_num = b.m_line_num; |
267 | |
268 | return *this; |
269 | } |
270 | |
271 | //____________________________________________________________________________// |
272 | |
273 | unit_test_log_t& |
274 | unit_test_log_t::operator<<( log::end const& ) |
275 | { |
276 | if( s_log_impl().m_entry_in_progress ) { |
277 | log_entry_context( l: s_log_impl().m_entry_data.m_level ); |
278 | |
279 | s_log_impl().m_log_formatter->log_entry_finish( os&: s_log_impl().stream() ); |
280 | |
281 | s_log_impl().m_entry_in_progress = false; |
282 | } |
283 | |
284 | clear_entry_context(); |
285 | |
286 | return *this; |
287 | } |
288 | |
289 | //____________________________________________________________________________// |
290 | |
291 | unit_test_log_t& |
292 | unit_test_log_t::operator<<( log_level l ) |
293 | { |
294 | s_log_impl().m_entry_data.m_level = l; |
295 | |
296 | return *this; |
297 | } |
298 | |
299 | //____________________________________________________________________________// |
300 | |
301 | ut_detail::entry_value_collector |
302 | unit_test_log_t::operator()( log_level l ) |
303 | { |
304 | *this << l; |
305 | |
306 | return ut_detail::entry_value_collector(); |
307 | } |
308 | |
309 | //____________________________________________________________________________// |
310 | |
311 | bool |
312 | unit_test_log_t::log_entry_start() |
313 | { |
314 | if( s_log_impl().m_entry_in_progress ) |
315 | return true; |
316 | |
317 | switch( s_log_impl().m_entry_data.m_level ) { |
318 | case log_successful_tests: |
319 | s_log_impl().m_log_formatter->log_entry_start( os&: s_log_impl().stream(), led: s_log_impl().m_entry_data, |
320 | let: unit_test_log_formatter::BOOST_UTL_ET_INFO ); |
321 | break; |
322 | case log_messages: |
323 | s_log_impl().m_log_formatter->log_entry_start( os&: s_log_impl().stream(), led: s_log_impl().m_entry_data, |
324 | let: unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ); |
325 | break; |
326 | case log_warnings: |
327 | s_log_impl().m_log_formatter->log_entry_start( os&: s_log_impl().stream(), led: s_log_impl().m_entry_data, |
328 | let: unit_test_log_formatter::BOOST_UTL_ET_WARNING ); |
329 | break; |
330 | case log_all_errors: |
331 | case log_cpp_exception_errors: |
332 | case log_system_errors: |
333 | s_log_impl().m_log_formatter->log_entry_start( os&: s_log_impl().stream(), led: s_log_impl().m_entry_data, |
334 | let: unit_test_log_formatter::BOOST_UTL_ET_ERROR ); |
335 | break; |
336 | case log_fatal_errors: |
337 | s_log_impl().m_log_formatter->log_entry_start( os&: s_log_impl().stream(), led: s_log_impl().m_entry_data, |
338 | let: unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR ); |
339 | break; |
340 | case log_nothing: |
341 | case log_test_units: |
342 | case invalid_log_level: |
343 | return false; |
344 | } |
345 | |
346 | s_log_impl().m_entry_in_progress = true; |
347 | |
348 | return true; |
349 | } |
350 | |
351 | //____________________________________________________________________________// |
352 | |
353 | unit_test_log_t& |
354 | unit_test_log_t::operator<<( const_string value ) |
355 | { |
356 | if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() ) |
357 | s_log_impl().m_log_formatter->log_entry_value( os&: s_log_impl().stream(), value ); |
358 | |
359 | return *this; |
360 | } |
361 | |
362 | //____________________________________________________________________________// |
363 | |
364 | unit_test_log_t& |
365 | unit_test_log_t::operator<<( lazy_ostream const& value ) |
366 | { |
367 | if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() ) |
368 | s_log_impl().m_log_formatter->log_entry_value( os&: s_log_impl().stream(), value ); |
369 | |
370 | return *this; |
371 | } |
372 | |
373 | //____________________________________________________________________________// |
374 | |
375 | void |
376 | unit_test_log_t::log_entry_context( log_level l ) |
377 | { |
378 | framework::context_generator const& context = framework::get_context(); |
379 | if( context.is_empty() ) |
380 | return; |
381 | |
382 | const_string frame; |
383 | |
384 | s_log_impl().m_log_formatter->entry_context_start( os&: s_log_impl().stream(), l ); |
385 | |
386 | while( !(frame=context.next()).is_empty() ) |
387 | s_log_impl().m_log_formatter->log_entry_context( os&: s_log_impl().stream(), value: frame ); |
388 | |
389 | s_log_impl().m_log_formatter->entry_context_finish( os&: s_log_impl().stream() ); |
390 | } |
391 | |
392 | //____________________________________________________________________________// |
393 | |
394 | void |
395 | unit_test_log_t::clear_entry_context() |
396 | { |
397 | framework::clear_context(); |
398 | } |
399 | |
400 | //____________________________________________________________________________// |
401 | |
402 | void |
403 | unit_test_log_t::set_stream( std::ostream& str ) |
404 | { |
405 | if( s_log_impl().m_entry_in_progress ) |
406 | return; |
407 | |
408 | s_log_impl().m_stream = &str; |
409 | s_log_impl().m_stream_state_saver.reset( p: new io_saver_type( str ) ); |
410 | } |
411 | |
412 | //____________________________________________________________________________// |
413 | |
414 | void |
415 | unit_test_log_t::set_threshold_level( log_level lev ) |
416 | { |
417 | if( s_log_impl().m_entry_in_progress || lev == invalid_log_level ) |
418 | return; |
419 | |
420 | s_log_impl().m_threshold_level = lev; |
421 | } |
422 | |
423 | //____________________________________________________________________________// |
424 | |
425 | void |
426 | unit_test_log_t::set_format( output_format log_format ) |
427 | { |
428 | if( s_log_impl().m_entry_in_progress ) |
429 | return; |
430 | |
431 | switch( log_format ) { |
432 | default: |
433 | case OF_CLF: |
434 | set_formatter( new output::compiler_log_formatter ); |
435 | break; |
436 | case OF_XML: |
437 | set_formatter( new output::xml_log_formatter ); |
438 | break; |
439 | } |
440 | } |
441 | |
442 | //____________________________________________________________________________// |
443 | |
444 | void |
445 | unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter ) |
446 | { |
447 | s_log_impl().m_log_formatter.reset( p: the_formatter ); |
448 | } |
449 | |
450 | //____________________________________________________________________________// |
451 | |
452 | // ************************************************************************** // |
453 | // ************** unit_test_log_formatter ************** // |
454 | // ************************************************************************** // |
455 | |
456 | void |
457 | unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value ) |
458 | { |
459 | log_entry_value( os&: ostr, value: (wrap_stringstream().ref() << value).str() ); |
460 | } |
461 | |
462 | //____________________________________________________________________________// |
463 | |
464 | } // namespace unit_test |
465 | } // namespace boost |
466 | |
467 | #include <boost/test/detail/enable_warnings.hpp> |
468 | |
469 | #endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER |
470 | |