Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74248 - in trunk/boost/test: . impl output
From: gennadiy.rozental_at_[hidden]
Date: 2011-09-06 03:14:10


Author: rogeeff
Date: 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
New Revision: 74248
URL: http://svn.boost.org/trac/boost/changeset/74248

Log:
support for failure context
Text files modified:
   trunk/boost/test/framework.hpp | 21 ++++++++
   trunk/boost/test/impl/compiler_log_formatter.ipp | 36 +++++++++++++
   trunk/boost/test/impl/framework.ipp | 98 +++++++++++++++++++++++++++++++++++++++
   trunk/boost/test/impl/test_tools.ipp | 25 ++++++++++
   trunk/boost/test/impl/unit_test_log.ipp | 35 +++++++++++++-
   trunk/boost/test/impl/xml_log_formatter.ipp | 41 +++++++++++++++
   trunk/boost/test/output/compiler_log_formatter.hpp | 7 ++
   trunk/boost/test/output/xml_log_formatter.hpp | 8 ++
   trunk/boost/test/test_tools.hpp | 24 +++++++++
   trunk/boost/test/unit_test_log.hpp | 4 +
   trunk/boost/test/unit_test_log_formatter.hpp | 12 ++--
   11 files changed, 294 insertions(+), 17 deletions(-)

Modified: trunk/boost/test/framework.hpp
==============================================================================
--- trunk/boost/test/framework.hpp (original)
+++ trunk/boost/test/framework.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -20,6 +20,7 @@
 #include <boost/test/detail/fwd_decl.hpp>
 #include <boost/test/utils/trivial_singleton.hpp>
 
+
 #include <boost/test/detail/suppress_warnings.hpp>
 
 // STL
@@ -61,6 +62,26 @@
 BOOST_TEST_DECL void deregister_observer( test_observer& );
 BOOST_TEST_DECL void reset_observers();
 
+// Assertions context support
+struct BOOST_TEST_DECL context_generator {
+ context_generator() : m_curr_frame( 0 ) {}
+
+ // is there any context?
+ bool is_empty() const;
+
+ // give me next frame; empty - last frame
+ const_string next() const;
+
+private:
+ // Data members
+ mutable unsigned m_curr_frame;
+};
+
+BOOST_TEST_DECL int add_context( lazy_ostream const& context_descr, bool sticky );
+BOOST_TEST_DECL void clear_context( int context_id = -1 );
+BOOST_TEST_DECL context_generator get_context();
+
+// Master test suite access
 BOOST_TEST_DECL master_test_suite_t& master_test_suite();
 
 // constant access methods

Modified: trunk/boost/test/impl/compiler_log_formatter.ipp
==============================================================================
--- trunk/boost/test/impl/compiler_log_formatter.ipp (original)
+++ trunk/boost/test/impl/compiler_log_formatter.ipp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -130,9 +130,10 @@
 //____________________________________________________________________________//
 
 void
-compiler_log_formatter::log_exception( std::ostream& output, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
+compiler_log_formatter::log_exception_start( std::ostream& output, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
 {
     execution_exception::location const& loc = ex.where();
+
     print_prefix( output, loc.m_file_name, loc.m_line_num );
 
     {
@@ -152,7 +153,13 @@
         if( !checkpoint_data.m_message.empty() )
             output << ": " << checkpoint_data.m_message;
     }
-
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_exception_finish( std::ostream& output )
+{
     output << std::endl;
 }
 
@@ -216,6 +223,7 @@
 {
     if( runtime_config::color_output() )
         output << setcolor();
+
     output << std::endl;
 }
 
@@ -236,6 +244,30 @@
 
 //____________________________________________________________________________//
 
+void
+compiler_log_formatter::entry_context_start( std::ostream& output )
+{
+ output << "\nFailure occurred in a following context:";
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::entry_context_finish( std::ostream& output )
+{
+ output.flush();
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_entry_context( std::ostream& output, const_string context_descr )
+{
+ output << "\n " << context_descr;
+}
+
+//____________________________________________________________________________//
+
 } // namespace output
 
 } // namespace unit_test

Modified: trunk/boost/test/impl/framework.ipp
==============================================================================
--- trunk/boost/test/impl/framework.ipp (original)
+++ trunk/boost/test/impl/framework.ipp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -117,6 +117,7 @@
     , m_next_test_suite_id( MIN_TEST_SUITE_ID )
     , m_is_initialized( false )
     , m_test_in_progress( false )
+ , m_context_idx( 0 )
     {}
 
     ~framework_impl() { clear(); }
@@ -134,7 +135,7 @@
                 delete static_cast<test_case const*>(tu_ptr);
         }
     }
-
+
     void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; }
 
     // test_tree_visitor interface implementation
