$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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