@@ -147,9 +148,15 @@
             return;
         }
 
+ // setup contexts
+ m_context_idx = 0;
+
+ // notify all observers
         BOOST_TEST_FOREACH( test_observer*, to, m_observers )
             to->test_unit_start( tc );
 
+
+ // execute the test case body
         boost::timer tc_timer;
         test_unit_id bkup = m_curr_test_case;
         m_curr_test_case = tc.p_id;
@@ -157,14 +164,21 @@
 
         unsigned long elapsed = static_cast<unsigned long>( tc_timer.elapsed() * 1e6 );
 
+
+ // notify all observers about abortion
         if( unit_test_monitor.is_critical_error( run_result ) ) {
             BOOST_TEST_FOREACH( test_observer*, to, m_observers )
                 to->test_aborted();
         }
 
+ // notify all observers about completion
         BOOST_TEST_REVERSE_FOREACH( test_observer*, to, m_observers )
             to->test_unit_finish( tc, elapsed );
 
+ // cleanup leftover context
+ m_context.clear();
+
+ // restore state and abort if necessary
         m_curr_test_case = bkup;
 
         if( unit_test_monitor.is_critical_error( run_result ) )
@@ -202,6 +216,18 @@
 
     typedef std::map<test_unit_id,test_unit*> test_unit_store;
     typedef std::set<test_observer*,priority_order> observer_store;
+ struct context_frame {
+ context_frame( std::string const& d, int id, bool sticky )
+ : descr( d )
+ , frame_id( id )
+ , is_sticky( sticky )
+ {}
+
+ std::string descr;
+ int frame_id;
+ bool is_sticky;
+ };
+ typedef std::vector<context_frame> context_data;
 
     master_test_suite_t* m_master_test_suite;
     test_unit_id m_curr_test_case;
@@ -214,6 +240,8 @@
     bool m_test_in_progress;
 
     observer_store m_observers;
+ context_data m_context;
+ int m_context_idx;
 };
 
 //____________________________________________________________________________//
@@ -361,6 +389,74 @@
 
 //____________________________________________________________________________//
 
+int
+add_context( ::boost::unit_test::lazy_ostream const& context_descr, bool sticky )
+{
+ std::stringstream buffer;
+ context_descr( buffer );
+ int res_idx = s_frk_impl().m_context_idx++;
+
+ s_frk_impl().m_context.push_back( framework_impl::context_frame( buffer.str(), res_idx, sticky ) );
+
+ return res_idx;
+}
+
+//____________________________________________________________________________//
+
+struct frame_with_id {
+ explicit frame_with_id( int id ) : m_id( id ) {}
+
+ bool operator()( framework_impl::context_frame const& f )
+ {
+ return f.frame_id == m_id;
+ }
+ int m_id;
+};
+
+void
+clear_context( int frame_id )
+{
+ if( frame_id == -1 ) { // clear all non sticky frames
+ for( int i=s_frk_impl().m_context.size()-1; i>=0; i-- )
+ if( !s_frk_impl().m_context[i].is_sticky )
+ s_frk_impl().m_context.erase( s_frk_impl().m_context.begin()+i );
+ }
+
+ else { // clear specific frame
+ framework_impl::context_data::iterator it =
+ std::find_if( s_frk_impl().m_context.begin(), s_frk_impl().m_context.end(), frame_with_id( frame_id ) );
+
+ if( it != s_frk_impl().m_context.end() ) // really an internal error if this is not true
+ s_frk_impl().m_context.erase( it );
+ }
+}
+
+//____________________________________________________________________________//
+
+context_generator
+get_context()
+{
+ return context_generator();
+}
+
+//____________________________________________________________________________//
+
+bool
+context_generator::is_empty() const
+{
+ return s_frk_impl().m_context.empty();
+}
+
+//____________________________________________________________________________//
+
+const_string
+context_generator::next() const
+{
+ return m_curr_frame < s_frk_impl().m_context.size() ? s_frk_impl().m_context[m_curr_frame++].descr : const_string();
+}
+
+//____________________________________________________________________________//
+
 master_test_suite_t&
 master_test_suite()
 {

Modified: trunk/boost/test/impl/test_tools.ipp
==============================================================================
--- trunk/boost/test/impl/test_tools.ipp (original)
+++ trunk/boost/test/impl/test_tools.ipp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -389,6 +389,31 @@
 
 //____________________________________________________________________________//
 
+// ************************************************************************** //
+// ************** context_frame ************** //
+// ************************************************************************** //
+
+context_frame::context_frame( ::boost::unit_test::lazy_ostream const& context_descr )
+: m_frame_id( unit_test::framework::add_context( context_descr, true ) )
+{
+}
+
+//____________________________________________________________________________//
+
+context_frame::~context_frame()
+{
+ unit_test::framework::clear_context( m_frame_id );
+}
+
+//____________________________________________________________________________//
+
+context_frame::operator bool()
+{
+ return true;
+}
+
+//____________________________________________________________________________//
+
 } // namespace tt_detail
 
 // ************************************************************************** //

Modified: trunk/boost/test/impl/unit_test_log.ipp
==============================================================================
--- trunk/boost/test/impl/unit_test_log.ipp (original)
+++ trunk/boost/test/impl/unit_test_log.ipp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -20,6 +20,7 @@
 #include <boost/test/unit_test_log_formatter.hpp>
 #include <boost/test/unit_test_suite_impl.hpp>
 #include <boost/test/execution_monitor.hpp>
+#include <boost/test/framework.hpp>
 
 #include <boost/test/detail/unit_test_parameters.hpp>
 
@@ -235,7 +236,11 @@
         if( s_log_impl().m_entry_in_progress )
             *this << log::end();
 
- s_log_impl().m_log_formatter->log_exception( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex );
+ s_log_impl().m_log_formatter->log_exception_start( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex );
+
+ log_entry_context();
+
+ s_log_impl().m_log_formatter->log_exception_finish( s_log_impl().stream() );
     }
 }
 
@@ -282,10 +287,13 @@
 unit_test_log_t&
 unit_test_log_t::operator<<( log::end const& )
 {
- if( s_log_impl().m_entry_in_progress )
+ if( s_log_impl().m_entry_in_progress ) {
+ log_entry_context();
+
         s_log_impl().m_log_formatter->log_entry_finish( s_log_impl().stream() );
 
- s_log_impl().m_entry_in_progress = false;
+ s_log_impl().m_entry_in_progress = false;
+ }
 
     return *this;
 }
@@ -377,6 +385,27 @@
 //____________________________________________________________________________//
 
 void
+unit_test_log_t::log_entry_context()
+{
+ framework::context_generator const& context = framework::get_context();
+ if( context.is_empty() )
+ return;
+
+ const_string frame;
+
+ s_log_impl().m_log_formatter->entry_context_start( s_log_impl().stream() );
+
+ while( !(frame=context.next()).is_empty() )
+ s_log_impl().m_log_formatter->log_entry_context( s_log_impl().stream(), frame );
+
+ s_log_impl().m_log_formatter->entry_context_finish( s_log_impl().stream() );
+
+ framework::clear_context();
+}
+
+//____________________________________________________________________________//
+
+void
 unit_test_log_t::set_stream( std::ostream& str )
 {
     if( s_log_impl().m_entry_in_progress )

Modified: trunk/boost/test/impl/xml_log_formatter.ipp
==============================================================================
--- trunk/boost/test/impl/xml_log_formatter.ipp (original)
+++ trunk/boost/test/impl/xml_log_formatter.ipp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -110,7 +110,7 @@
 //____________________________________________________________________________//
 
 void
-xml_log_formatter::log_exception( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
+xml_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
 {
     execution_exception::location const& loc = ex.where();
 
@@ -129,7 +129,13 @@
              << cdata() << checkpoint_data.m_message
              << "</LastCheckpoint>";
     }
+}
+
+//____________________________________________________________________________//
 
+void
+xml_log_formatter::log_exception_finish( std::ostream& ostr )
+{
     ostr << "</Exception>";
 }
 
@@ -145,6 +151,8 @@
          << BOOST_TEST_L( " file" ) << attr_value() << entry_data.m_file_name
          << BOOST_TEST_L( " line" ) << attr_value() << entry_data.m_line_num
          << BOOST_TEST_L( "><![CDATA[" );
+
+ m_value_closed = false;
 }
 
 //____________________________________________________________________________//
@@ -160,13 +168,42 @@
 void
 xml_log_formatter::log_entry_finish( std::ostream& ostr )
 {
- ostr << BOOST_TEST_L( "]]></" ) << m_curr_tag << BOOST_TEST_L( ">" );
+ if( !m_value_closed ) {
+ ostr << BOOST_TEST_L( "]]>" );
+ m_value_closed = true;
+ }
+
+ ostr << BOOST_TEST_L( "</" ) << m_curr_tag << BOOST_TEST_L( ">" );
 
     m_curr_tag.clear();
 }
 
 //____________________________________________________________________________//
 
+void
+xml_log_formatter::entry_context_start( std::ostream& ostr )
+{
+ if( !m_value_closed ) {
+ ostr << BOOST_TEST_L( "]]>" );
+ m_value_closed = true;
+ }
+
+ ostr << BOOST_TEST_L( "<Context>" );
+
+}
+
+void
+xml_log_formatter::entry_context_finish( std::ostream& ostr )
+{
+ ostr << BOOST_TEST_L( "</Context>" );
+}
+
+void
+xml_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr )
+{
+ ostr << BOOST_TEST_L( "<Frame><![CDATA[" ) << context_descr << BOOST_TEST_L( "]]></Frame>" );
+}
+
 } // namespace output
 
 } // namespace unit_test

Modified: trunk/boost/test/output/compiler_log_formatter.hpp
==============================================================================
--- trunk/boost/test/output/compiler_log_formatter.hpp (original)
+++ trunk/boost/test/output/compiler_log_formatter.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -44,13 +44,18 @@
     void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed );
     void test_unit_skipped( std::ostream&, test_unit const& tu );
 
- void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex );
+ void log_exception_start( std::ostream&, log_checkpoint_data const&, execution_exception const& ex );
+ void log_exception_finish( std::ostream& );
 
     void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let );
     void log_entry_value( std::ostream&, const_string value );
     void log_entry_value( std::ostream&, lazy_ostream const& value );
     void log_entry_finish( std::ostream& );
 
+ void entry_context_start( std::ostream& );
+ void log_entry_context( std::ostream&, const_string );
+ void entry_context_finish( std::ostream& );
+
 protected:
     virtual void print_prefix( std::ostream&, const_string file, std::size_t line );
 };

Modified: trunk/boost/test/output/xml_log_formatter.hpp
==============================================================================
--- trunk/boost/test/output/xml_log_formatter.hpp (original)
+++ trunk/boost/test/output/xml_log_formatter.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -47,16 +47,22 @@
     void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed );
     void test_unit_skipped( std::ostream&, test_unit const& tu );
 
- void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex );
+ void log_exception_start( std::ostream&, log_checkpoint_data const&, execution_exception const& ex );
+ void log_exception_finish( std::ostream& );
 
     void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let );
     using unit_test_log_formatter::log_entry_value; // bring base class functions into overload set
     void log_entry_value( std::ostream&, const_string value );
     void log_entry_finish( std::ostream& );
 
+ void entry_context_start( std::ostream& );
+ void log_entry_context( std::ostream&, const_string );
+ void entry_context_finish( std::ostream& );
+
 private:
     // Data members
     const_string m_curr_tag;
+ bool m_value_closed;
 };
 
 } // namespace output

Modified: trunk/boost/test/test_tools.hpp
==============================================================================
--- trunk/boost/test/test_tools.hpp (original)
+++ trunk/boost/test/test_tools.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -293,6 +293,16 @@
 
 //____________________________________________________________________________//
 
+#define BOOST_TEST_INFO( context_descr ) \
+ ::boost::unit_test::framework::add_context( ::boost::unit_test::lazy_ostream::instance() << context_descr, false )
+
+//____________________________________________________________________________//
+
+#define BOOST_TEST_CONTEXT( context_descr ) \
+ if( ::boost::test_tools::tt_detail::context_frame BOOST_JOIN( context_frame_, __LINE__ ) = ::boost::test_tools::tt_detail::context_frame( ::boost::unit_test::lazy_ostream::instance() << context_descr ) )
+
+//____________________________________________________________________________//
+
 // ***************************** //
 // deprecated interface
 
@@ -712,6 +722,20 @@
 
 //____________________________________________________________________________//
 
+// ************************************************************************** //
+// ************** context_frame ************** //
+// ************************************************************************** //
+
+struct BOOST_TEST_DECL context_frame {
+ explicit context_frame( ::boost::unit_test::lazy_ostream const& context_descr );
+ ~context_frame();
+
+ operator bool();
+
+private:
+ int m_frame_id;
+};
+
 } // namespace tt_detail
 
 } // namespace test_tools

Modified: trunk/boost/test/unit_test_log.hpp
==============================================================================
--- trunk/boost/test/unit_test_log.hpp (original)
+++ trunk/boost/test/unit_test_log.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -126,7 +126,9 @@
     ut_detail::entry_value_collector operator()( log_level ); // initiate entry collection
 
 private:
- bool log_entry_start();
+ // Implementation helpers
+ bool log_entry_start();
+ void log_entry_context();
 
     BOOST_TEST_SINGLETON_CONS( unit_test_log_t );
 }; // unit_test_log_t

Modified: trunk/boost/test/unit_test_log_formatter.hpp
==============================================================================
--- trunk/boost/test/unit_test_log_formatter.hpp (original)
+++ trunk/boost/test/unit_test_log_formatter.hpp 2011-09-06 03:14:08 EDT (Tue, 06 Sep 2011)
@@ -98,17 +98,17 @@
     virtual void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ) = 0;
     virtual void test_unit_skipped( std::ostream&, test_unit const& ) = 0;
 
- virtual void log_exception( std::ostream& os, log_checkpoint_data const& cd, execution_exception const& ex )
- {
- // for backward compatibility
- log_exception( os, cd, ex.what() );
- }
- virtual void log_exception( std::ostream&, log_checkpoint_data const&, const_string /* explanation */ ) {}
+ virtual void log_exception_start( std::ostream&, log_checkpoint_data const&, execution_exception const& ex ) = 0;
+ virtual void log_exception_finish( std::ostream& ) = 0;
 
     virtual void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ) = 0;
     virtual void log_entry_value( std::ostream&, const_string value ) = 0;
     virtual void log_entry_value( std::ostream&, lazy_ostream const& value ); // there is a default impl
     virtual void log_entry_finish( std::ostream& ) = 0;
+
+ virtual void entry_context_start( std::ostream& ) = 0;
+ virtual void log_entry_context( std::ostream&, const_string ) = 0;
+ virtual void entry_context_finish( std::ostream& ) = 0;
 };
 
 } // namespace unit_test


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk