Include bind in ndnboost.
diff --git a/ndnboost/test/impl/compiler_log_formatter.ipp b/ndnboost/test/impl/compiler_log_formatter.ipp
new file mode 100644
index 0000000..e153920
--- /dev/null
+++ b/ndnboost/test/impl/compiler_log_formatter.ipp
@@ -0,0 +1,222 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : implements compiler like Log formatter
+// ***************************************************************************
+
+#ifndef BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER
+#define BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/output/compiler_log_formatter.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+#include <ndnboost/test/utils/lazy_ostream.hpp>
+
+// Boost
+#include <ndnboost/version.hpp>
+
+// STL
+#include <iostream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace output {
+
+// ************************************************************************** //
+// ************** compiler_log_formatter ************** //
+// ************************************************************************** //
+
+namespace {
+
+const_string
+test_phase_identifier()
+{
+ return framework::is_initialized()
+ ? const_string( framework::current_test_case().p_name.get() )
+ : BOOST_TEST_L( "Test setup" );
+}
+
+} // local namespace
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_start( std::ostream& output, counter_t test_cases_amount )
+{
+ if( test_cases_amount > 0 )
+ output << "Running " << test_cases_amount << " test "
+ << (test_cases_amount > 1 ? "cases" : "case") << "...\n";
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_finish( std::ostream& ostr )
+{
+ ostr.flush();
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_build_info( std::ostream& output )
+{
+ output << "Platform: " << BOOST_PLATFORM << '\n'
+ << "Compiler: " << BOOST_COMPILER << '\n'
+ << "STL : " << BOOST_STDLIB << '\n'
+ << "Boost : " << BOOST_VERSION/100000 << "."
+ << BOOST_VERSION/100 % 1000 << "."
+ << BOOST_VERSION % 100 << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::test_unit_start( std::ostream& output, test_unit const& tu )
+{
+ output << "Entering test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& tu, unsigned long elapsed )
+{
+ output << "Leaving test " << tu.p_type_name << " \"" << tu.p_name << "\"";
+
+ if( elapsed > 0 ) {
+ output << "; testing time: ";
+ if( elapsed % 1000 == 0 )
+ output << elapsed/1000 << "ms";
+ else
+ output << elapsed << "mks";
+ }
+
+ output << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::test_unit_skipped( std::ostream& output, test_unit const& tu )
+{
+ output << "Test " << tu.p_type_name << " \"" << tu.p_name << "\"" << "is skipped" << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_exception( 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 );
+
+ output << "fatal error in \"" << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": ";
+
+ output << ex.what();
+
+ if( !checkpoint_data.m_file_name.is_empty() ) {
+ output << '\n';
+ print_prefix( output, checkpoint_data.m_file_name, checkpoint_data.m_line_num );
+ output << "last checkpoint";
+ if( !checkpoint_data.m_message.empty() )
+ output << ": " << checkpoint_data.m_message;
+ }
+
+ output << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_entry_start( std::ostream& output, log_entry_data const& entry_data, log_entry_types let )
+{
+ switch( let ) {
+ case BOOST_UTL_ET_INFO:
+ print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
+ output << "info: ";
+ break;
+ case BOOST_UTL_ET_MESSAGE:
+ break;
+ case BOOST_UTL_ET_WARNING:
+ print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
+ output << "warning in \"" << test_phase_identifier() << "\": ";
+ break;
+ case BOOST_UTL_ET_ERROR:
+ print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
+ output << "error in \"" << test_phase_identifier() << "\": ";
+ break;
+ case BOOST_UTL_ET_FATAL_ERROR:
+ print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
+ output << "fatal error in \"" << test_phase_identifier() << "\": ";
+ break;
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_entry_value( std::ostream& output, const_string value )
+{
+ output << value;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_entry_value( std::ostream& output, lazy_ostream const& value )
+{
+ output << value;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::log_entry_finish( std::ostream& output )
+{
+ output << std::endl;
+}
+
+//____________________________________________________________________________//
+
+void
+compiler_log_formatter::print_prefix( std::ostream& output, const_string file, std::size_t line )
+{
+#ifdef __APPLE_CC__
+ // Xcode-compatible logging format, idea by Richard Dingwall at
+ // <http://richarddingwall.name/2008/06/01/using-the-boost-unit-test-framework-with-xcode-3/>.
+ output << file << ':' << line << ": ";
+#else
+ output << file << '(' << line << "): ";
+#endif
+}
+
+//____________________________________________________________________________//
+
+} // namespace output
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER
diff --git a/ndnboost/test/impl/cpp_main.ipp b/ndnboost/test/impl/cpp_main.ipp
new file mode 100644
index 0000000..3bacee1
--- /dev/null
+++ b/ndnboost/test/impl/cpp_main.ipp
@@ -0,0 +1,139 @@
+// (C) Copyright Gennadiy Rozental 2001-2008.
+// (C) Copyright Beman Dawes 1995-2001.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 49312 $
+//
+// Description : main function implementation for Program Executon Monitor
+// ***************************************************************************
+
+#ifndef BOOST_TEST_CPP_MAIN_IPP_012205GER
+#define BOOST_TEST_CPP_MAIN_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/execution_monitor.hpp>
+#include <ndnboost/test/detail/config.hpp>
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+
+// Boost
+#include <ndnboost/cstdlib.hpp> // for exit codes
+#include <ndnboost/config.hpp> // for workarounds
+
+// STL
+#include <iostream>
+#include <cstdlib> // std::getenv
+#include <cstring> // std::strerror
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::getenv; using ::strerror; }
+#endif
+
+namespace {
+
+struct cpp_main_caller {
+ cpp_main_caller( int (*cpp_main_func)( int argc, char* argv[] ), int argc, char** argv )
+ : m_cpp_main_func( cpp_main_func )
+ , m_argc( argc )
+ , m_argv( argv ) {}
+
+ int operator()() { return (*m_cpp_main_func)( m_argc, m_argv ); }
+
+private:
+ // Data members
+ int (*m_cpp_main_func)( int argc, char* argv[] );
+ int m_argc;
+ char** m_argv;
+};
+
+} // local namespace
+
+// ************************************************************************** //
+// ************** prg_exec_monitor_main ************** //
+// ************************************************************************** //
+
+namespace ndnboost {
+
+int BOOST_TEST_DECL
+prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char* argv[] )
+{
+ int result = 0;
+
+ try {
+ ndnboost::unit_test::const_string p( std::getenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS" ) );
+ ::ndnboost::execution_monitor ex_mon;
+
+ ex_mon.p_catch_system_errors.value = p != "no";
+
+ result = ex_mon.execute(
+ ::ndnboost::unit_test::callback0<int>( cpp_main_caller( cpp_main, argc, argv ) ) );
+
+ if( result == 0 )
+ result = ::ndnboost::exit_success;
+ else if( result != ::ndnboost::exit_success ) {
+ std::cout << "\n**** error return code: " << result << std::endl;
+ result = ::ndnboost::exit_failure;
+ }
+ }
+ catch( ::ndnboost::execution_exception const& exex ) {
+ std::cout << "\n**** exception(" << exex.code() << "): " << exex.what() << std::endl;
+ result = ::ndnboost::exit_exception_failure;
+ }
+ catch( ::ndnboost::system_error const& ex ) {
+ std::cout << "\n**** failed to initialize execution monitor."
+ << "\n**** expression at fault: " << ex.p_failed_exp
+ << "\n**** error(" << ex.p_errno << "): " << std::strerror( ex.p_errno ) << std::endl;
+ result = ::ndnboost::exit_exception_failure;
+ }
+
+ if( result != ::ndnboost::exit_success ) {
+ std::cerr << "******** errors detected; see standard output for details ********" << std::endl;
+ }
+ else {
+ // Some prefer a confirming message when all is well, while others don't
+ // like the clutter. Use an environment variable to avoid command
+ // line argument modifications; for use in production programs
+ // that's a no-no in some organizations.
+ ::ndnboost::unit_test::const_string p( std::getenv( "BOOST_PRG_MON_CONFIRM" ) );
+ if( p != "no" ) {
+ std::cerr << std::flush << "no errors detected" << std::endl;
+ }
+ }
+
+ return result;
+}
+
+} // namespace ndnboost
+
+#if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN)
+
+// ************************************************************************** //
+// ************** main function for tests using lib ************** //
+// ************************************************************************** //
+
+int cpp_main( int argc, char* argv[] ); // prototype for user's cpp_main()
+
+int BOOST_TEST_CALL_DECL
+main( int argc, char* argv[] )
+{
+ return ::ndnboost::prg_exec_monitor_main( &cpp_main, argc, argv );
+}
+
+//____________________________________________________________________________//
+
+#endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_CPP_MAIN_IPP_012205GER
diff --git a/ndnboost/test/impl/debug.ipp b/ndnboost/test/impl/debug.ipp
new file mode 100644
index 0000000..bf23f2e
--- /dev/null
+++ b/ndnboost/test/impl/debug.ipp
@@ -0,0 +1,970 @@
+// (C) Copyright Gennadiy Rozental 2006-2008.
+// Use, modification, and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : debug interfaces implementation
+// ***************************************************************************
+
+#ifndef BOOST_TEST_DEBUG_API_IPP_112006GER
+#define BOOST_TEST_DEBUG_API_IPP_112006GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+#include <ndnboost/test/detail/workaround.hpp>
+#include <ndnboost/test/detail/global_typedef.hpp>
+
+#include <ndnboost/test/debug.hpp>
+#include <ndnboost/test/debug_config.hpp>
+
+// Implementation on Windows
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32
+
+# define BOOST_WIN32_BASED_DEBUG
+
+// SYSTEM API
+# include <windows.h>
+# include <winreg.h>
+# include <cstdio>
+# include <cstring>
+
+# if !defined(NDEBUG) && defined(_MSC_VER)
+# define BOOST_MS_CRT_BASED_DEBUG
+# include <crtdbg.h>
+# endif
+
+
+# if BOOST_WORKAROUND( BOOST_MSVC, <1300)
+# define snprintf _snprintf
+# endif
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::memset; using ::sprintf; }
+# endif
+
+#elif defined(unix) || defined(__unix) // ********************* UNIX
+
+# define BOOST_UNIX_BASED_DEBUG
+
+// Boost.Test
+#include <ndnboost/test/utils/class_properties.hpp>
+#include <ndnboost/test/utils/algorithm.hpp>
+
+// STL
+#include <cstring> // std::memcpy
+#include <map>
+#include <cstdio>
+#include <stdarg.h> // !! ?? cstdarg
+
+// SYSTEM API
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/wait.h>
+# include <sys/time.h>
+# include <stdio.h>
+# include <stdlib.h>
+
+# if defined(sun) || defined(__sun)
+
+# define BOOST_SUN_BASED_DEBUG
+
+# ifndef BOOST_TEST_DBG_LIST
+# define BOOST_TEST_DBG_LIST dbx;gdb
+# endif
+
+# define BOOST_TEST_CNL_DBG dbx
+# define BOOST_TEST_GUI_DBG dbx-ddd
+
+# include <procfs.h>
+
+# elif defined(linux) || defined(__linux)
+
+# define BOOST_LINUX_BASED_DEBUG
+
+# include <sys/ptrace.h>
+
+# ifndef BOOST_TEST_STAT_LINE_MAX
+# define BOOST_TEST_STAT_LINE_MAX 500
+# endif
+
+# ifndef BOOST_TEST_DBG_LIST
+# define BOOST_TEST_DBG_LIST gdb
+# endif
+
+# define BOOST_TEST_CNL_DBG gdb
+# define BOOST_TEST_GUI_DBG gdb-xterm
+
+# endif
+
+#endif
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace debug {
+
+using unit_test::const_string;
+
+// ************************************************************************** //
+// ************** debug::info_t ************** //
+// ************************************************************************** //
+
+namespace {
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+template<typename T>
+inline void
+dyn_symbol( T& res, char const* module_name, char const* symbol_name )
+{
+ HMODULE m = ::GetModuleHandleA( module_name );
+
+ if( !m )
+ m = ::LoadLibraryA( module_name );
+
+ res = reinterpret_cast<T>( ::GetProcAddress( m, symbol_name ) );
+}
+
+//____________________________________________________________________________//
+
+static struct info_t {
+ typedef BOOL (WINAPI* IsDebuggerPresentT)();
+ typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* /*LPTSTR*/, LPDWORD, LPDWORD, LPBYTE, LPDWORD );
+ typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* /*LPCTSTR*/, PHKEY );
+ typedef LONG (WINAPI* RegCloseKeyT)( HKEY );
+
+ info_t();
+
+ IsDebuggerPresentT m_is_debugger_present;
+ RegOpenKeyT m_reg_open_key;
+ RegQueryValueExT m_reg_query_value;
+ RegCloseKeyT m_reg_close_key;
+
+} s_info;
+
+//____________________________________________________________________________//
+
+info_t::info_t()
+{
+ dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" );
+ dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" );
+ dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" );
+ dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" );
+}
+
+//____________________________________________________________________________//
+
+#elif defined(BOOST_UNIX_BASED_DEBUG)
+
+// ************************************************************************** //
+// ************** fd_holder ************** //
+// ************************************************************************** //
+
+struct fd_holder {
+ explicit fd_holder( int fd ) : m_fd( fd ) {}
+ ~fd_holder()
+ {
+ if( m_fd != -1 )
+ ::close( m_fd );
+ }
+
+ operator int() { return m_fd; }
+
+private:
+ // Data members
+ int m_fd;
+};
+
+
+// ************************************************************************** //
+// ************** process_info ************** //
+// ************************************************************************** //
+
+struct process_info {
+ // Constructor
+ explicit process_info( int pid );
+
+ // access methods
+ int parent_pid() const { return m_parent_pid; }
+ const_string binary_name() const { return m_binary_name; }
+ const_string binary_path() const { return m_binary_path; }
+
+private:
+ // Data members
+ int m_parent_pid;
+ const_string m_binary_name;
+ const_string m_binary_path;
+
+#if defined(BOOST_SUN_BASED_DEBUG)
+ struct psinfo m_psi;
+#elif defined(BOOST_LINUX_BASED_DEBUG)
+ char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1];
+#endif
+ char m_binary_path_buff[500+1]; // !! ??
+};
+
+//____________________________________________________________________________//
+
+process_info::process_info( int pid )
+: m_parent_pid( 0 )
+{
+#if defined(BOOST_SUN_BASED_DEBUG)
+ char fname_buff[30];
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid );
+
+ fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
+
+ if( psinfo_fd == -1 )
+ return;
+
+ if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 )
+ return;
+
+ m_parent_pid = m_psi.pr_ppid;
+
+ m_binary_name.assign( m_psi.pr_fname );
+
+ //-------------------------- //
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid );
+
+ fd_holder as_fd( ::open( fname_buff, O_RDONLY ) );
+ uintptr_t binary_name_pos;
+
+ // !! ?? could we avoid reading whole m_binary_path_buff?
+ if( as_fd == -1 ||
+ ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 ||
+ ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 ||
+ ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 ||
+ ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 )
+ return;
+
+ m_binary_path.assign( m_binary_path_buff );
+
+#elif defined(BOOST_LINUX_BASED_DEBUG)
+ char fname_buff[30];
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid );
+
+ fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
+
+ if( psinfo_fd == -1 )
+ return;
+
+ ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 );
+ if( num_read == -1 )
+ return;
+
+ m_stat_line[num_read] = 0;
+
+ char const* name_beg = m_stat_line;
+ while( *name_beg && *name_beg != '(' )
+ ++name_beg;
+
+ char const* name_end = name_beg+1;
+ while( *name_end && *name_end != ')' )
+ ++name_end;
+
+ std::sscanf( name_end+1, "%*s%d", &m_parent_pid );
+
+ m_binary_name.assign( name_beg+1, name_end );
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid );
+ num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 );
+
+ if( num_read == -1 )
+ return;
+
+ m_binary_path_buff[num_read] = 0;
+ m_binary_path.assign( m_binary_path_buff, num_read );
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** prepare_window_title ************** //
+// ************************************************************************** //
+
+static char*
+prepare_window_title( dbg_startup_info const& dsi )
+{
+ typedef unit_test::const_string str_t;
+
+ static char title_str[50];
+
+ str_t path_sep( "\\/" );
+
+ str_t::iterator it = unit_test::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(),
+ path_sep.begin(), path_sep.end() );
+
+ if( it == dsi.binary_path.end() )
+ it = dsi.binary_path.begin();
+ else
+ ++it;
+
+ ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid );
+
+ return title_str;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** save_execlp ************** //
+// ************************************************************************** //
+
+typedef unit_test::basic_cstring<char> mbuffer;
+
+inline char*
+copy_arg( mbuffer& dest, const_string arg )
+{
+ if( dest.size() < arg.size()+1 )
+ return 0;
+
+ char* res = dest.begin();
+
+ std::memcpy( res, arg.begin(), arg.size()+1 );
+
+ dest.trim_left( arg.size()+1 );
+
+ return res;
+}
+
+//____________________________________________________________________________//
+
+bool
+safe_execlp( char const* file, ... )
+{
+ static char* argv_buff[200];
+
+ va_list args;
+ char const* arg;
+
+ // first calculate actual number of arguments
+ int num_args = 2; // file name and 0 at least
+
+ va_start( args, file );
+ while( !!(arg = va_arg( args, char const* )) )
+ num_args++;
+ va_end( args );
+
+ // reserve space for the argument pointers array
+ char** argv_it = argv_buff;
+ mbuffer work_buff( reinterpret_cast<char*>(argv_buff), sizeof(argv_buff) );
+ work_buff.trim_left( num_args * sizeof(char*) );
+
+ // copy all the argument values into local storage
+ if( !(*argv_it++ = copy_arg( work_buff, file )) )
+ return false;
+
+ printf( "!! %s\n", file );
+
+ va_start( args, file );
+ while( !!(arg = va_arg( args, char const* )) ) {
+ printf( "!! %s\n", arg );
+ if( !(*argv_it++ = copy_arg( work_buff, arg )) )
+ return false;
+ }
+ va_end( args );
+
+ *argv_it = 0;
+
+ return ::execvp( file, argv_buff ) != -1;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** start_debugger_in_emacs ************** //
+// ************************************************************************** //
+
+static void
+start_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command )
+{
+ char const* title = prepare_window_title( dsi );
+
+ if( !title )
+ return;
+
+ dsi.display.is_empty()
+ ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 )
+ : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** gdb starters ************** //
+// ************************************************************************** //
+
+static char const*
+prepare_gdb_cmnd_file( dbg_startup_info const& dsi )
+{
+ // prepare pid value
+ char pid_buff[16];
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+ unit_test::const_string pid_str( pid_buff );
+
+ static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX"; // !! ??
+
+ // prepare commands
+ fd_holder cmd_fd( ::mkstemp( cmd_file_name ) );
+
+ if( cmd_fd == -1 )
+ return 0;
+
+#define WRITE_STR( str ) if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0;
+#define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0;
+
+ WRITE_CSTR( "file " );
+ WRITE_STR( dsi.binary_path );
+ WRITE_CSTR( "\nattach " );
+ WRITE_STR( pid_str );
+ WRITE_CSTR( "\nshell unlink " );
+ WRITE_STR( dsi.init_done_lock );
+ WRITE_CSTR( "\ncont" );
+ if( dsi.break_or_continue )
+ WRITE_CSTR( "\nup 4" );
+
+ WRITE_CSTR( "\necho \\n" ); // !! ??
+ WRITE_CSTR( "\nlist -" );
+ WRITE_CSTR( "\nlist" );
+ WRITE_CSTR( "\nshell unlink " );
+ WRITE_CSTR( cmd_file_name );
+
+ return cmd_file_name;
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_console( dbg_startup_info const& dsi )
+{
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+
+ if( !cmnd_file_name )
+ return;
+
+ safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_xterm( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+
+ if( !title || !cmnd_file_name )
+ return;
+
+ safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
+ "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
+ "gdb", "-q", "-x", cmnd_file_name, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_emacs( dbg_startup_info const& dsi )
+{
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+ if( !cmnd_file_name )
+ return;
+
+ char dbg_cmd_buff[500]; // !! ??
+ ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (gdb \"gdb -q -x %s\"))", cmnd_file_name );
+
+ start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_xemacs( dbg_startup_info const& )
+{
+ // !! ??
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** dbx starters ************** //
+// ************************************************************************** //
+
+static char const*
+prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true )
+{
+ static char cmd_line_buff[500]; // !! ??
+
+ ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s",
+ dsi.init_done_lock.begin(),
+ dsi.break_or_continue ? "up 2;": "",
+ list_source ? "echo \" \";list -w3;" : "" );
+
+ return cmd_line_buff;
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_console( dbg_startup_info const& dsi )
+{
+ char pid_buff[16];
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_xterm( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ if( !title )
+ return;
+
+ char pid_buff[16]; // !! ??
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
+ "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
+ "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_emacs( dbg_startup_info const& /*dsi*/ )
+{
+// char dbg_cmd_buff[500]; // !! ??
+//
+// ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (dbx \"dbx -q -c cont %s %ld\"))", dsi.binary_path.begin(), dsi.pid );
+
+// start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_xemacs( dbg_startup_info const& )
+{
+ // !! ??
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_ddd( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ if( !title )
+ return;
+
+ char pid_buff[16]; // !! ??
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "ddd", "-display", dsi.display.begin(),
+ "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** debug::info_t ************** //
+// ************************************************************************** //
+
+static struct info_t {
+ // Constructor
+ info_t();
+
+ // Public properties
+ unit_test::readwrite_property<std::string> p_dbg;
+
+ // Data members
+ std::map<std::string,dbg_starter> m_dbg_starter_reg;
+} s_info;
+
+//____________________________________________________________________________//
+
+info_t::info_t()
+{
+ p_dbg.value = ::getenv( "DISPLAY" )
+ ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) )
+ : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) );
+
+ m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console;
+ m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs;
+ m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm;
+ m_dbg_starter_reg[std::string("gdb-xemacs")] = &start_gdb_in_xemacs;
+
+ m_dbg_starter_reg[std::string("dbx")] = &start_dbx_in_console;
+ m_dbg_starter_reg[std::string("dbx-emacs")] = &start_dbx_in_emacs;
+ m_dbg_starter_reg[std::string("dbx-xterm")] = &start_dbx_in_xterm;
+ m_dbg_starter_reg[std::string("dbx-xemacs")] = &start_dbx_in_xemacs;
+ m_dbg_starter_reg[std::string("dbx-ddd")] = &start_dbx_in_ddd;
+}
+
+//____________________________________________________________________________//
+
+#endif
+
+} // local namespace
+
+// ************************************************************************** //
+// ************** check if program is running under debugger ************** //
+// ************************************************************************** //
+
+bool
+under_debugger()
+{
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+ return !!s_info.m_is_debugger_present && s_info.m_is_debugger_present();
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ // !! ?? could/should we cache the result somehow?
+ const_string dbg_list = BOOST_TEST_STRINGIZE( BOOST_TEST_DBG_LIST );
+
+ pid_t pid = ::getpid();
+
+ while( pid != 0 ) {
+ process_info pi( pid );
+
+ // !! ?? should we use tokenizer here instead?
+ if( dbg_list.find( pi.binary_name() ) != const_string::npos )
+ return true;
+
+ pid = (pi.parent_pid() == pid ? 0 : pi.parent_pid());
+ }
+
+ return false;
+
+#else // ****************************************************** default
+
+ return false;
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** cause program to break execution ************** //
+// ************** in debugger at call point ************** //
+// ************************************************************************** //
+
+void
+debugger_break()
+{
+ // !! ?? auto-start debugger?
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1300) || \
+ BOOST_WORKAROUND(__GNUC__, >= 3) && !defined(__MINGW32__) || \
+ defined(__INTEL_COMPILER)
+# define BOOST_DEBUG_BREAK __debugbreak
+#else
+# define BOOST_DEBUG_BREAK DebugBreak
+#endif
+
+#ifndef __MINGW32__
+ if( !under_debugger() ) {
+ __try {
+ __try {
+ BOOST_DEBUG_BREAK();
+ }
+ __except( UnhandledExceptionFilter(GetExceptionInformation()) )
+ {
+ // User opted to ignore the breakpoint
+ return;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // If we got here, the user has pushed Debug. Debugger is already attached to our process and we
+ // continue to let the another BOOST_DEBUG_BREAK to be called.
+ }
+ }
+#endif
+
+ BOOST_DEBUG_BREAK();
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ ::kill( ::getpid(), SIGTRAP );
+
+#else // ****************************************************** default
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** console debugger setup ************** //
+// ************************************************************************** //
+
+#if defined(BOOST_UNIX_BASED_DEBUG) // ************************ UNIX
+
+std::string
+set_debugger( unit_test::const_string dbg_id, dbg_starter s )
+{
+ std::string old = s_info.p_dbg;
+
+ assign_op( s_info.p_dbg.value, dbg_id, 0 );
+
+ if( !!s )
+ s_info.m_dbg_starter_reg[s_info.p_dbg] = s;
+
+ return old;
+}
+
+#else // ***************************************************** default
+
+std::string
+set_debugger( unit_test::const_string, dbg_starter )
+{
+ return std::string();
+}
+
+#endif
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** attach debugger to the current process ************** //
+// ************************************************************************** //
+
+bool
+attach_debugger( bool break_or_continue )
+{
+ if( under_debugger() )
+ return false;
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+ const int MAX_CMD_LINE = 200;
+
+ // *************************************************** //
+ // Debugger "ready" event
+
+ SECURITY_ATTRIBUTES attr;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = true;
+
+ // manual resettable, initially non signaled, unnamed event,
+ // that will signal me that debugger initialization is done
+ HANDLE dbg_init_done_ev = ::CreateEvent(
+ &attr, // pointer to security attributes
+ true, // flag for manual-reset event
+ false, // flag for initial state
+ NULL // pointer to event-object name
+ );
+
+ if( !dbg_init_done_ev )
+ return false;
+
+ // *************************************************** //
+ // Debugger command line format
+
+ HKEY reg_key;
+
+ if( !s_info.m_reg_open_key || (*s_info.m_reg_open_key)(
+ HKEY_LOCAL_MACHINE, // handle of open key
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", // name of subkey to open
+ ®_key ) != ERROR_SUCCESS ) // address of handle of open key
+ return false;
+
+ char format[MAX_CMD_LINE];
+ DWORD format_size = MAX_CMD_LINE;
+ DWORD type = REG_SZ;
+
+ if( !s_info.m_reg_query_value || (*s_info.m_reg_query_value)(
+ reg_key, // handle of open key
+ "Debugger", // name of subkey to query
+ 0, // reserved
+ &type, // value type
+ (LPBYTE)format, // buffer for returned string
+ &format_size ) != ERROR_SUCCESS ) // in: buffer size; out: actual size of returned string
+ return false;
+
+ if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS )
+ return false;
+
+ // *************************************************** //
+ // Debugger command line
+
+ char cmd_line[MAX_CMD_LINE];
+ std::sprintf( cmd_line, format, ::GetCurrentProcessId(), dbg_init_done_ev );
+
+ // *************************************************** //
+ // Debugger window parameters
+
+ STARTUPINFOA startup_info;
+ std::memset( &startup_info, 0, sizeof(startup_info) );
+
+ startup_info.cb = sizeof(startup_info);
+ startup_info.dwFlags = STARTF_USESHOWWINDOW;
+ startup_info.wShowWindow = SW_SHOWNORMAL;
+
+ // debugger process s_info
+ PROCESS_INFORMATION debugger_info;
+
+ bool created = !!::CreateProcessA(
+ NULL, // pointer to name of executable module; NULL - use the one in command line
+ cmd_line, // pointer to command line string
+ NULL, // pointer to process security attributes; NULL - debugger's handle can't be inherited
+ NULL, // pointer to thread security attributes; NULL - debugger's handle can't be inherited
+ true, // debugger inherit opened handles
+ 0, // priority flags; 0 - normal priority
+ NULL, // pointer to new environment block; NULL - use this process environment
+ NULL, // pointer to current directory name; NULL - use this process correct directory
+ &startup_info, // pointer to STARTUPINFO that specifies main window appearance
+ &debugger_info // pointer to PROCESS_INFORMATION that will contain the new process identification
+ );
+
+ if( created )
+ ::WaitForSingleObject( dbg_init_done_ev, INFINITE );
+
+ ::CloseHandle( dbg_init_done_ev );
+
+ if( !created )
+ return false;
+
+ if( break_or_continue )
+ debugger_break();
+
+ return true;
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ char init_done_lock_fn[] = "/tmp/btl_dbg_init_done_XXXXXX";
+ fd_holder init_done_lock_fd( ::mkstemp( init_done_lock_fn ) );
+
+ if( init_done_lock_fd == -1 )
+ return false;
+
+ pid_t child_pid = fork();
+
+ if( child_pid == -1 )
+ return false;
+
+ if( child_pid != 0 ) { // parent process - here we will start the debugger
+ dbg_startup_info dsi;
+
+ process_info pi( child_pid );
+ if( pi.binary_path().is_empty() )
+ ::exit( -1 );
+
+ dsi.pid = child_pid;
+ dsi.break_or_continue = break_or_continue;
+ dsi.binary_path = pi.binary_path();
+ dsi.display = ::getenv( "DISPLAY" );
+ dsi.init_done_lock = init_done_lock_fn;
+
+ dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg];
+ if( !!starter )
+ starter( dsi );
+
+ ::perror( "Boost.Test execution monitor failed to start a debugger:" );
+
+ ::exit( -1 );
+ }
+
+ // child process - here we will continue our test module execution ; // !! ?? should it be vice versa
+
+ while( ::access( init_done_lock_fn, F_OK ) == 0 ) {
+ struct timeval to = { 0, 100 };
+
+ ::select( 0, 0, 0, 0, &to );
+ }
+
+// char dummy;
+// while( ::read( init_done_lock_fd, &dummy, sizeof(char) ) == 0 );
+
+ if( break_or_continue )
+ debugger_break();
+
+ return true;
+
+#else // ****************************************************** default
+
+ return false;
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** switch on/off detect memory leaks feature ************** //
+// ************************************************************************** //
+
+void
+detect_memory_leaks( bool on_off )
+{
+ unit_test::ut_detail::ignore_unused_variable_warning( on_off );
+
+#ifdef BOOST_MS_CRT_BASED_DEBUG
+ int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
+
+ if( !on_off )
+ flags &= ~_CRTDBG_LEAK_CHECK_DF;
+ else {
+ flags |= _CRTDBG_LEAK_CHECK_DF;
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
+ }
+
+ _CrtSetDbgFlag ( flags );
+#endif // BOOST_MS_CRT_BASED_DEBUG
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** cause program to break execution in ************** //
+// ************** debugger at specific allocation point ************** //
+// ************************************************************************** //
+
+void
+break_memory_alloc( long mem_alloc_order_num )
+{
+ unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num );
+
+#ifdef BOOST_MS_CRT_BASED_DEBUG
+ _CrtSetBreakAlloc( mem_alloc_order_num );
+#endif // BOOST_MS_CRT_BASED_DEBUG
+}
+
+} // namespace debug
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_DEBUG_API_IPP_112006GER
+
diff --git a/ndnboost/test/impl/exception_safety.ipp b/ndnboost/test/impl/exception_safety.ipp
new file mode 100644
index 0000000..c3680a9
--- /dev/null
+++ b/ndnboost/test/impl/exception_safety.ipp
@@ -0,0 +1,537 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Use, modification, and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : Facilities to perform exception safety tests
+// ***************************************************************************
+
+#ifndef BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
+#define BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+
+#if BOOST_TEST_SUPPORT_INTERACTION_TESTING
+
+#include <ndnboost/test/detail/global_typedef.hpp>
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+#include <ndnboost/test/utils/callback.hpp>
+#include <ndnboost/test/utils/wrap_stringstream.hpp>
+#include <ndnboost/test/utils/iterator/token_iterator.hpp>
+
+#include <ndnboost/test/interaction_based.hpp>
+#include <ndnboost/test/test_tools.hpp>
+#include <ndnboost/test/unit_test_log.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/test_observer.hpp>
+#include <ndnboost/test/debug.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+// Boost
+#include <ndnboost/lexical_cast.hpp>
+
+// STL
+#include <vector>
+#include <cstdlib>
+#include <map>
+#include <iomanip>
+#include <cctype>
+#include <ndnboost/limits.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+using namespace ::ndnboost::unit_test;
+
+namespace itest {
+
+// ************************************************************************** //
+// ************** execution_path_point ************** //
+// ************************************************************************** //
+
+enum exec_path_point_type { EPP_SCOPE, EPP_EXCEPT, EPP_DECISION, EPP_ALLOC };
+
+struct execution_path_point {
+ execution_path_point( exec_path_point_type t, const_string file, std::size_t line_num )
+ : m_type( t )
+ , m_file_name( file )
+ , m_line_num( line_num )
+ {}
+
+ exec_path_point_type m_type;
+ const_string m_file_name;
+ std::size_t m_line_num;
+
+ // Execution path point specific
+ struct decision_data {
+ bool value;
+ unsigned forced_exception_point;
+ };
+ struct scope_data {
+ unsigned size;
+ char const* name;
+ };
+ struct except_data {
+ char const* description;
+ };
+ struct alloc_data {
+ void* ptr;
+ std::size_t size;
+ };
+
+ union {
+ struct decision_data m_decision;
+ struct scope_data m_scope;
+ struct except_data m_except;
+ struct alloc_data m_alloc;
+ };
+};
+
+// ************************************************************************** //
+// ************** exception safety test implementation ************** //
+// ************************************************************************** //
+
+struct exception_safety_tester : itest::manager, test_observer {
+ // helpers types
+ struct unique_exception {};
+
+ // Constructor
+ explicit exception_safety_tester( const_string test_name );
+ ~exception_safety_tester();
+
+ // check last run and prepare for next
+ bool next_execution_path();
+
+ // memory tracking
+
+ // manager interface implementation
+ virtual void exception_point( const_string file, std::size_t line_num, const_string description );
+ virtual bool decision_point( const_string file, std::size_t line_num );
+ virtual unsigned enter_scope( const_string file, std::size_t line_num, const_string scope_name );
+ virtual void leave_scope( unsigned enter_scope_point );
+ virtual void allocated( const_string file, std::size_t line_num, void* p, std::size_t s );
+ virtual void freed( void* p );
+
+ // test observer interface
+ virtual void assertion_result( bool passed );
+ virtual int priority() { return (std::numeric_limits<int>::max)(); } // we want this observer to run the last
+
+private:
+ void failure_point();
+ void report_error();
+
+ typedef std::vector<execution_path_point> exec_path;
+ typedef std::map<void*,unsigned> registry;
+
+ // Data members
+ bool m_internal_activity;
+
+ unsigned m_exception_point_counter;
+ unsigned m_forced_exception_point;
+
+ unsigned m_exec_path_point;
+ exec_path m_execution_path;
+
+ unsigned m_exec_path_counter;
+ unsigned m_break_exec_path;
+
+ bool m_invairant_failed;
+ registry m_memory_in_use;
+};
+
+//____________________________________________________________________________//
+
+struct activity_guard {
+ bool& m_v;
+
+ activity_guard( bool& v ) : m_v( v ) { m_v = true; }
+ ~activity_guard() { m_v = false; }
+};
+
+//____________________________________________________________________________//
+
+exception_safety_tester::exception_safety_tester( const_string test_name )
+: m_internal_activity( true )
+, m_exception_point_counter( 0 )
+, m_forced_exception_point( 1 )
+, m_exec_path_point( 0 )
+, m_exec_path_counter( 1 )
+, m_break_exec_path( static_cast<unsigned>(-1) )
+, m_invairant_failed( false )
+{
+ framework::register_observer( *this );
+
+ if( !runtime_config::break_exec_path().is_empty() ) {
+ using namespace unit_test;
+
+ string_token_iterator tit( runtime_config::break_exec_path(),
+ (dropped_delimeters = ":",kept_delimeters = " ") );
+
+ const_string test_to_break = *tit;
+
+ if( test_to_break == test_name ) {
+ ++tit;
+
+ m_break_exec_path = lexical_cast<unsigned>( *tit );
+ }
+ }
+
+ m_internal_activity = false;
+}
+
+//____________________________________________________________________________//
+
+exception_safety_tester::~exception_safety_tester()
+{
+ m_internal_activity = true;
+
+ framework::deregister_observer( *this );
+}
+
+//____________________________________________________________________________//
+
+bool
+exception_safety_tester::next_execution_path()
+{
+ activity_guard ag( m_internal_activity );
+
+ // check memory usage
+ if( m_execution_path.size() > 0 ) {
+ bool errors_detected = m_invairant_failed || (m_memory_in_use.size() != 0);
+ framework::assertion_result( !errors_detected );
+
+ if( errors_detected )
+ report_error();
+
+ m_memory_in_use.clear();
+ }
+
+ m_exec_path_point = 0;
+ m_exception_point_counter = 0;
+ m_invairant_failed = false;
+ ++m_exec_path_counter;
+
+ while( m_execution_path.size() > 0 ) {
+ switch( m_execution_path.back().m_type ) {
+ case EPP_SCOPE:
+ case EPP_ALLOC:
+ m_execution_path.pop_back();
+ break;
+
+ case EPP_DECISION:
+ if( !m_execution_path.back().m_decision.value ) {
+ m_execution_path.pop_back();
+ break;
+ }
+
+ m_execution_path.back().m_decision.value = false;
+ m_forced_exception_point = m_execution_path.back().m_decision.forced_exception_point;
+ return true;
+
+ case EPP_EXCEPT:
+ m_execution_path.pop_back();
+ ++m_forced_exception_point;
+ return true;
+ }
+ }
+
+ BOOST_TEST_MESSAGE( "Total tested " << --m_exec_path_counter << " execution path" );
+
+ return false;
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::exception_point( const_string file, std::size_t line_num, const_string description )
+{
+ activity_guard ag( m_internal_activity );
+
+ if( ++m_exception_point_counter == m_forced_exception_point ) {
+ m_execution_path.push_back(
+ execution_path_point( EPP_EXCEPT, file, line_num ) );
+
+ m_execution_path.back().m_except.description = description.begin();
+
+ ++m_exec_path_point;
+
+ failure_point();
+ }
+}
+
+//____________________________________________________________________________//
+
+bool
+exception_safety_tester::decision_point( const_string file, std::size_t line_num )
+{
+ activity_guard ag( m_internal_activity );
+
+ if( m_exec_path_point < m_execution_path.size() ) {
+ BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_DECISION &&
+ m_execution_path[m_exec_path_point].m_file_name == file &&
+ m_execution_path[m_exec_path_point].m_line_num == line_num,
+ "Function under test exibit non-deterministic behavior" );
+ }
+ else {
+ m_execution_path.push_back(
+ execution_path_point( EPP_DECISION, file, line_num ) );
+
+ m_execution_path.back().m_decision.value = true;
+ m_execution_path.back().m_decision.forced_exception_point = m_forced_exception_point;
+ }
+
+ return m_execution_path[m_exec_path_point++].m_decision.value;
+}
+
+//____________________________________________________________________________//
+
+unsigned
+exception_safety_tester::enter_scope( const_string file, std::size_t line_num, const_string scope_name )
+{
+ activity_guard ag( m_internal_activity );
+
+ if( m_exec_path_point < m_execution_path.size() ) {
+ BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_SCOPE &&
+ m_execution_path[m_exec_path_point].m_file_name == file &&
+ m_execution_path[m_exec_path_point].m_line_num == line_num,
+ "Function under test exibit non-deterministic behavior" );
+ }
+ else {
+ m_execution_path.push_back(
+ execution_path_point( EPP_SCOPE, file, line_num ) );
+ }
+
+ m_execution_path[m_exec_path_point].m_scope.size = 0;
+ m_execution_path[m_exec_path_point].m_scope.name = scope_name.begin();
+
+ return m_exec_path_point++;
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::leave_scope( unsigned enter_scope_point )
+{
+ activity_guard ag( m_internal_activity );
+
+ BOOST_REQUIRE_MESSAGE( m_execution_path[enter_scope_point].m_type == EPP_SCOPE,
+ "Function under test exibit non-deterministic behavior" );
+
+ m_execution_path[enter_scope_point].m_scope.size = m_exec_path_point - enter_scope_point;
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::allocated( const_string file, std::size_t line_num, void* p, std::size_t s )
+{
+ if( m_internal_activity )
+ return;
+
+ activity_guard ag( m_internal_activity );
+
+ if( m_exec_path_point < m_execution_path.size() )
+ BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_ALLOC,
+ "Function under test exibit non-deterministic behavior" );
+ else
+ m_execution_path.push_back(
+ execution_path_point( EPP_ALLOC, file, line_num ) );
+
+ m_execution_path[m_exec_path_point].m_alloc.ptr = p;
+ m_execution_path[m_exec_path_point].m_alloc.size = s;
+
+ m_memory_in_use.insert( std::make_pair( p, m_exec_path_point++ ) );
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::freed( void* p )
+{
+ if( m_internal_activity )
+ return;
+
+ activity_guard ag( m_internal_activity );
+
+ registry::iterator it = m_memory_in_use.find( p );
+ if( it != m_memory_in_use.end() ) {
+ m_execution_path[it->second].m_alloc.ptr = 0;
+ m_memory_in_use.erase( it );
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::assertion_result( bool passed )
+{
+ if( !m_internal_activity && !passed ) {
+ m_invairant_failed = true;
+
+ failure_point();
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+exception_safety_tester::failure_point()
+{
+ if( m_exec_path_counter == m_break_exec_path )
+ debug::debugger_break();
+
+ throw unique_exception();
+}
+
+//____________________________________________________________________________//
+
+namespace {
+
+inline void
+format_location( wrap_stringstream& formatter, execution_path_point const& /*p*/, unsigned indent )
+{
+ if( indent )
+ formatter << std::left << std::setw( indent ) << "";
+
+// !! ?? optional if( p.m_file_name )
+// formatter << p.m_file_name << '(' << p.m_line_num << "): ";
+}
+
+//____________________________________________________________________________//
+
+template<typename ExecPathIt>
+inline void
+format_execution_path( wrap_stringstream& formatter, ExecPathIt it, ExecPathIt end, unsigned indent = 0 )
+{
+ while( it != end ) {
+ switch( it->m_type ) {
+ case EPP_SCOPE:
+ format_location( formatter, *it, indent );
+ formatter << "> \"" << it->m_scope.name << "\"\n";
+ format_execution_path( formatter, it+1, it + it->m_scope.size, indent + 2 );
+ format_location( formatter, *it, indent );
+ formatter << "< \"" << it->m_scope.name << "\"\n";
+ it += it->m_scope.size;
+ break;
+
+ case EPP_DECISION:
+ format_location( formatter, *it, indent );
+ formatter << "Decision made as " << std::boolalpha << it->m_decision.value << '\n';
+ ++it;
+ break;
+
+ case EPP_EXCEPT:
+ format_location( formatter, *it, indent );
+ formatter << "Forced failure";
+ if( it->m_except.description )
+ formatter << ": " << it->m_except.description;
+ formatter << "\n";
+ ++it;
+ break;
+
+ case EPP_ALLOC:
+ if( it->m_alloc.ptr ) {
+ format_location( formatter, *it, indent );
+ formatter << "Allocated memory block 0x" << std::uppercase << it->m_alloc.ptr
+ << ", " << it->m_alloc.size << " bytes long: <";
+
+ unsigned i;
+ for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) {
+ unsigned char c = static_cast<unsigned char*>(it->m_alloc.ptr)[i];
+ if( (std::isprint)( c ) )
+ formatter << c;
+ else
+ formatter << '.';
+ }
+
+ formatter << "> ";
+
+ for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) {
+ unsigned c = static_cast<unsigned char*>(it->m_alloc.ptr)[i];
+ formatter << std::hex << std::uppercase << c << ' ';
+ }
+
+ formatter << "\n";
+ }
+ ++it;
+ break;
+ }
+ }
+}
+
+//____________________________________________________________________________//
+
+} // local namespace
+
+void
+exception_safety_tester::report_error()
+{
+ activity_guard ag( m_internal_activity );
+
+ unit_test_log << unit_test::log::begin( m_execution_path.back().m_file_name,
+ m_execution_path.back().m_line_num )
+ << log_all_errors;
+
+ wrap_stringstream formatter;
+
+ if( m_invairant_failed )
+ formatter << "Failed invariant";
+
+ if( m_memory_in_use.size() != 0 ) {
+ if( m_invairant_failed )
+ formatter << " and ";
+
+ formatter << static_cast<unsigned int>(m_memory_in_use.size()) << " memory leak";
+ if( m_memory_in_use.size() > 1 )
+ formatter << 's';
+ }
+ formatter << " detected in the execution path " << m_exec_path_counter << ":\n";
+
+ format_execution_path( formatter, m_execution_path.begin(), m_execution_path.end() );
+
+ unit_test_log << const_string( formatter.str() ) << unit_test::log::end();
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** exception safety test ************** //
+// ************************************************************************** //
+
+void BOOST_TEST_DECL
+exception_safety( callback0<> const& F, const_string test_name )
+{
+ exception_safety_tester est( test_name );
+
+ do {
+ try {
+ F();
+ }
+ catch( exception_safety_tester::unique_exception const& ) {}
+
+ } while( est.next_execution_path() );
+}
+
+//____________________________________________________________________________//
+
+} // namespace itest
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // non-ancient compiler
+
+#endif // BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
diff --git a/ndnboost/test/impl/execution_monitor.ipp b/ndnboost/test/impl/execution_monitor.ipp
new file mode 100644
index 0000000..5337347
--- /dev/null
+++ b/ndnboost/test/impl/execution_monitor.ipp
@@ -0,0 +1,1367 @@
+// (C) Copyright Gennadiy Rozental 2001-2008.
+// (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001.
+// Use, modification, and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : provides execution monitor implementation for all supported
+// configurations, including Microsoft structured exception based, unix signals
+// based and special workarounds for borland
+//
+// Note that when testing requirements or user wishes preclude use of this
+// file as a separate compilation unit, it may be included as a header file.
+//
+// Header dependencies are deliberately restricted to reduce coupling to other
+// boost libraries.
+// ***************************************************************************
+
+#ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
+#define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+#include <ndnboost/test/detail/workaround.hpp>
+#include <ndnboost/test/execution_monitor.hpp>
+#include <ndnboost/test/debug.hpp>
+
+// Boost
+#include <ndnboost/cstdlib.hpp> // for exit codes
+#include <ndnboost/config.hpp> // for workarounds
+#include <ndnboost/exception/get_error_info.hpp> // for get_error_info
+#include <ndnboost/exception/current_exception_cast.hpp> // for current_exception_cast
+
+// STL
+#include <string> // for std::string
+#include <new> // for std::bad_alloc
+#include <typeinfo> // for std::bad_cast, std::bad_typeid
+#include <exception> // for std::exception, std::bad_exception
+#include <stdexcept> // for std exception hierarchy
+#include <cstring> // for C string API
+#include <cassert> // for assert
+#include <cstddef> // for NULL
+#include <cstdio> // for vsnprintf
+#include <cstdarg> // for varargs
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::strerror; using ::strlen; using ::strncat; }
+#endif
+
+// to use vsnprintf
+#if defined(__SUNPRO_CC) || defined(__SunOS)
+# include <stdio.h>
+# include <stdarg.h>
+using std::va_list;
+#endif
+
+// to use vsnprintf
+#if defined(__QNXNTO__)
+# include <stdio.h>
+#endif
+
+#if defined(_WIN32) && !defined(BOOST_DISABLE_WIN32) && \
+ (!defined(__COMO__) && !defined(__MWERKS__) && !defined(__GNUC__) || \
+ BOOST_WORKAROUND(__MWERKS__, >= 0x3000))
+
+# define BOOST_SEH_BASED_SIGNAL_HANDLING
+
+# include <windows.h>
+
+# if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE))
+# include <eh.h>
+# endif
+
+# if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 || defined(__MWERKS__)
+# include <stdint.h>
+# endif
+
+# if defined(__BORLANDC__) && __BORLANDC__ < 0x560
+ typedef unsigned uintptr_t;
+# endif
+
+# if BOOST_WORKAROUND(_MSC_VER, < 1300 ) || defined(UNDER_CE)
+typedef void* uintptr_t;
+# endif
+
+// for the FP control routines
+#include <float.h>
+
+#ifndef EM_INVALID
+#define EM_INVALID _EM_INVALID
+#endif
+
+#ifndef EM_DENORMAL
+#define EM_DENORMAL _EM_DENORMAL
+#endif
+
+#ifndef EM_ZERODIVIDE
+#define EM_ZERODIVIDE _EM_ZERODIVIDE
+#endif
+
+#ifndef EM_OVERFLOW
+#define EM_OVERFLOW _EM_OVERFLOW
+#endif
+
+#ifndef EM_UNDERFLOW
+#define EM_UNDERFLOW _EM_UNDERFLOW
+#endif
+
+#ifndef MCW_EM
+#define MCW_EM _MCW_EM
+#endif
+
+# if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE)
+# include <crtdbg.h>
+# define BOOST_TEST_CRT_HOOK_TYPE _CRT_REPORT_HOOK
+# define BOOST_TEST_CRT_ASSERT _CRT_ASSERT
+# define BOOST_TEST_CRT_ERROR _CRT_ERROR
+# define BOOST_TEST_CRT_SET_HOOK(H) _CrtSetReportHook(H)
+# else
+# define BOOST_TEST_CRT_HOOK_TYPE void*
+# define BOOST_TEST_CRT_ASSERT 2
+# define BOOST_TEST_CRT_ERROR 1
+# define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H)
+# endif
+
+# if !BOOST_WORKAROUND(_MSC_VER, >= 1400 ) || defined(UNDER_CE)
+
+typedef void* _invalid_parameter_handler;
+
+inline _invalid_parameter_handler
+_set_invalid_parameter_handler( _invalid_parameter_handler arg )
+{
+ return arg;
+}
+
+# endif
+
+# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE)
+
+namespace { void _set_se_translator( void* ) {} }
+
+# endif
+
+#elif defined(BOOST_HAS_SIGACTION)
+
+# define BOOST_SIGACTION_BASED_SIGNAL_HANDLING
+
+# include <unistd.h>
+# include <signal.h>
+# include <setjmp.h>
+
+# if defined(__FreeBSD__)
+
+# ifndef SIGPOLL
+# define SIGPOLL SIGIO
+# endif
+
+# if (__FreeBSD_version < 70100)
+
+# define ILL_ILLADR 0 // ILL_RESAD_FAULT
+# define ILL_PRVOPC ILL_PRIVIN_FAULT
+# define ILL_ILLOPN 2 // ILL_RESOP_FAULT
+# define ILL_COPROC ILL_FPOP_FAULT
+
+# define BOOST_TEST_LIMITED_SIGNAL_DETAILS
+# define BOOST_TEST_IGNORE_SIGCHLD
+
+# endif
+# endif
+
+# if !defined(__CYGWIN__) && !defined(__QNXNTO__)
+# define BOOST_TEST_USE_ALT_STACK
+# endif
+
+# if defined(SIGPOLL) && !defined(__CYGWIN__) && \
+ !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && \
+ !defined(__NetBSD__) && \
+ !defined(__QNXNTO__)
+# define BOOST_TEST_CATCH_SIGPOLL
+# endif
+
+# ifdef BOOST_TEST_USE_ALT_STACK
+# define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ
+# endif
+
+#else
+
+# define BOOST_NO_SIGNAL_HANDLING
+
+#endif
+
+#ifndef UNDER_CE
+#include <errno.h>
+#endif
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+// ************************************************************************** //
+// ************** report_error ************** //
+// ************************************************************************** //
+
+namespace detail {
+
+#ifdef __BORLANDC__
+# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) )
+#elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \
+ BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \
+ defined(UNDER_CE)
+# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) )
+#else
+# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) )
+#endif
+
+template <typename ErrorInfo>
+typename ErrorInfo::value_type
+extract( ndnboost::exception const* ex )
+{
+ if( !ex )
+ return 0;
+
+ typename ErrorInfo::value_type const * val = ndnboost::get_error_info<ErrorInfo>( *ex );
+
+ return val ? *val : 0;
+}
+
+//____________________________________________________________________________//
+
+static void
+report_error( execution_exception::error_code ec, ndnboost::exception const* be, char const* format, va_list* args )
+{
+ static const int REPORT_ERROR_BUFFER_SIZE = 512;
+ static char buf[REPORT_ERROR_BUFFER_SIZE];
+
+ BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args );
+ buf[sizeof(buf)-1] = 0;
+
+ va_end( *args );
+
+ throw execution_exception( ec, buf, execution_exception::location( extract<throw_file>( be ),
+ extract<throw_line>( be ),
+ extract<throw_function>( be ) ) );
+}
+
+//____________________________________________________________________________//
+
+static void
+report_error( execution_exception::error_code ec, char const* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+
+ report_error( ec, 0, format, &args );
+}
+
+//____________________________________________________________________________//
+
+static void
+report_error( execution_exception::error_code ec, ndnboost::exception const* be, char const* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+
+ report_error( ec, be, format, &args );
+}
+
+//____________________________________________________________________________//
+
+template<typename Tr,typename Functor>
+inline int
+do_invoke( Tr const& tr, Functor const& F )
+{
+ return tr ? (*tr)( F ) : F();
+}
+
+//____________________________________________________________________________//
+
+} // namespace detail
+
+#if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING)
+
+// ************************************************************************** //
+// ************** Sigaction based signal handling ************** //
+// ************************************************************************** //
+
+namespace detail {
+
+// ************************************************************************** //
+// ************** ndnboost::detail::system_signal_exception ************** //
+// ************************************************************************** //
+
+class system_signal_exception {
+public:
+ // Constructor
+ system_signal_exception()
+ : m_sig_info( 0 )
+ , m_context( 0 )
+ {}
+
+ // Access methods
+ void operator()( siginfo_t* i, void* c )
+ {
+ m_sig_info = i;
+ m_context = c;
+ }
+ void report() const;
+
+private:
+ // Data members
+ siginfo_t* m_sig_info; // system signal detailed info
+ void* m_context; // signal context
+};
+
+//____________________________________________________________________________//
+
+void
+system_signal_exception::report() const
+{
+ if( !m_sig_info )
+ return; // no error actually occur?
+
+ switch( m_sig_info->si_code ) {
+ case SI_USER:
+ report_error( execution_exception::system_error,
+ "signal: generated by kill() (or family); uid=%d; pid=%d",
+ (int)m_sig_info->si_uid, (int)m_sig_info->si_pid );
+ break;
+ case SI_QUEUE:
+ report_error( execution_exception::system_error,
+ "signal: sent by sigqueue()" );
+ break;
+ case SI_TIMER:
+ report_error( execution_exception::system_error,
+ "signal: the expiration of a timer set by timer_settimer()" );
+ break;
+ case SI_ASYNCIO:
+ report_error( execution_exception::system_error,
+ "signal: generated by the completion of an asynchronous I/O request" );
+ break;
+ case SI_MESGQ:
+ report_error( execution_exception::system_error,
+ "signal: generated by the the arrival of a message on an empty message queue" );
+ break;
+ default:
+ break;
+ }
+
+ switch( m_sig_info->si_signo ) {
+ case SIGILL:
+ switch( m_sig_info->si_code ) {
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ case ILL_ILLOPC:
+ report_error( execution_exception::system_fatal_error,
+ "signal: illegal opcode; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_ILLTRP:
+ report_error( execution_exception::system_fatal_error,
+ "signal: illegal trap; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_PRVREG:
+ report_error( execution_exception::system_fatal_error,
+ "signal: privileged register; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_BADSTK:
+ report_error( execution_exception::system_fatal_error,
+ "signal: internal stack error; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+#endif
+ case ILL_ILLOPN:
+ report_error( execution_exception::system_fatal_error,
+ "signal: illegal operand; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_ILLADR:
+ report_error( execution_exception::system_fatal_error,
+ "signal: illegal addressing mode; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_PRVOPC:
+ report_error( execution_exception::system_fatal_error,
+ "signal: privileged opcode; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case ILL_COPROC:
+ report_error( execution_exception::system_fatal_error,
+ "signal: co-processor error; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ default:
+ report_error( execution_exception::system_fatal_error,
+ "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)",
+ m_sig_info->si_addr, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+ case SIGFPE:
+ switch( m_sig_info->si_code ) {
+ case FPE_INTDIV:
+ report_error( execution_exception::system_error,
+ "signal: integer divide by zero; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_INTOVF:
+ report_error( execution_exception::system_error,
+ "signal: integer overflow; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTDIV:
+ report_error( execution_exception::system_error,
+ "signal: floating point divide by zero; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTOVF:
+ report_error( execution_exception::system_error,
+ "signal: floating point overflow; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTUND:
+ report_error( execution_exception::system_error,
+ "signal: floating point underflow; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTRES:
+ report_error( execution_exception::system_error,
+ "signal: floating point inexact result; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTINV:
+ report_error( execution_exception::system_error,
+ "signal: invalid floating point operation; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ case FPE_FLTSUB:
+ report_error( execution_exception::system_error,
+ "signal: subscript out of range; address of failing instruction: 0x%08lx",
+ m_sig_info->si_addr );
+ break;
+ default:
+ report_error( execution_exception::system_error,
+ "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)",
+ m_sig_info->si_addr, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+ case SIGSEGV:
+ switch( m_sig_info->si_code ) {
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ case SEGV_MAPERR:
+ report_error( execution_exception::system_fatal_error,
+ "memory access violation at address: 0x%08lx: no mapping at fault address",
+ m_sig_info->si_addr );
+ break;
+ case SEGV_ACCERR:
+ report_error( execution_exception::system_fatal_error,
+ "memory access violation at address: 0x%08lx: invalid permissions",
+ m_sig_info->si_addr );
+ break;
+#endif
+ default:
+ report_error( execution_exception::system_fatal_error,
+ "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)",
+ m_sig_info->si_addr, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+ case SIGBUS:
+ switch( m_sig_info->si_code ) {
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ case BUS_ADRALN:
+ report_error( execution_exception::system_fatal_error,
+ "memory access violation at address: 0x%08lx: invalid address alignment",
+ m_sig_info->si_addr );
+ break;
+ case BUS_ADRERR:
+ report_error( execution_exception::system_fatal_error,
+ "memory access violation at address: 0x%08lx: non-existent physical address",
+ m_sig_info->si_addr );
+ break;
+ case BUS_OBJERR:
+ report_error( execution_exception::system_fatal_error,
+ "memory access violation at address: 0x%08lx: object specific hardware error",
+ m_sig_info->si_addr );
+ break;
+#endif
+ default:
+ report_error( execution_exception::system_fatal_error,
+ "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)",
+ m_sig_info->si_addr, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+ case SIGCHLD:
+ switch( m_sig_info->si_code ) {
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ case CLD_EXITED:
+ report_error( execution_exception::system_error,
+ "child has exited; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+ case CLD_KILLED:
+ report_error( execution_exception::system_error,
+ "child was killed; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+ case CLD_DUMPED:
+ report_error( execution_exception::system_error,
+ "child terminated abnormally; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+ case CLD_TRAPPED:
+ report_error( execution_exception::system_error,
+ "traced child has trapped; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+ case CLD_STOPPED:
+ report_error( execution_exception::system_error,
+ "child has stopped; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+ case CLD_CONTINUED:
+ report_error( execution_exception::system_error,
+ "stopped child had continued; pid: %d; uid: %d; exit value: %d",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status );
+ break;
+#endif
+ default:
+ report_error( execution_exception::system_error,
+ "signal: SIGCHLD, si_code: %d (child process has terminated; pid: %d; uid: %d; exit value: %d)",
+ (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+#if defined(BOOST_TEST_CATCH_SIGPOLL)
+
+ case SIGPOLL:
+ switch( m_sig_info->si_code ) {
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ case POLL_IN:
+ report_error( execution_exception::system_error,
+ "data input available; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+ case POLL_OUT:
+ report_error( execution_exception::system_error,
+ "output buffers available; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+ case POLL_MSG:
+ report_error( execution_exception::system_error,
+ "input message available; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+ case POLL_ERR:
+ report_error( execution_exception::system_error,
+ "i/o error; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+ case POLL_PRI:
+ report_error( execution_exception::system_error,
+ "high priority input available; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+#if defined(POLL_ERR) && defined(POLL_HUP) && (POLL_ERR - POLL_HUP)
+ case POLL_HUP:
+ report_error( execution_exception::system_error,
+ "device disconnected; band event %d",
+ (int)m_sig_info->si_band );
+ break;
+#endif
+#endif
+ default:
+ report_error( execution_exception::system_error,
+ "signal: SIGPOLL, si_code: %d (asynchronous I/O event occured; band event %d)",
+ (int)m_sig_info->si_band, m_sig_info->si_code );
+ break;
+ }
+ break;
+
+#endif
+
+ case SIGABRT:
+ report_error( execution_exception::system_error,
+ "signal: SIGABRT (application abort requested)" );
+ break;
+
+ case SIGALRM:
+ report_error( execution_exception::timeout_error,
+ "signal: SIGALRM (timeout while executing function)" );
+ break;
+
+ default:
+ report_error( execution_exception::system_error, "unrecognized signal" );
+ }
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** ndnboost::detail::signal_action ************** //
+// ************************************************************************** //
+
+// Forward declaration
+extern "C" {
+static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context );
+static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context );
+}
+
+class signal_action {
+ typedef struct sigaction* sigaction_ptr;
+public:
+ //Constructor
+ signal_action();
+ signal_action( int sig, bool install, bool attach_dbg, char* alt_stack );
+ ~signal_action();
+
+private:
+ // Data members
+ int m_sig;
+ bool m_installed;
+ struct sigaction m_new_action;
+ struct sigaction m_old_action;
+};
+
+//____________________________________________________________________________//
+
+signal_action::signal_action()
+: m_installed( false )
+{}
+
+//____________________________________________________________________________//
+
+signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_stack )
+: m_sig( sig )
+, m_installed( install )
+{
+ if( !install )
+ return;
+
+ std::memset( &m_new_action, 0, sizeof(struct sigaction) );
+
+ BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig , sigaction_ptr(), &m_new_action ) != -1 );
+
+ if( m_new_action.sa_sigaction || m_new_action.sa_handler ) {
+ m_installed = false;
+ return;
+ }
+
+ m_new_action.sa_flags |= SA_SIGINFO;
+ m_new_action.sa_sigaction = attach_dbg ? &execution_monitor_attaching_signal_handler
+ : &execution_monitor_jumping_signal_handler;
+ BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 );
+
+#ifdef BOOST_TEST_USE_ALT_STACK
+ if( alt_stack )
+ m_new_action.sa_flags |= SA_ONSTACK;
+#endif
+
+ BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig, &m_new_action, &m_old_action ) != -1 );
+}
+
+//____________________________________________________________________________//
+
+signal_action::~signal_action()
+{
+ if( m_installed )
+ ::sigaction( m_sig, &m_old_action , sigaction_ptr() );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** ndnboost::detail::signal_handler ************** //
+// ************************************************************************** //
+
+class signal_handler {
+public:
+ // Constructor
+ explicit signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack );
+
+ // Destructor
+ ~signal_handler();
+
+ // access methods
+ static sigjmp_buf& jump_buffer()
+ {
+ assert( !!s_active_handler );
+
+ return s_active_handler->m_sigjmp_buf;
+ }
+
+ static system_signal_exception& sys_sig()
+ {
+ assert( !!s_active_handler );
+
+ return s_active_handler->m_sys_sig;
+ }
+
+private:
+ // Data members
+ signal_handler* m_prev_handler;
+ int m_timeout;
+
+ signal_action m_ILL_action;
+ signal_action m_FPE_action;
+ signal_action m_SEGV_action;
+ signal_action m_BUS_action;
+ signal_action m_CHLD_action;
+ signal_action m_POLL_action;
+ signal_action m_ABRT_action;
+ signal_action m_ALRM_action;
+
+ sigjmp_buf m_sigjmp_buf;
+ system_signal_exception m_sys_sig;
+
+ static signal_handler* s_active_handler;
+};
+
+// !! need to be placed in thread specific storage
+typedef signal_handler* signal_handler_ptr;
+signal_handler* signal_handler::s_active_handler = signal_handler_ptr();
+
+//____________________________________________________________________________//
+
+signal_handler::signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack )
+: m_prev_handler( s_active_handler )
+, m_timeout( timeout )
+, m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack )
+, m_FPE_action ( SIGFPE , catch_system_errors, attach_dbg, alt_stack )
+, m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack )
+, m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack )
+#ifndef BOOST_TEST_IGNORE_SIGCHLD
+, m_CHLD_action( SIGCHLD, catch_system_errors, attach_dbg, alt_stack )
+#endif
+#ifdef BOOST_TEST_CATCH_SIGPOLL
+, m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack )
+#endif
+, m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack )
+, m_ALRM_action( SIGALRM, timeout > 0 , attach_dbg, alt_stack )
+{
+ s_active_handler = this;
+
+ if( m_timeout > 0 ) {
+ ::alarm( 0 );
+ ::alarm( timeout );
+ }
+
+#ifdef BOOST_TEST_USE_ALT_STACK
+ if( alt_stack ) {
+ stack_t sigstk;
+ std::memset( &sigstk, 0, sizeof(stack_t) );
+
+ BOOST_TEST_SYS_ASSERT( ::sigaltstack( 0, &sigstk ) != -1 );
+
+ if( sigstk.ss_flags & SS_DISABLE ) {
+ sigstk.ss_sp = alt_stack;
+ sigstk.ss_size = BOOST_TEST_ALT_STACK_SIZE;
+ sigstk.ss_flags = 0;
+ BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 );
+ }
+ }
+#endif
+}
+
+//____________________________________________________________________________//
+
+signal_handler::~signal_handler()
+{
+ assert( s_active_handler == this );
+
+ if( m_timeout > 0 )
+ ::alarm( 0 );
+
+#ifdef BOOST_TEST_USE_ALT_STACK
+#ifdef __GNUC__
+ // We shouldn't need to explicitly initialize all the members here,
+ // but gcc warns if we don't, so add initializers for each of the
+ // members specified in the POSIX std:
+ stack_t sigstk = { 0, 0, 0 };
+#else
+ stack_t sigstk = { };
+#endif
+
+ sigstk.ss_size = MINSIGSTKSZ;
+ sigstk.ss_flags = SS_DISABLE;
+ BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 );
+#endif
+
+ s_active_handler = m_prev_handler;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** execution_monitor_signal_handler ************** //
+// ************************************************************************** //
+
+extern "C" {
+
+static bool ignore_sigchild( siginfo_t* info )
+{
+ return info->si_signo == SIGCHLD
+#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS
+ && info->si_code == CLD_EXITED
+#endif
+#ifdef BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE
+ ;
+#else
+ && (int)info->si_status == 0;
+#endif
+}
+
+//____________________________________________________________________________//
+
+static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context )
+{
+ if( ignore_sigchild( info ) )
+ return;
+
+ signal_handler::sys_sig()( info, context );
+
+ siglongjmp( signal_handler::jump_buffer(), sig );
+}
+
+//____________________________________________________________________________//
+
+static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context )
+{
+ if( ignore_sigchild( info ) )
+ return;
+
+ if( !debug::attach_debugger( false ) )
+ execution_monitor_jumping_signal_handler( sig, info, context );
+
+ // debugger attached; it will handle the signal
+ BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR );
+}
+
+//____________________________________________________________________________//
+
+}
+
+} // namespace detail
+
+// ************************************************************************** //
+// ************** execution_monitor::catch_signals ************** //
+// ************************************************************************** //
+
+int
+execution_monitor::catch_signals( unit_test::callback0<int> const& F )
+{
+ using namespace detail;
+
+#if defined(__CYGWIN__)
+ p_catch_system_errors.value = false;
+#endif
+
+#ifdef BOOST_TEST_USE_ALT_STACK
+ if( !!p_use_alt_stack && !m_alt_stack )
+ m_alt_stack.reset( new char[BOOST_TEST_ALT_STACK_SIZE] );
+#else
+ p_use_alt_stack.value = false;
+#endif
+
+ signal_handler local_signal_handler( p_catch_system_errors, p_timeout, p_auto_start_dbg,
+ !p_use_alt_stack ? 0 : m_alt_stack.get() );
+
+ if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) )
+ return detail::do_invoke( m_custom_translators , F );
+ else
+ throw local_signal_handler.sys_sig();
+}
+
+//____________________________________________________________________________//
+
+#elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING)
+
+// ************************************************************************** //
+// ************** Microsoft structured exception handling ************** //
+// ************************************************************************** //
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564))
+namespace { void _set_se_translator( void* ) {} }
+#endif
+
+namespace detail {
+
+// ************************************************************************** //
+// ************** ndnboost::detail::system_signal_exception ************** //
+// ************************************************************************** //
+
+class system_signal_exception {
+public:
+ // Constructor
+ explicit system_signal_exception( execution_monitor* em )
+ : m_em( em )
+ , m_se_id( 0 )
+ , m_fault_address( 0 )
+ , m_dir( false )
+ {}
+
+ void report() const;
+ int operator()( unsigned int id, _EXCEPTION_POINTERS* exps );
+
+private:
+ // Data members
+ execution_monitor* m_em;
+
+ unsigned int m_se_id;
+ void* m_fault_address;
+ bool m_dir;
+};
+
+static void
+seh_catch_preventer( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ )
+{
+ throw;
+}
+
+//____________________________________________________________________________//
+
+int
+system_signal_exception::operator()( unsigned int id, _EXCEPTION_POINTERS* exps )
+{
+ const unsigned int MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC
+
+ if( !m_em->p_catch_system_errors || (id == MSFT_CPP_EXCEPT) )
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) {
+ m_em->p_catch_system_errors.value = false;
+ _set_se_translator( &seh_catch_preventer );
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ m_se_id = id;
+ if( m_se_id == EXCEPTION_ACCESS_VIOLATION && exps->ExceptionRecord->NumberParameters == 2 ) {
+ m_fault_address = (void*)exps->ExceptionRecord->ExceptionInformation[1];
+ m_dir = exps->ExceptionRecord->ExceptionInformation[0] == 0;
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+//____________________________________________________________________________//
+
+void
+system_signal_exception::report() const
+{
+ switch( m_se_id ) {
+ // cases classified as system_fatal_error
+ case EXCEPTION_ACCESS_VIOLATION: {
+ if( !m_fault_address )
+ detail::report_error( execution_exception::system_fatal_error, "memory access violation" );
+ else
+ detail::report_error(
+ execution_exception::system_fatal_error,
+ "memory access violation occurred at address 0x%08lx, while attempting to %s",
+ m_fault_address,
+ m_dir ? " read inaccessible data"
+ : " write to an inaccessible (or protected) address"
+ );
+ break;
+ }
+
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ detail::report_error( execution_exception::system_fatal_error, "illegal instruction" );
+ break;
+
+ case EXCEPTION_PRIV_INSTRUCTION:
+ detail::report_error( execution_exception::system_fatal_error, "tried to execute an instruction whose operation is not allowed in the current machine mode" );
+ break;
+
+ case EXCEPTION_IN_PAGE_ERROR:
+ detail::report_error( execution_exception::system_fatal_error, "access to a memory page that is not present" );
+ break;
+
+ case EXCEPTION_STACK_OVERFLOW:
+ detail::report_error( execution_exception::system_fatal_error, "stack overflow" );
+ break;
+
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ detail::report_error( execution_exception::system_fatal_error, "tried to continue execution after a non continuable exception occurred" );
+ break;
+
+ // cases classified as (non-fatal) system_trap
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ detail::report_error( execution_exception::system_error, "data misalignment" );
+ break;
+
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ detail::report_error( execution_exception::system_error, "integer divide by zero" );
+ break;
+
+ case EXCEPTION_INT_OVERFLOW:
+ detail::report_error( execution_exception::system_error, "integer overflow" );
+ break;
+
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ detail::report_error( execution_exception::system_error, "array bounds exceeded" );
+ break;
+
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ detail::report_error( execution_exception::system_error, "floating point divide by zero" );
+ break;
+
+ case EXCEPTION_FLT_STACK_CHECK:
+ detail::report_error( execution_exception::system_error,
+ "stack overflowed or underflowed as the result of a floating-point operation" );
+ break;
+
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ detail::report_error( execution_exception::system_error,
+ "operand of floating point operation is denormal" );
+ break;
+
+# if 0 // !! ??
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ detail::report_error( execution_exception::system_error,
+ "result of a floating-point operation cannot be represented exactly" );
+ break;
+#endif
+
+ case EXCEPTION_FLT_OVERFLOW:
+ detail::report_error( execution_exception::system_error,
+ "exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type" );
+ break;
+
+ case EXCEPTION_FLT_UNDERFLOW:
+ detail::report_error( execution_exception::system_error,
+ "exponent of a floating-point operation is less than the magnitude allowed by the corresponding type" );
+ break;
+
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ detail::report_error( execution_exception::system_error, "floating point error" );
+ break;
+
+ case EXCEPTION_BREAKPOINT:
+ detail::report_error( execution_exception::system_error, "breakpoint encountered" );
+ break;
+
+ default:
+ detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id );
+ break;
+ }
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** assert_reporting_function ************** //
+// ************************************************************************** //
+
+int BOOST_TEST_CALL_DECL
+assert_reporting_function( int reportType, char* userMessage, int* )
+{
+ switch( reportType ) {
+ case BOOST_TEST_CRT_ASSERT:
+ detail::report_error( execution_exception::user_error, userMessage );
+
+ return 1; // return value and retVal are not important since we never reach this line
+ case BOOST_TEST_CRT_ERROR:
+ detail::report_error( execution_exception::system_error, userMessage );
+
+ return 1; // return value and retVal are not important since we never reach this line
+ default:
+ return 0; // use usual reporting method
+ }
+} // assert_reporting_function
+
+//____________________________________________________________________________//
+
+void BOOST_TEST_CALL_DECL
+invalid_param_handler( wchar_t const* /* expr */,
+ wchar_t const* /* func */,
+ wchar_t const* /* file */,
+ unsigned int /* line */,
+ uintptr_t /* reserved */)
+{
+ detail::report_error( execution_exception::user_error,
+ "Invalid parameter detected by C runtime library" );
+}
+
+//____________________________________________________________________________//
+
+void BOOST_TEST_CALL_DECL
+switch_fp_exceptions( bool on_off )
+{
+ if( !on_off )
+ _clearfp();
+
+ int cw = ::_controlfp( 0, 0 );
+
+ int exceptions_mask = EM_INVALID|EM_DENORMAL|EM_ZERODIVIDE|EM_OVERFLOW|EM_UNDERFLOW;
+
+ if( on_off )
+ cw &= ~exceptions_mask; // Set the exception masks on, turn exceptions off
+ else
+ cw |= exceptions_mask; // Set the exception masks off, turn exceptions on
+
+ if( on_off )
+ _clearfp();
+
+ // Set the control word
+ ::_controlfp( cw, MCW_EM );
+}
+
+//____________________________________________________________________________//
+
+} // namespace detail
+
+// ************************************************************************** //
+// ************** execution_monitor::catch_signals ************** //
+// ************************************************************************** //
+
+int
+execution_monitor::catch_signals( unit_test::callback0<int> const& F )
+{
+ _invalid_parameter_handler old_iph = _invalid_parameter_handler();
+ BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0;
+
+ if( !p_catch_system_errors )
+ _set_se_translator( &detail::seh_catch_preventer );
+ else {
+ if( !!p_detect_fp_exceptions )
+ detail::switch_fp_exceptions( true );
+
+ old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function );
+
+ old_iph = _set_invalid_parameter_handler(
+ reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) );
+ }
+
+ detail::system_signal_exception SSE( this );
+
+ int ret_val = 0;
+
+ __try {
+ __try {
+ ret_val = detail::do_invoke( m_custom_translators, F );
+ }
+ __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) {
+ throw SSE;
+ }
+ }
+ __finally {
+ if( !!p_catch_system_errors ) {
+ if( !!p_detect_fp_exceptions )
+ detail::switch_fp_exceptions( false );
+
+ BOOST_TEST_CRT_SET_HOOK( old_crt_hook );
+
+ _set_invalid_parameter_handler( old_iph );
+ }
+ }
+
+ return ret_val;
+}
+
+//____________________________________________________________________________//
+
+#else // default signal handler
+
+namespace detail {
+
+class system_signal_exception {
+public:
+ void report() const {}
+};
+
+} // namespace detail
+
+int
+execution_monitor::catch_signals( unit_test::callback0<int> const& F )
+{
+ return detail::do_invoke( m_custom_translators , F );
+}
+
+//____________________________________________________________________________//
+
+#endif // choose signal handler
+
+// ************************************************************************** //
+// ************** execution_monitor::execute ************** //
+// ************************************************************************** //
+
+int
+execution_monitor::execute( unit_test::callback0<int> const& F )
+{
+ if( debug::under_debugger() )
+ p_catch_system_errors.value = false;
+
+ try {
+ return catch_signals( F );
+ }
+
+ // Catch-clause reference arguments are a bit different from function
+ // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't
+ // required. Programmers ask for const anyhow, so we supply it. That's
+ // easier than answering questions about non-const usage.
+
+ catch( char const* ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ "C string: %s", ex ); }
+ catch( std::string const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ "std::string: %s", ex.c_str() ); }
+
+ // std:: exceptions
+
+ catch( std::bad_alloc const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_alloc: %s", ex.what() ); }
+
+#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
+ catch( std::bad_cast const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_cast" ); }
+ catch( std::bad_typeid const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_typeid" ); }
+#else
+ catch( std::bad_cast const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_cast: %s", ex.what() ); }
+ catch( std::bad_typeid const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_typeid: %s", ex.what() ); }
+#endif
+
+ catch( std::bad_exception const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::bad_exception: %s", ex.what() ); }
+ catch( std::domain_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::domain_error: %s", ex.what() ); }
+ catch( std::invalid_argument const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::invalid_argument: %s", ex.what() ); }
+ catch( std::length_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::length_error: %s", ex.what() ); }
+ catch( std::out_of_range const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::out_of_range: %s", ex.what() ); }
+ catch( std::range_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::range_error: %s", ex.what() ); }
+ catch( std::overflow_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::overflow_error: %s", ex.what() ); }
+ catch( std::underflow_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::underflow_error: %s", ex.what() ); }
+ catch( std::logic_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::logic_error: %s", ex.what() ); }
+ catch( std::runtime_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::runtime_error: %s", ex.what() ); }
+ catch( std::exception const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ current_exception_cast<ndnboost::exception const>(),
+ "std::exception: %s", ex.what() ); }
+
+ catch( ndnboost::exception const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ &ex,
+ "unknown ndnboost::exception" ); }
+
+ // system errors
+ catch( system_error const& ex )
+ { detail::report_error( execution_exception::cpp_exception_error,
+ "system_error produced by: %s: %s", ex.p_failed_exp.get(), std::strerror( ex.p_errno ) ); }
+ catch( detail::system_signal_exception const& ex )
+ { ex.report(); }
+
+ // not an error
+ catch( execution_aborted const& )
+ { return 0; }
+
+ // just forward
+ catch( execution_exception const& )
+ { throw; }
+
+ // unknown error
+ catch( ... )
+ { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); }
+
+ return 0; // never reached; supplied to quiet compiler warnings
+} // execute
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** system_error ************** //
+// ************************************************************************** //
+
+system_error::system_error( char const* exp )
+#ifdef UNDER_CE
+: p_errno( GetLastError() )
+#else
+: p_errno( errno )
+#endif
+, p_failed_exp( exp )
+{}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** execution_exception ************** //
+// ************************************************************************** //
+
+execution_exception::execution_exception( error_code ec_, const_string what_msg_, location const& location_ )
+: m_error_code( ec_ )
+, m_what( what_msg_.empty() ? BOOST_TEST_L( "uncaught exception, system error or abort requested" ) : what_msg_ )
+, m_location( location_ )
+{}
+
+//____________________________________________________________________________//
+
+execution_exception::location::location( char const* file_name, size_t line_num, char const* func )
+: m_file_name( file_name ? file_name : "unknown location" )
+, m_line_num( line_num )
+, m_function( func )
+{}
+
+//____________________________________________________________________________//
+
+} // namespace ndnboost
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER
+
diff --git a/ndnboost/test/impl/framework.ipp b/ndnboost/test/impl/framework.ipp
new file mode 100644
index 0000000..cdbce24
--- /dev/null
+++ b/ndnboost/test/impl/framework.ipp
@@ -0,0 +1,503 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57991 $
+//
+// Description : implements framework API - main driver for the test
+// ***************************************************************************
+
+#ifndef BOOST_TEST_FRAMEWORK_IPP_021005GER
+#define BOOST_TEST_FRAMEWORK_IPP_021005GER
+
+// Boost.Test
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/execution_monitor.hpp>
+#include <ndnboost/test/debug.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/unit_test_log.hpp>
+#include <ndnboost/test/unit_test_monitor.hpp>
+#include <ndnboost/test/test_observer.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/progress_monitor.hpp>
+#include <ndnboost/test/results_reporter.hpp>
+#include <ndnboost/test/test_tools.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+#include <ndnboost/test/detail/global_typedef.hpp>
+
+#include <ndnboost/test/utils/foreach.hpp>
+
+// Boost
+#include <ndnboost/timer.hpp>
+
+// STL
+#include <map>
+#include <set>
+#include <cstdlib>
+#include <ctime>
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::time; using ::srand; }
+#endif
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** test_start calls wrapper ************** //
+// ************************************************************************** //
+
+namespace ut_detail {
+
+struct test_start_caller {
+ test_start_caller( test_observer* to, counter_t tc_amount )
+ : m_to( to )
+ , m_tc_amount( tc_amount )
+ {}
+
+ int operator()()
+ {
+ m_to->test_start( m_tc_amount );
+ return 0;
+ }
+
+private:
+ // Data members
+ test_observer* m_to;
+ counter_t m_tc_amount;
+};
+
+//____________________________________________________________________________//
+
+struct test_init_caller {
+ explicit test_init_caller( init_unit_test_func init_func )
+ : m_init_func( init_func )
+ {}
+ int operator()()
+ {
+#ifdef BOOST_TEST_ALTERNATIVE_INIT_API
+ if( !(*m_init_func)() )
+ throw std::runtime_error( "test module initialization failed" );
+#else
+ test_suite* manual_test_units = (*m_init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv );
+
+ if( manual_test_units )
+ framework::master_test_suite().add( manual_test_units );
+#endif
+ return 0;
+ }
+
+ // Data members
+ init_unit_test_func m_init_func;
+};
+
+}
+
+// ************************************************************************** //
+// ************** framework ************** //
+// ************************************************************************** //
+
+class framework_impl : public test_tree_visitor {
+public:
+ framework_impl()
+ : m_master_test_suite( 0 )
+ , m_curr_test_case( INV_TEST_UNIT_ID )
+ , m_next_test_case_id( MIN_TEST_CASE_ID )
+ , m_next_test_suite_id( MIN_TEST_SUITE_ID )
+ , m_is_initialized( false )
+ , m_test_in_progress( false )
+ {}
+
+ ~framework_impl() { clear(); }
+
+ void clear()
+ {
+ while( !m_test_units.empty() ) {
+ test_unit_store::value_type const& tu = *m_test_units.begin();
+ test_unit* tu_ptr = tu.second;
+
+ // the delete will erase this element from map
+ if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == tut_suite )
+ delete (test_suite const*)tu_ptr;
+ else
+ delete (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
+ void visit( test_case const& tc )
+ {
+ if( !tc.check_dependencies() ) {
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_skipped( tc );
+
+ return;
+ }
+
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_start( tc );
+
+ ndnboost::timer tc_timer;
+ test_unit_id bkup = m_curr_test_case;
+ m_curr_test_case = tc.p_id;
+ unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc );
+
+ unsigned long elapsed = static_cast<unsigned long>( tc_timer.elapsed() * 1e6 );
+
+ if( unit_test_monitor.is_critical_error( run_result ) ) {
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_aborted();
+ }
+
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_finish( tc, elapsed );
+
+ m_curr_test_case = bkup;
+
+ if( unit_test_monitor.is_critical_error( run_result ) )
+ throw test_being_aborted();
+ }
+
+ bool test_suite_start( test_suite const& ts )
+ {
+ if( !ts.check_dependencies() ) {
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_skipped( ts );
+
+ return false;
+ }
+
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_start( ts );
+
+ return true;
+ }
+
+ void test_suite_finish( test_suite const& ts )
+ {
+ BOOST_TEST_FOREACH( test_observer*, to, m_observers )
+ to->test_unit_finish( ts, 0 );
+ }
+
+ //////////////////////////////////////////////////////////////////
+ struct priority_order {
+ bool operator()( test_observer* lhs, test_observer* rhs ) const
+ {
+ return (lhs->priority() < rhs->priority()) || ((lhs->priority() == rhs->priority()) && (lhs < rhs));
+ }
+ };
+
+ typedef std::map<test_unit_id,test_unit*> test_unit_store;
+ typedef std::set<test_observer*,priority_order> observer_store;
+
+ master_test_suite_t* m_master_test_suite;
+ test_unit_id m_curr_test_case;
+ test_unit_store m_test_units;
+
+ test_unit_id m_next_test_case_id;
+ test_unit_id m_next_test_suite_id;
+
+ bool m_is_initialized;
+ bool m_test_in_progress;
+
+ observer_store m_observers;
+};
+
+//____________________________________________________________________________//
+
+namespace {
+
+#if defined(__CYGWIN__)
+framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; }
+#else
+framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; }
+#endif
+
+} // local namespace
+
+//____________________________________________________________________________//
+
+namespace framework {
+
+void
+init( init_unit_test_func init_func, int argc, char* argv[] )
+{
+ runtime_config::init( argc, argv );
+
+ // set the log level and format
+ unit_test_log.set_threshold_level( runtime_config::log_level() );
+ unit_test_log.set_format( runtime_config::log_format() );
+
+ // set the report level and format
+ results_reporter::set_level( runtime_config::report_level() );
+ results_reporter::set_format( runtime_config::report_format() );
+
+ register_observer( results_collector );
+ register_observer( unit_test_log );
+
+ if( runtime_config::show_progress() )
+ register_observer( progress_monitor );
+
+ if( runtime_config::detect_memory_leaks() > 0 ) {
+ debug::detect_memory_leaks( true );
+ debug::break_memory_alloc( runtime_config::detect_memory_leaks() );
+ }
+
+ // init master unit test suite
+ master_test_suite().argc = argc;
+ master_test_suite().argv = argv;
+
+ try {
+ ndnboost::execution_monitor em;
+
+ ut_detail::test_init_caller tic( init_func );
+
+ em.execute( tic );
+ }
+ catch( execution_exception const& ex ) {
+ throw setup_error( ex.what() );
+ }
+
+ s_frk_impl().m_is_initialized = true;
+}
+
+//____________________________________________________________________________//
+
+bool
+is_initialized()
+{
+ return s_frk_impl().m_is_initialized;
+}
+
+//____________________________________________________________________________//
+
+void
+register_test_unit( test_case* tc )
+{
+ BOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test case already registered" ) );
+
+ test_unit_id new_id = s_frk_impl().m_next_test_case_id;
+
+ BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, BOOST_TEST_L( "too many test cases" ) );
+
+ typedef framework_impl::test_unit_store::value_type map_value_type;
+
+ s_frk_impl().m_test_units.insert( map_value_type( new_id, tc ) );
+ s_frk_impl().m_next_test_case_id++;
+
+ s_frk_impl().set_tu_id( *tc, new_id );
+}
+
+//____________________________________________________________________________//
+
+void
+register_test_unit( test_suite* ts )
+{
+ BOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test suite already registered" ) );
+
+ test_unit_id new_id = s_frk_impl().m_next_test_suite_id;
+
+ BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, BOOST_TEST_L( "too many test suites" ) );
+
+ typedef framework_impl::test_unit_store::value_type map_value_type;
+ s_frk_impl().m_test_units.insert( map_value_type( new_id, ts ) );
+ s_frk_impl().m_next_test_suite_id++;
+
+ s_frk_impl().set_tu_id( *ts, new_id );
+}
+
+//____________________________________________________________________________//
+
+void
+deregister_test_unit( test_unit* tu )
+{
+ s_frk_impl().m_test_units.erase( tu->p_id );
+}
+
+//____________________________________________________________________________//
+
+void
+clear()
+{
+ s_frk_impl().clear();
+}
+
+//____________________________________________________________________________//
+
+void
+register_observer( test_observer& to )
+{
+ s_frk_impl().m_observers.insert( &to );
+}
+
+//____________________________________________________________________________//
+
+void
+deregister_observer( test_observer& to )
+{
+ s_frk_impl().m_observers.erase( &to );
+}
+
+//____________________________________________________________________________//
+
+void
+reset_observers()
+{
+ s_frk_impl().m_observers.clear();
+}
+
+//____________________________________________________________________________//
+
+master_test_suite_t&
+master_test_suite()
+{
+ if( !s_frk_impl().m_master_test_suite )
+ s_frk_impl().m_master_test_suite = new master_test_suite_t;
+
+ return *s_frk_impl().m_master_test_suite;
+}
+
+//____________________________________________________________________________//
+
+test_case const&
+current_test_case()
+{
+ return get<test_case>( s_frk_impl().m_curr_test_case );
+}
+
+//____________________________________________________________________________//
+
+test_unit&
+get( test_unit_id id, test_unit_type t )
+{
+ test_unit* res = s_frk_impl().m_test_units[id];
+
+ if( (res->p_type & t) == 0 )
+ throw internal_error( "Invalid test unit type" );
+
+ return *res;
+}
+
+//____________________________________________________________________________//
+
+void
+run( test_unit_id id, bool continue_test )
+{
+ if( id == INV_TEST_UNIT_ID )
+ id = master_test_suite().p_id;
+
+ test_case_counter tcc;
+ traverse_test_tree( id, tcc );
+
+ BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().is_empty()
+ ? BOOST_TEST_L( "test tree is empty" )
+ : BOOST_TEST_L( "no test cases matching filter" ) );
+
+ bool call_start_finish = !continue_test || !s_frk_impl().m_test_in_progress;
+ bool was_in_progress = s_frk_impl().m_test_in_progress;
+
+ s_frk_impl().m_test_in_progress = true;
+
+ if( call_start_finish ) {
+ BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) {
+ ndnboost::execution_monitor em;
+
+ try {
+ em.execute( ut_detail::test_start_caller( to, tcc.p_count ) );
+ }
+ catch( execution_exception const& ex ) {
+ throw setup_error( ex.what() );
+ }
+ }
+ }
+
+ switch( runtime_config::random_seed() ) {
+ case 0:
+ break;
+ case 1: {
+ unsigned int seed = static_cast<unsigned int>( std::time( 0 ) );
+ BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed );
+ std::srand( seed );
+ break;
+ }
+ default:
+ BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << runtime_config::random_seed() );
+ std::srand( runtime_config::random_seed() );
+ }
+
+ try {
+ traverse_test_tree( id, s_frk_impl() );
+ }
+ catch( test_being_aborted const& ) {
+ // abort already reported
+ }
+
+ if( call_start_finish ) {
+ BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
+ to->test_finish();
+ }
+
+ s_frk_impl().m_test_in_progress = was_in_progress;
+}
+
+//____________________________________________________________________________//
+
+void
+run( test_unit const* tu, bool continue_test )
+{
+ run( tu->p_id, continue_test );
+}
+
+//____________________________________________________________________________//
+
+void
+assertion_result( bool passed )
+{
+ BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
+ to->assertion_result( passed );
+}
+
+//____________________________________________________________________________//
+
+void
+exception_caught( execution_exception const& ex )
+{
+ BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
+ to->exception_caught( ex );
+}
+
+//____________________________________________________________________________//
+
+void
+test_unit_aborted( test_unit const& tu )
+{
+ BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers )
+ to->test_unit_aborted( tu );
+}
+
+//____________________________________________________________________________//
+
+} // namespace framework
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_FRAMEWORK_IPP_021005GER
diff --git a/ndnboost/test/impl/interaction_based.ipp b/ndnboost/test/impl/interaction_based.ipp
new file mode 100644
index 0000000..03ee9be
--- /dev/null
+++ b/ndnboost/test/impl/interaction_based.ipp
@@ -0,0 +1,90 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Use, modification, and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : Facilities to perform interaction-based testing
+// ***************************************************************************
+
+#ifndef BOOST_TEST_INTERACTION_BASED_IPP_112105GER
+#define BOOST_TEST_INTERACTION_BASED_IPP_112105GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+
+#if BOOST_TEST_SUPPORT_INTERACTION_TESTING
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+#include <ndnboost/test/utils/callback.hpp>
+#include <ndnboost/test/interaction_based.hpp>
+#include <ndnboost/test/mock_object.hpp>
+#include <ndnboost/test/framework.hpp> // for setup_error
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+// STL
+#include <stdexcept>
+#include <string>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace itest { // interaction-based testing
+
+// ************************************************************************** //
+// ************** manager ************** //
+// ************************************************************************** //
+
+manager::manager()
+{
+ instance_ptr( true, this );
+}
+
+//____________________________________________________________________________//
+
+manager::~manager()
+{
+ instance_ptr( true );
+}
+
+//____________________________________________________________________________//
+
+manager*
+manager::instance_ptr( bool reset, manager* new_ptr )
+{
+ static manager dummy( 0 );
+
+ static manager* ptr = &dummy;
+
+ if( reset ) {
+ if( new_ptr ) {
+ BOOST_TEST_SETUP_ASSERT( ptr == &dummy, BOOST_TEST_L( "Can't run two interation based test the same time" ) );
+
+ ptr = new_ptr;
+ }
+ else
+ ptr = &dummy;
+ }
+
+ return ptr;
+}
+
+} // namespace itest
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // not ancient compiler
+
+#endif // BOOST_TEST_INTERACTION_BASED_IPP_112105GER
diff --git a/ndnboost/test/impl/logged_expectations.ipp b/ndnboost/test/impl/logged_expectations.ipp
new file mode 100644
index 0000000..4db7b81
--- /dev/null
+++ b/ndnboost/test/impl/logged_expectations.ipp
@@ -0,0 +1,246 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Use, modification, and distribution are subject to the
+// Boost Software License, ELOG_VER 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : Facilities to perform interaction based testng of logged expectations
+// ***************************************************************************
+
+#ifndef BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
+#define BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+
+#if BOOST_TEST_SUPPORT_INTERACTION_TESTING
+
+#include <ndnboost/test/detail/global_typedef.hpp>
+
+#include <ndnboost/test/utils/callback.hpp>
+#include <ndnboost/test/utils/iterator/token_iterator.hpp>
+
+#include <ndnboost/test/interaction_based.hpp>
+#include <ndnboost/test/test_tools.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+// Boost
+#include <ndnboost/lexical_cast.hpp>
+
+// STL
+#include <fstream>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+using namespace ::ndnboost::unit_test;
+
+namespace itest {
+
+// ************************************************************************** //
+// ************** logged expectation test implementation ************** //
+// ************************************************************************** //
+
+struct expectations_logger : itest::manager {
+ // Constructor
+ expectations_logger( const_string log_file_name, bool test_or_log );
+
+ virtual bool decision_point( const_string, std::size_t );
+ virtual unsigned enter_scope( const_string, std::size_t, const_string scope_name );
+ virtual void allocated( const_string, std::size_t, void*, std::size_t s );
+ virtual void data_flow( const_string d );
+ virtual std::string return_value( const_string default_value );
+
+private:
+ // Data members
+ bool m_test_or_log;
+ std::fstream m_log_file;
+};
+
+literal_string ELOG_VER = "1.0";
+literal_string CLMN_SEP = "|";
+static const char LINE_SEP = '\n';
+
+literal_string FILE_SIG = "ELOG";
+literal_string SCOPE_SIG = "SCOPE";
+literal_string ALLOC_SIG = "ALLOC";
+literal_string DP_SIG = "SWITCH";
+literal_string DATA_SIG = "DATA";
+literal_string RETURN_SIG = "RETURN";
+
+//____________________________________________________________________________//
+
+expectations_logger::expectations_logger( const_string log_file_name, bool test_or_log )
+: m_test_or_log( test_or_log )
+{
+ BOOST_REQUIRE_MESSAGE( !log_file_name.is_empty(), "Empty expectations log file name" );
+
+ m_log_file.open( log_file_name.begin(), test_or_log ? std::ios::in : std::ios::out );
+
+ BOOST_REQUIRE_MESSAGE( m_log_file.is_open(),
+ "Can't open expectations log file " << log_file_name
+ << " for " << ( m_test_or_log ? "reading" : "writing") );
+
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, FILE_SIG );
+ ++tit;
+ BOOST_CHECK_EQUAL( *tit, ELOG_VER );
+ }
+ else {
+ m_log_file << FILE_SIG << CLMN_SEP << ELOG_VER << LINE_SEP;
+ }
+}
+
+//____________________________________________________________________________//
+
+bool
+expectations_logger::decision_point( const_string, std::size_t )
+{
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, DP_SIG ); ++tit;
+ return lexical_cast<bool>( *tit );
+ }
+ else {
+ m_log_file << DP_SIG << CLMN_SEP << std::boolalpha << true << LINE_SEP;
+
+ return true;
+ }
+}
+
+//____________________________________________________________________________//
+
+unsigned
+expectations_logger::enter_scope( const_string, std::size_t, const_string scope_name )
+{
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, SCOPE_SIG ); ++tit;
+ BOOST_CHECK_EQUAL( *tit, scope_name );
+ }
+ else {
+ m_log_file << SCOPE_SIG << CLMN_SEP << scope_name << LINE_SEP;
+ }
+
+ return 0;
+}
+
+//____________________________________________________________________________//
+
+void
+expectations_logger::allocated( const_string, std::size_t, void*, std::size_t s )
+{
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, ALLOC_SIG ); ++tit;
+ BOOST_CHECK_EQUAL( lexical_cast<std::size_t>( *tit ), s );
+ }
+ else {
+ m_log_file << ALLOC_SIG << CLMN_SEP << s << LINE_SEP;
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+expectations_logger::data_flow( const_string d )
+{
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, DATA_SIG ); ++tit;
+ BOOST_CHECK_EQUAL( *tit, d );
+ }
+ else {
+ m_log_file << DATA_SIG << CLMN_SEP << d << LINE_SEP;
+ }
+}
+
+//____________________________________________________________________________//
+
+std::string
+expectations_logger::return_value( const_string default_value )
+{
+ if( m_test_or_log ) {
+ std::string line;
+
+ std::getline( m_log_file, line, LINE_SEP );
+
+ const_string cline( line );
+ string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
+
+ BOOST_CHECK_EQUAL( *tit, RETURN_SIG ); ++tit;
+
+ return std::string( tit->begin(), tit->size() );
+ }
+ else {
+ m_log_file << RETURN_SIG << CLMN_SEP << default_value << LINE_SEP;
+
+ return std::string();
+ }
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** logged expectations test ************** //
+// ************************************************************************** //
+
+void BOOST_TEST_DECL
+logged_expectations( callback0<> const& F, const_string log_file_name, bool test_or_log )
+{
+ expectations_logger el( log_file_name, test_or_log );
+
+ F();
+}
+
+//____________________________________________________________________________//
+
+} // namespace itest
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // not ancient compiler
+
+#endif // BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
diff --git a/ndnboost/test/impl/plain_report_formatter.ipp b/ndnboost/test/impl/plain_report_formatter.ipp
new file mode 100644
index 0000000..1f0aaac
--- /dev/null
+++ b/ndnboost/test/impl/plain_report_formatter.ipp
@@ -0,0 +1,198 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 49312 $
+//
+// Description : plain report formatter definition
+// ***************************************************************************
+
+#ifndef BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER
+#define BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/output/plain_report_formatter.hpp>
+#include <ndnboost/test/utils/custom_manip.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+
+// STL
+#include <iomanip>
+#include <ndnboost/config/no_tr1/cmath.hpp>
+#include <iostream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::log10; }
+# endif
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace output {
+
+namespace {
+
+typedef custom_manip<struct quote_t> quote;
+
+template<typename T>
+inline std::ostream&
+operator<<( custom_printer<quote> const& p, T const& value )
+{
+ *p << '"' << value << '"';
+
+ return *p;
+}
+
+//____________________________________________________________________________//
+
+void
+print_stat_value( std::ostream& ostr, counter_t v, counter_t indent, counter_t total,
+ const_string name, const_string res )
+{
+ if( v > 0 ) {
+ ostr << std::setw( indent ) << ""
+ << v << ' ' << name << ( v != 1 ? "s" : "" );
+ if( total > 0 )
+ ostr << " out of " << total;
+
+ ostr << ' ' << res << '\n';
+ }
+}
+
+//____________________________________________________________________________//
+
+} // local namespace
+
+// ************************************************************************** //
+// ************** plain_report_formatter ************** //
+// ************************************************************************** //
+
+void
+plain_report_formatter::results_report_start( std::ostream& ostr )
+{
+ m_indent = 0;
+ ostr << '\n';
+}
+
+//____________________________________________________________________________//
+
+void
+plain_report_formatter::results_report_finish( std::ostream& ostr )
+{
+ ostr.flush();
+}
+
+//____________________________________________________________________________//
+
+void
+plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& ostr )
+{
+ test_results const& tr = results_collector.results( tu.p_id );
+
+ const_string descr;
+
+ if( tr.passed() )
+ descr = "passed";
+ else if( tr.p_skipped )
+ descr = "skipped";
+ else if( tr.p_aborted )
+ descr = "aborted";
+ else
+ descr = "failed";
+
+ ostr << std::setw( m_indent ) << ""
+ << "Test " << (tu.p_type == tut_case ? "case " : "suite " ) << quote() << tu.p_name << ' ' << descr;
+
+ if( tr.p_skipped ) {
+ ostr << " due to " << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" );
+ m_indent += 2;
+ return;
+ }
+
+ counter_t total_assertions = tr.p_assertions_passed + tr.p_assertions_failed;
+ counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_failed + tr.p_test_cases_skipped;
+
+ if( total_assertions > 0 || total_tc > 0 )
+ ostr << " with:";
+
+ ostr << '\n';
+ m_indent += 2;
+
+ print_stat_value( ostr, tr.p_assertions_passed, m_indent, total_assertions, "assertion", "passed" );
+ print_stat_value( ostr, tr.p_assertions_failed, m_indent, total_assertions, "assertion", "failed" );
+ print_stat_value( ostr, tr.p_expected_failures, m_indent, 0 , "failure" , "expected" );
+ print_stat_value( ostr, tr.p_test_cases_passed, m_indent, total_tc , "test case", "passed" );
+ print_stat_value( ostr, tr.p_test_cases_failed, m_indent, total_tc , "test case", "failed" );
+ print_stat_value( ostr, tr.p_test_cases_skipped, m_indent, total_tc , "test case", "skipped" );
+ print_stat_value( ostr, tr.p_test_cases_aborted, m_indent, total_tc , "test case", "aborted" );
+
+ ostr << '\n';
+}
+
+//____________________________________________________________________________//
+
+void
+plain_report_formatter::test_unit_report_finish( test_unit const&, std::ostream& )
+{
+ m_indent -= 2;
+}
+
+//____________________________________________________________________________//
+
+void
+plain_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr )
+{
+ test_results const& tr = results_collector.results( tu.p_id );
+
+ if( tr.passed() ) {
+ ostr << "*** No errors detected\n";
+ return;
+ }
+
+ if( tr.p_skipped ) {
+ ostr << "*** Test " << tu.p_type_name << " skipped due to "
+ << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" );
+ return;
+ }
+
+ if( tr.p_assertions_failed == 0 ) {
+ ostr << "*** errors detected in test " << tu.p_type_name << " " << quote() << tu.p_name
+ << "; see standard output for details\n";
+ return;
+ }
+
+ counter_t num_failures = tr.p_assertions_failed;
+
+ ostr << "*** " << num_failures << " failure" << ( num_failures != 1 ? "s" : "" ) << " detected";
+
+ if( tr.p_expected_failures > 0 )
+ ostr << " (" << tr.p_expected_failures << " failure" << ( tr.p_expected_failures != 1 ? "s" : "" ) << " expected)";
+
+ ostr << " in test " << tu.p_type_name << " " << quote() << tu.p_name << "\n";
+}
+
+//____________________________________________________________________________//
+
+} // namespace output
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER
diff --git a/ndnboost/test/impl/progress_monitor.ipp b/ndnboost/test/impl/progress_monitor.ipp
new file mode 100644
index 0000000..ac93432
--- /dev/null
+++ b/ndnboost/test/impl/progress_monitor.ipp
@@ -0,0 +1,110 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : implements simple text based progress monitor
+// ***************************************************************************
+
+#ifndef BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER
+#define BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/progress_monitor.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+// Boost
+#include <ndnboost/progress.hpp>
+#include <ndnboost/scoped_ptr.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** progress_monitor ************** //
+// ************************************************************************** //
+
+namespace {
+
+struct progress_monitor_impl {
+ // Constructor
+ progress_monitor_impl()
+ : m_stream( runtime_config::log_sink() )
+ {}
+
+ std::ostream* m_stream;
+ scoped_ptr<progress_display> m_progress_display;
+};
+
+progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; return the_inst; }
+
+} // local namespace
+
+//____________________________________________________________________________//
+
+void
+progress_monitor_t::test_start( counter_t test_cases_amount )
+{
+ s_pm_impl().m_progress_display.reset( new progress_display( test_cases_amount, *s_pm_impl().m_stream ) );
+}
+
+//____________________________________________________________________________//
+
+void
+progress_monitor_t::test_aborted()
+{
+ (*s_pm_impl().m_progress_display) += s_pm_impl().m_progress_display->count();
+}
+
+//____________________________________________________________________________//
+
+void
+progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long )
+{
+ if( tu.p_type == tut_case )
+ ++(*s_pm_impl().m_progress_display);
+}
+
+//____________________________________________________________________________//
+
+void
+progress_monitor_t::test_unit_skipped( test_unit const& tu )
+{
+ test_case_counter tcc;
+ traverse_test_tree( tu, tcc );
+
+ (*s_pm_impl().m_progress_display) += tcc.p_count;
+}
+
+//____________________________________________________________________________//
+
+void
+progress_monitor_t::set_stream( std::ostream& ostr )
+{
+ s_pm_impl().m_stream = &ostr;
+}
+
+//____________________________________________________________________________//
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER
diff --git a/ndnboost/test/impl/results_collector.ipp b/ndnboost/test/impl/results_collector.ipp
new file mode 100644
index 0000000..7b676cf
--- /dev/null
+++ b/ndnboost/test/impl/results_collector.ipp
@@ -0,0 +1,294 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : implements Unit Test results collecting facility.
+// ***************************************************************************
+
+#ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
+#define BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
+
+// Boost.Test
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/unit_test_log.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/framework.hpp>
+
+// Boost
+#include <ndnboost/cstdlib.hpp>
+
+// STL
+#include <map>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** test_results ************** //
+// ************************************************************************** //
+
+test_results::test_results()
+{
+ clear();
+}
+
+//____________________________________________________________________________//
+
+bool
+test_results::passed() const
+{
+ return !p_skipped &&
+ p_test_cases_failed == 0 &&
+ p_assertions_failed <= p_expected_failures &&
+ !p_aborted;
+}
+
+//____________________________________________________________________________//
+
+int
+test_results::result_code() const
+{
+ return passed() ? exit_success
+ : ( (p_assertions_failed > p_expected_failures || p_skipped )
+ ? exit_test_failure
+ : exit_exception_failure );
+}
+
+//____________________________________________________________________________//
+
+void
+test_results::operator+=( test_results const& tr )
+{
+ p_assertions_passed.value += tr.p_assertions_passed;
+ p_assertions_failed.value += tr.p_assertions_failed;
+ p_test_cases_passed.value += tr.p_test_cases_passed;
+ p_test_cases_failed.value += tr.p_test_cases_failed;
+ p_test_cases_skipped.value += tr.p_test_cases_skipped;
+ p_test_cases_aborted.value += tr.p_test_cases_aborted;
+}
+
+//____________________________________________________________________________//
+
+void
+test_results::clear()
+{
+ p_assertions_passed.value = 0;
+ p_assertions_failed.value = 0;
+ p_expected_failures.value = 0;
+ p_test_cases_passed.value = 0;
+ p_test_cases_failed.value = 0;
+ p_test_cases_skipped.value = 0;
+ p_test_cases_aborted.value = 0;
+ p_aborted.value = false;
+ p_skipped.value = true;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** results_collector ************** //
+// ************************************************************************** //
+
+#if !BOOST_WORKAROUND(BOOST_MSVC, <1300)
+
+namespace {
+
+struct results_collector_impl {
+ std::map<test_unit_id,test_results> m_results_store;
+};
+
+results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; }
+
+} // local namespace
+
+#else
+
+struct results_collector_impl {
+ std::map<test_unit_id,test_results> m_results_store;
+};
+
+static results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; }
+
+#endif
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_start( counter_t )
+{
+ s_rc_impl().m_results_store.clear();
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_finish()
+{
+ // do nothing
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_aborted()
+{
+ // do nothing
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_unit_start( test_unit const& tu )
+{
+ // init test_results entry
+ test_results& tr = s_rc_impl().m_results_store[tu.p_id];
+
+ tr.clear();
+
+ tr.p_expected_failures.value = tu.p_expected_failures;
+ tr.p_skipped.value = false;
+}
+
+//____________________________________________________________________________//
+
+class results_collect_helper : public test_tree_visitor {
+public:
+ explicit results_collect_helper( test_results& tr, test_unit const& ts ) : m_tr( tr ), m_ts( ts ) {}
+
+ void visit( test_case const& tc )
+ {
+ test_results const& tr = results_collector.results( tc.p_id );
+ m_tr += tr;
+
+ if( tr.passed() )
+ m_tr.p_test_cases_passed.value++;
+ else if( tr.p_skipped )
+ m_tr.p_test_cases_skipped.value++;
+ else {
+ if( tr.p_aborted )
+ m_tr.p_test_cases_aborted.value++;
+ m_tr.p_test_cases_failed.value++;
+ }
+ }
+ bool test_suite_start( test_suite const& ts )
+ {
+ if( m_ts.p_id == ts.p_id )
+ return true;
+ else {
+ m_tr += results_collector.results( ts.p_id );
+ return false;
+ }
+ }
+
+private:
+ // Data members
+ test_results& m_tr;
+ test_unit const& m_ts;
+};
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_unit_finish( test_unit const& tu, unsigned long )
+{
+ if( tu.p_type == tut_suite ) {
+ results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu );
+
+ traverse_test_tree( tu, ch );
+ }
+ else {
+ test_results const& tr = s_rc_impl().m_results_store[tu.p_id];
+
+ bool num_failures_match = tr.p_aborted || tr.p_assertions_failed >= tr.p_expected_failures;
+ if( !num_failures_match )
+ BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " has fewer failures than expected" );
+
+ bool check_any_assertions = tr.p_aborted || (tr.p_assertions_failed != 0) || (tr.p_assertions_passed != 0);
+ if( !check_any_assertions )
+ BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " did not check any assertions" );
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_unit_skipped( test_unit const& tu )
+{
+ if( tu.p_type == tut_suite ) {
+ test_case_counter tcc;
+ traverse_test_tree( tu, tcc );
+
+ test_results& tr = s_rc_impl().m_results_store[tu.p_id];
+
+ tr.clear();
+
+ tr.p_skipped.value = true;
+ tr.p_test_cases_skipped.value = tcc.p_count;
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::assertion_result( bool passed )
+{
+ test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id];
+
+ if( passed )
+ tr.p_assertions_passed.value++;
+ else
+ tr.p_assertions_failed.value++;
+
+ if( tr.p_assertions_failed == 1 )
+ first_failed_assertion();
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::exception_caught( execution_exception const& )
+{
+ test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id];
+
+ tr.p_assertions_failed.value++;
+}
+
+//____________________________________________________________________________//
+
+void
+results_collector_t::test_unit_aborted( test_unit const& tu )
+{
+ s_rc_impl().m_results_store[tu.p_id].p_aborted.value = true;
+}
+
+//____________________________________________________________________________//
+
+test_results const&
+results_collector_t::results( test_unit_id id ) const
+{
+ return s_rc_impl().m_results_store[id];
+}
+
+//____________________________________________________________________________//
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
diff --git a/ndnboost/test/impl/results_reporter.ipp b/ndnboost/test/impl/results_reporter.ipp
new file mode 100644
index 0000000..1009a3d
--- /dev/null
+++ b/ndnboost/test/impl/results_reporter.ipp
@@ -0,0 +1,202 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : result reporting facilties
+// ***************************************************************************
+
+#ifndef BOOST_TEST_RESULTS_REPORTER_IPP_020105GER
+#define BOOST_TEST_RESULTS_REPORTER_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/results_reporter.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/output/plain_report_formatter.hpp>
+#include <ndnboost/test/output/xml_report_formatter.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+// Boost
+#include <ndnboost/scoped_ptr.hpp>
+#include <ndnboost/io/ios_state.hpp>
+typedef ::ndnboost::io::ios_base_all_saver io_saver_type;
+
+// STL
+#include <iostream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace results_reporter {
+
+// ************************************************************************** //
+// ************** result reporter implementation ************** //
+// ************************************************************************** //
+
+namespace {
+
+struct results_reporter_impl : test_tree_visitor {
+ // Constructor
+ results_reporter_impl()
+ : m_output( runtime_config::report_sink() )
+ , m_stream_state_saver( new io_saver_type( *m_output ) )
+ , m_report_level( CONFIRMATION_REPORT )
+ , m_formatter( new output::plain_report_formatter )
+ {}
+
+ // test tree visitor interface implementation
+ void visit( test_case const& tc )
+ {
+ m_formatter->test_unit_report_start( tc, *m_output );
+ m_formatter->test_unit_report_finish( tc, *m_output );
+ }
+ bool test_suite_start( test_suite const& ts )
+ {
+ m_formatter->test_unit_report_start( ts, *m_output );
+
+ if( m_report_level == DETAILED_REPORT && !results_collector.results( ts.p_id ).p_skipped )
+ return true;
+
+ m_formatter->test_unit_report_finish( ts, *m_output );
+ return false;
+ }
+ void test_suite_finish( test_suite const& ts )
+ {
+ m_formatter->test_unit_report_finish( ts, *m_output );
+ }
+
+ typedef scoped_ptr<io_saver_type> saver_ptr;
+
+ // Data members
+ std::ostream* m_output;
+ saver_ptr m_stream_state_saver;
+ report_level m_report_level;
+ scoped_ptr<format> m_formatter;
+};
+
+results_reporter_impl& s_rr_impl() { static results_reporter_impl the_inst; return the_inst; }
+
+} // local namespace
+
+// ************************************************************************** //
+// ************** report configuration ************** //
+// ************************************************************************** //
+
+void
+set_level( report_level l )
+{
+ if( l != INV_REPORT_LEVEL )
+ s_rr_impl().m_report_level = l;
+}
+
+//____________________________________________________________________________//
+
+void
+set_stream( std::ostream& ostr )
+{
+ s_rr_impl().m_output = &ostr;
+ s_rr_impl().m_stream_state_saver.reset( new io_saver_type( ostr ) );
+}
+
+//____________________________________________________________________________//
+
+std::ostream&
+get_stream()
+{
+ return *s_rr_impl().m_output;
+}
+
+//____________________________________________________________________________//
+
+void
+set_format( output_format rf )
+{
+ switch( rf ) {
+ case CLF:
+ set_format( new output::plain_report_formatter );
+ break;
+ case XML:
+ set_format( new output::xml_report_formatter );
+ break;
+ default:
+ break;
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+set_format( results_reporter::format* f )
+{
+ if( f )
+ s_rr_impl().m_formatter.reset( f );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** report initiation ************** //
+// ************************************************************************** //
+
+void
+make_report( report_level l, test_unit_id id )
+{
+ if( l == INV_REPORT_LEVEL )
+ l = s_rr_impl().m_report_level;
+
+ if( l == NO_REPORT )
+ return;
+
+ if( id == INV_TEST_UNIT_ID )
+ id = framework::master_test_suite().p_id;
+
+ s_rr_impl().m_stream_state_saver->restore();
+
+ report_level bkup = s_rr_impl().m_report_level;
+ s_rr_impl().m_report_level = l;
+
+ s_rr_impl().m_formatter->results_report_start( *s_rr_impl().m_output );
+
+ switch( l ) {
+ case CONFIRMATION_REPORT:
+ s_rr_impl().m_formatter->do_confirmation_report( framework::get<test_unit>( id ), *s_rr_impl().m_output );
+ break;
+ case SHORT_REPORT:
+ case DETAILED_REPORT:
+ traverse_test_tree( id, s_rr_impl() );
+ break;
+ default:
+ break;
+ }
+
+ s_rr_impl().m_formatter->results_report_finish( *s_rr_impl().m_output );
+ s_rr_impl().m_report_level = bkup;
+}
+
+//____________________________________________________________________________//
+
+} // namespace results_reporter
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_RESULTS_REPORTER_IPP_020105GER
diff --git a/ndnboost/test/impl/test_main.ipp b/ndnboost/test/impl/test_main.ipp
new file mode 100644
index 0000000..5991f1c
--- /dev/null
+++ b/ndnboost/test/impl/test_main.ipp
@@ -0,0 +1,68 @@
+// (C) Copyright Gennadiy Rozental 2001-2008.
+// (C) Copyright Beman Dawes 1995-2001.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $$Revision: 49312 $
+//
+// Description : implements main function for Test Execution Monitor.
+// ***************************************************************************
+
+#ifndef BOOST_TEST_TEST_MAIN_IPP_012205GER
+#define BOOST_TEST_TEST_MAIN_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/test_tools.hpp>
+#include <ndnboost/test/unit_test_suite.hpp>
+
+// Boost
+#include <ndnboost/cstdlib.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+extern int test_main( int argc, char* argv[] ); // prototype for user's test_main()
+
+struct test_main_caller {
+ test_main_caller( int argc, char** argv ) : m_argc( argc ), m_argv( argv ) {}
+
+ void operator()() {
+ int test_main_result = test_main( m_argc, m_argv );
+
+ // translate a test_main non-success return into a test error
+ BOOST_CHECK( test_main_result == 0 || test_main_result == ndnboost::exit_success );
+ }
+
+private:
+ // Data members
+ int m_argc;
+ char** m_argv;
+};
+
+// ************************************************************************** //
+// ************** test main ************** //
+// ************************************************************************** //
+
+::ndnboost::unit_test::test_suite*
+init_unit_test_suite( int argc, char* argv[] ) {
+ using namespace ::ndnboost::unit_test;
+
+ framework::master_test_suite().p_name.value = "Test Program";
+
+ framework::master_test_suite().add( BOOST_TEST_CASE( test_main_caller( argc, argv ) ) );
+
+ return 0;
+}
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_TEST_MAIN_IPP_012205GER
diff --git a/ndnboost/test/impl/test_tools.ipp b/ndnboost/test/impl/test_tools.ipp
new file mode 100644
index 0000000..b47ef81
--- /dev/null
+++ b/ndnboost/test/impl/test_tools.ipp
@@ -0,0 +1,628 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : supplies offline implementation for the Test Tools
+// ***************************************************************************
+
+#ifndef BOOST_TEST_TEST_TOOLS_IPP_012205GER
+#define BOOST_TEST_TEST_TOOLS_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/test_tools.hpp>
+#include <ndnboost/test/unit_test_log.hpp>
+#include <ndnboost/test/output_test_stream.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/execution_monitor.hpp> // execution_aborted
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+
+// Boost
+#include <ndnboost/config.hpp>
+
+// STL
+#include <fstream>
+#include <string>
+#include <cstring>
+#include <cctype>
+#include <cwchar>
+#include <stdexcept>
+#include <ios>
+
+// !! should we use #include <cstdarg>
+#include <stdarg.h>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::strcmp; using ::strlen; using ::isprint; }
+#if !defined( BOOST_NO_CWCHAR )
+namespace std { using ::wcscmp; }
+#endif
+# endif
+
+namespace ndnboost {
+
+namespace test_tools {
+
+// ************************************************************************** //
+// ************** print_log_value ************** //
+// ************************************************************************** //
+
+void
+print_log_value<char>::operator()( std::ostream& ostr, char t )
+{
+ if( (std::isprint)( static_cast<unsigned char>(t) ) )
+ ostr << '\'' << t << '\'';
+ else
+ ostr << std::hex
+#if BOOST_TEST_USE_STD_LOCALE
+ << std::showbase
+#else
+ << "0x"
+#endif
+ << static_cast<int>(t);
+}
+
+//____________________________________________________________________________//
+
+void
+print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t )
+{
+ ostr << std::hex
+ // showbase is only available for new style streams:
+#if BOOST_TEST_USE_STD_LOCALE
+ << std::showbase
+#else
+ << "0x"
+#endif
+ << static_cast<int>(t);
+}
+
+//____________________________________________________________________________//
+
+void
+print_log_value<char const*>::operator()( std::ostream& ostr, char const* t )
+{
+ ostr << ( t ? t : "null string" );
+}
+
+//____________________________________________________________________________//
+
+void
+print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t )
+{
+ ostr << ( t ? t : L"null string" );
+}
+
+//____________________________________________________________________________//
+
+namespace tt_detail {
+
+// ************************************************************************** //
+// ************** TOOL BOX Implementation ************** //
+// ************************************************************************** //
+
+using ::ndnboost::unit_test::lazy_ostream;
+
+bool
+check_impl( predicate_result const& pr, lazy_ostream const& check_descr,
+ const_string file_name, std::size_t line_num,
+ tool_level tl, check_type ct,
+ std::size_t num_of_args, ... )
+{
+ using namespace unit_test;
+
+ if( !framework::is_initialized() )
+ throw std::runtime_error( "can't use testing tools before framework is initialized" );
+
+ if( !!pr )
+ tl = PASS;
+
+ log_level ll;
+ char const* prefix;
+ char const* suffix;
+
+ switch( tl ) {
+ case PASS:
+ ll = log_successful_tests;
+ prefix = "check ";
+ suffix = " passed";
+ break;
+ case WARN:
+ ll = log_warnings;
+ prefix = "condition ";
+ suffix = " is not satisfied";
+ break;
+ case CHECK:
+ ll = log_all_errors;
+ prefix = "check ";
+ suffix = " failed";
+ break;
+ case REQUIRE:
+ ll = log_fatal_errors;
+ prefix = "critical check ";
+ suffix = " failed";
+ break;
+ default:
+ return true;
+ }
+
+ switch( ct ) {
+ case CHECK_PRED:
+ unit_test_log << unit_test::log::begin( file_name, line_num )
+ << ll << prefix << check_descr << suffix;
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+
+ case CHECK_MSG:
+ unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
+
+ if( tl == PASS )
+ unit_test_log << prefix << "'" << check_descr << "'" << suffix;
+ else
+ unit_test_log << check_descr;
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+
+ case CHECK_EQUAL:
+ case CHECK_NE:
+ case CHECK_LT:
+ case CHECK_LE:
+ case CHECK_GT:
+ case CHECK_GE: {
+ static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " };
+ static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " };
+
+ va_list args;
+
+ va_start( args, num_of_args );
+ char const* arg1_descr = va_arg( args, char const* );
+ lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
+ char const* arg2_descr = va_arg( args, char const* );
+ lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
+
+ unit_test_log << unit_test::log::begin( file_name, line_num )
+ << ll << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix;
+
+ if( tl != PASS )
+ unit_test_log << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ;
+
+ va_end( args );
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+
+ case CHECK_CLOSE:
+ case CHECK_CLOSE_FRACTION: {
+ va_list args;
+
+ va_start( args, num_of_args );
+ char const* arg1_descr = va_arg( args, char const* );
+ lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
+ char const* arg2_descr = va_arg( args, char const* );
+ lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
+ /* toler_descr = */ va_arg( args, char const* );
+ lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* );
+
+ unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
+
+ unit_test_log << "difference{" << pr.message() << (ct == CHECK_CLOSE ? "%" : "")
+ << "} between " << arg1_descr << "{" << *arg1_val
+ << "} and " << arg2_descr << "{" << *arg2_val
+ << ( tl == PASS ? "} doesn't exceed " : "} exceeds " )
+ << *toler_val;
+ if( ct == CHECK_CLOSE )
+ unit_test_log << "%";
+
+ va_end( args );
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+ case CHECK_SMALL: {
+ va_list args;
+
+ va_start( args, num_of_args );
+ char const* arg1_descr = va_arg( args, char const* );
+ lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
+ /* toler_descr = */ va_arg( args, char const* );
+ lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* );
+
+ unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
+
+ unit_test_log << "absolute value of " << arg1_descr << "{" << *arg1_val << "}"
+ << ( tl == PASS ? " doesn't exceed " : " exceeds " )
+ << *toler_val;
+
+ va_end( args );
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+
+ case CHECK_PRED_WITH_ARGS: {
+ unit_test_log << unit_test::log::begin( file_name, line_num )
+ << ll << prefix << check_descr;
+
+ // print predicate call description
+ {
+ va_list args;
+ va_start( args, num_of_args );
+
+ unit_test_log << "( ";
+ for( std::size_t i = 0; i < num_of_args; ++i ) {
+ unit_test_log << va_arg( args, char const* );
+ va_arg( args, lazy_ostream const* ); // skip argument value;
+
+ if( i != num_of_args-1 )
+ unit_test_log << ", ";
+ }
+ unit_test_log << " )" << suffix;
+ va_end( args );
+ }
+
+ if( tl != PASS ) {
+ va_list args;
+ va_start( args, num_of_args );
+
+ unit_test_log << " for ( ";
+ for( std::size_t i = 0; i < num_of_args; ++i ) {
+ va_arg( args, char const* ); // skip argument description;
+ unit_test_log << *va_arg( args, lazy_ostream const* );
+
+ if( i != num_of_args-1 )
+ unit_test_log << ", ";
+ }
+ unit_test_log << " )";
+ va_end( args );
+ }
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+
+ case CHECK_EQUAL_COLL: {
+ va_list args;
+
+ va_start( args, num_of_args );
+ char const* left_begin_descr = va_arg( args, char const* );
+ char const* left_end_descr = va_arg( args, char const* );
+ char const* right_begin_descr = va_arg( args, char const* );
+ char const* right_end_descr = va_arg( args, char const* );
+
+ unit_test_log << unit_test::log::begin( file_name, line_num )
+ << ll << prefix
+ << "{ " << left_begin_descr << ", " << left_end_descr << " } == { "
+ << right_begin_descr << ", " << right_end_descr << " }"
+ << suffix;
+
+ va_end( args );
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+
+ case CHECK_BITWISE_EQUAL: {
+ va_list args;
+
+ va_start( args, num_of_args );
+ char const* left_descr = va_arg( args, char const* );
+ char const* right_descr = va_arg( args, char const* );
+
+ unit_test_log << unit_test::log::begin( file_name, line_num )
+ << ll << prefix << left_descr << " =.= " << right_descr << suffix;
+
+ va_end( args );
+
+ if( !pr.has_empty_message() )
+ unit_test_log << ". " << pr.message();
+
+ unit_test_log << unit_test::log::end();
+ break;
+ }
+ }
+
+ switch( tl ) {
+ case PASS:
+ framework::assertion_result( true );
+ return true;
+
+ case WARN:
+ return false;
+
+ case CHECK:
+ framework::assertion_result( false );
+ return false;
+
+ case REQUIRE:
+ framework::assertion_result( false );
+
+ framework::test_unit_aborted( framework::current_test_case() );
+
+ throw execution_aborted();
+ }
+
+ return true;
+}
+
+//____________________________________________________________________________//
+
+predicate_result
+equal_impl( char const* left, char const* right )
+{
+ return (left && right) ? std::strcmp( left, right ) == 0 : (left == right);
+}
+
+//____________________________________________________________________________//
+
+#if !defined( BOOST_NO_CWCHAR )
+
+predicate_result
+equal_impl( wchar_t const* left, wchar_t const* right )
+{
+ return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right);
+}
+
+#endif // !defined( BOOST_NO_CWCHAR )
+
+//____________________________________________________________________________//
+
+bool
+is_defined_impl( const_string symbol_name, const_string symbol_value )
+{
+ symbol_value.trim_left( 2 );
+ return symbol_name != symbol_value;
+}
+
+//____________________________________________________________________________//
+
+} // namespace tt_detail
+
+// ************************************************************************** //
+// ************** output_test_stream ************** //
+// ************************************************************************** //
+
+struct output_test_stream::Impl
+{
+ std::fstream m_pattern;
+ bool m_match_or_save;
+ bool m_text_or_binary;
+ std::string m_synced_string;
+
+ char get_char()
+ {
+ char res;
+ do {
+ m_pattern.get( res );
+ } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
+
+ return res;
+ }
+
+ void check_and_fill( predicate_result& res )
+ {
+ if( !res.p_predicate_value )
+ res.message() << "Output content: \"" << m_synced_string << '\"';
+ }
+};
+
+//____________________________________________________________________________//
+
+output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary )
+: m_pimpl( new Impl )
+{
+ if( !pattern_file_name.is_empty() ) {
+ std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out;
+ if( !text_or_binary )
+ m |= std::ios::binary;
+
+ m_pimpl->m_pattern.open( pattern_file_name.begin(), m );
+
+ BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(),
+ "Can't open pattern file " << pattern_file_name
+ << " for " << (match_or_save ? "reading" : "writing") );
+ }
+
+ m_pimpl->m_match_or_save = match_or_save;
+ m_pimpl->m_text_or_binary = text_or_binary;
+}
+
+//____________________________________________________________________________//
+
+output_test_stream::~output_test_stream()
+{
+ delete m_pimpl;
+}
+
+//____________________________________________________________________________//
+
+predicate_result
+output_test_stream::is_empty( bool flush_stream )
+{
+ sync();
+
+ result_type res( m_pimpl->m_synced_string.empty() );
+
+ m_pimpl->check_and_fill( res );
+
+ if( flush_stream )
+ flush();
+
+ return res;
+}
+
+//____________________________________________________________________________//
+
+predicate_result
+output_test_stream::check_length( std::size_t length_, bool flush_stream )
+{
+ sync();
+
+ result_type res( m_pimpl->m_synced_string.length() == length_ );
+
+ m_pimpl->check_and_fill( res );
+
+ if( flush_stream )
+ flush();
+
+ return res;
+}
+
+//____________________________________________________________________________//
+
+predicate_result
+output_test_stream::is_equal( const_string arg, bool flush_stream )
+{
+ sync();
+
+ result_type res( const_string( m_pimpl->m_synced_string ) == arg );
+
+ m_pimpl->check_and_fill( res );
+
+ if( flush_stream )
+ flush();
+
+ return res;
+}
+
+//____________________________________________________________________________//
+
+predicate_result
+output_test_stream::match_pattern( bool flush_stream )
+{
+ sync();
+
+ result_type result( true );
+
+ if( !m_pimpl->m_pattern.is_open() ) {
+ result = false;
+ result.message() << "Pattern file can't be opened!";
+ }
+ else {
+ if( m_pimpl->m_match_or_save ) {
+ for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) {
+ char c = m_pimpl->get_char();
+
+ result = !m_pimpl->m_pattern.fail() &&
+ !m_pimpl->m_pattern.eof() &&
+ (m_pimpl->m_synced_string[i] == c);
+
+ if( !result ) {
+ std::string::size_type suffix_size = (std::min)( m_pimpl->m_synced_string.length() - i,
+ static_cast<std::string::size_type>(5) );
+
+ // try to log area around the mismatch
+ result.message() << "Mismatch at position " << i << '\n'
+ << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n'
+ << "..." << c;
+
+ std::string::size_type counter = suffix_size;
+ while( --counter ) {
+ char c = m_pimpl->get_char();
+
+ if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() )
+ break;
+
+ result.message() << c;
+ }
+
+ result.message() << "...";
+
+ // skip rest of the bytes. May help for further matching
+ m_pimpl->m_pattern.ignore(
+ static_cast<std::streamsize>( m_pimpl->m_synced_string.length() - i - suffix_size) );
+ break;
+ }
+ }
+ }
+ else {
+ m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(),
+ static_cast<std::streamsize>( m_pimpl->m_synced_string.length() ) );
+ m_pimpl->m_pattern.flush();
+ }
+ }
+
+ if( flush_stream )
+ flush();
+
+ return result;
+}
+
+//____________________________________________________________________________//
+
+void
+output_test_stream::flush()
+{
+ m_pimpl->m_synced_string.erase();
+
+#ifndef BOOST_NO_STRINGSTREAM
+ str( std::string() );
+#else
+ seekp( 0, std::ios::beg );
+#endif
+}
+
+//____________________________________________________________________________//
+
+std::size_t
+output_test_stream::length()
+{
+ sync();
+
+ return m_pimpl->m_synced_string.length();
+}
+
+//____________________________________________________________________________//
+
+void
+output_test_stream::sync()
+{
+#ifdef BOOST_NO_STRINGSTREAM
+ m_pimpl->m_synced_string.assign( str(), pcount() );
+ freeze( false );
+#else
+ m_pimpl->m_synced_string = str();
+#endif
+}
+
+//____________________________________________________________________________//
+
+} // namespace test_tools
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER
diff --git a/ndnboost/test/impl/unit_test_log.ipp b/ndnboost/test/impl/unit_test_log.ipp
new file mode 100644
index 0000000..63d089e
--- /dev/null
+++ b/ndnboost/test/impl/unit_test_log.ipp
@@ -0,0 +1,444 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : implemets Unit Test Log
+// ***************************************************************************
+
+#ifndef BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
+#define BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/unit_test_log.hpp>
+#include <ndnboost/test/unit_test_log_formatter.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/execution_monitor.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+#include <ndnboost/test/utils/basic_cstring/compare.hpp>
+
+#include <ndnboost/test/output/compiler_log_formatter.hpp>
+#include <ndnboost/test/output/xml_log_formatter.hpp>
+
+// Boost
+#include <ndnboost/scoped_ptr.hpp>
+#include <ndnboost/io/ios_state.hpp>
+typedef ::ndnboost::io::ios_base_all_saver io_saver_type;
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** entry_value_collector ************** //
+// ************************************************************************** //
+
+namespace ut_detail {
+
+entry_value_collector const&
+entry_value_collector::operator<<( lazy_ostream const& v ) const
+{
+ unit_test_log << v;
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+entry_value_collector const&
+entry_value_collector::operator<<( const_string v ) const
+{
+ unit_test_log << v;
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+entry_value_collector::~entry_value_collector()
+{
+ if( m_last )
+ unit_test_log << log::end();
+}
+
+//____________________________________________________________________________//
+
+} // namespace ut_detail
+
+// ************************************************************************** //
+// ************** unit_test_log ************** //
+// ************************************************************************** //
+
+namespace {
+
+struct unit_test_log_impl {
+ // Constructor
+ unit_test_log_impl()
+ : m_stream( runtime_config::log_sink() )
+ , m_stream_state_saver( new io_saver_type( *m_stream ) )
+ , m_threshold_level( log_all_errors )
+ , m_log_formatter( new output::compiler_log_formatter )
+ {
+ }
+
+ // log data
+ typedef scoped_ptr<unit_test_log_formatter> formatter_ptr;
+ typedef scoped_ptr<io_saver_type> saver_ptr;
+
+ std::ostream* m_stream;
+ saver_ptr m_stream_state_saver;
+ log_level m_threshold_level;
+ formatter_ptr m_log_formatter;
+
+ // entry data
+ bool m_entry_in_progress;
+ bool m_entry_started;
+ log_entry_data m_entry_data;
+
+ // check point data
+ log_checkpoint_data m_checkpoint_data;
+
+ // helper functions
+ std::ostream& stream() { return *m_stream; }
+ void set_checkpoint( const_string file, std::size_t line_num, const_string msg )
+ {
+ assign_op( m_checkpoint_data.m_message, msg, 0 );
+ m_checkpoint_data.m_file_name = file;
+ m_checkpoint_data.m_line_num = line_num;
+ }
+};
+
+unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; }
+
+} // local namespace
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_start( counter_t test_cases_amount )
+{
+ if( s_log_impl().m_threshold_level == log_nothing )
+ return;
+
+ s_log_impl().m_log_formatter->log_start( s_log_impl().stream(), test_cases_amount );
+
+ if( runtime_config::show_build_info() )
+ s_log_impl().m_log_formatter->log_build_info( s_log_impl().stream() );
+
+ s_log_impl().m_entry_in_progress = false;
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_finish()
+{
+ if( s_log_impl().m_threshold_level == log_nothing )
+ return;
+
+ s_log_impl().m_log_formatter->log_finish( s_log_impl().stream() );
+
+ s_log_impl().stream().flush();
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_aborted()
+{
+ BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted";
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_unit_start( test_unit const& tu )
+{
+ if( s_log_impl().m_threshold_level > log_test_units )
+ return;
+
+ if( s_log_impl().m_entry_in_progress )
+ *this << log::end();
+
+ s_log_impl().m_log_formatter->test_unit_start( s_log_impl().stream(), tu );
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed )
+{
+ if( s_log_impl().m_threshold_level > log_test_units )
+ return;
+
+ s_log_impl().m_checkpoint_data.clear();
+
+ if( s_log_impl().m_entry_in_progress )
+ *this << log::end();
+
+ s_log_impl().m_log_formatter->test_unit_finish( s_log_impl().stream(), tu, elapsed );
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_unit_skipped( test_unit const& tu )
+{
+ if( s_log_impl().m_threshold_level > log_test_units )
+ return;
+
+ if( s_log_impl().m_entry_in_progress )
+ *this << log::end();
+
+ s_log_impl().m_log_formatter->test_unit_skipped( s_log_impl().stream(), tu );
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::test_unit_aborted( test_unit const& )
+{
+ // do nothing
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::assertion_result( bool )
+{
+ // do nothing
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::exception_caught( execution_exception const& ex )
+{
+ log_level l =
+ ex.code() <= execution_exception::cpp_exception_error ? log_cpp_exception_errors :
+ (ex.code() <= execution_exception::timeout_error ? log_system_errors
+ : log_fatal_errors );
+
+ if( l >= s_log_impl().m_threshold_level ) {
+ 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 );
+ }
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg )
+{
+ s_log_impl().set_checkpoint( file, line_num, msg );
+}
+
+//____________________________________________________________________________//
+
+char
+set_unix_slash( char in )
+{
+ return in == '\\' ? '/' : in;
+}
+
+unit_test_log_t&
+unit_test_log_t::operator<<( log::begin const& b )
+{
+ if( s_log_impl().m_entry_in_progress )
+ *this << log::end();
+
+ s_log_impl().m_stream_state_saver->restore();
+
+ s_log_impl().m_entry_data.clear();
+
+ assign_op( s_log_impl().m_entry_data.m_file_name, b.m_file_name, 0 );
+
+ // normalize file name
+ std::transform( s_log_impl().m_entry_data.m_file_name.begin(), s_log_impl().m_entry_data.m_file_name.end(),
+ s_log_impl().m_entry_data.m_file_name.begin(),
+ &set_unix_slash );
+
+ s_log_impl().m_entry_data.m_line_num = b.m_line_num;
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+unit_test_log_t&
+unit_test_log_t::operator<<( log::end const& )
+{
+ if( s_log_impl().m_entry_in_progress )
+ s_log_impl().m_log_formatter->log_entry_finish( s_log_impl().stream() );
+
+ s_log_impl().m_entry_in_progress = false;
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+unit_test_log_t&
+unit_test_log_t::operator<<( log_level l )
+{
+ s_log_impl().m_entry_data.m_level = l;
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+ut_detail::entry_value_collector
+unit_test_log_t::operator()( log_level l )
+{
+ *this << l;
+
+ return ut_detail::entry_value_collector();
+}
+
+//____________________________________________________________________________//
+
+bool
+unit_test_log_t::log_entry_start()
+{
+ if( s_log_impl().m_entry_in_progress )
+ return true;
+
+ switch( s_log_impl().m_entry_data.m_level ) {
+ case log_successful_tests:
+ s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
+ unit_test_log_formatter::BOOST_UTL_ET_INFO );
+ break;
+ case log_messages:
+ s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
+ unit_test_log_formatter::BOOST_UTL_ET_MESSAGE );
+ break;
+ case log_warnings:
+ s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
+ unit_test_log_formatter::BOOST_UTL_ET_WARNING );
+ break;
+ case log_all_errors:
+ case log_cpp_exception_errors:
+ case log_system_errors:
+ s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
+ unit_test_log_formatter::BOOST_UTL_ET_ERROR );
+ break;
+ case log_fatal_errors:
+ s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
+ unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR );
+ break;
+ case log_nothing:
+ case log_test_units:
+ case invalid_log_level:
+ return false;
+ }
+
+ s_log_impl().m_entry_in_progress = true;
+
+ return true;
+}
+
+//____________________________________________________________________________//
+
+unit_test_log_t&
+unit_test_log_t::operator<<( const_string value )
+{
+ if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() )
+ s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value );
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+unit_test_log_t&
+unit_test_log_t::operator<<( lazy_ostream const& value )
+{
+ if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() )
+ s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value );
+
+ return *this;
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::set_stream( std::ostream& str )
+{
+ if( s_log_impl().m_entry_in_progress )
+ return;
+
+ s_log_impl().m_stream = &str;
+ s_log_impl().m_stream_state_saver.reset( new io_saver_type( str ) );
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::set_threshold_level( log_level lev )
+{
+ if( s_log_impl().m_entry_in_progress || lev == invalid_log_level )
+ return;
+
+ s_log_impl().m_threshold_level = lev;
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::set_format( output_format log_format )
+{
+ if( s_log_impl().m_entry_in_progress )
+ return;
+
+ if( log_format == CLF )
+ set_formatter( new output::compiler_log_formatter );
+ else
+ set_formatter( new output::xml_log_formatter );
+}
+
+//____________________________________________________________________________//
+
+void
+unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter )
+{
+ s_log_impl().m_log_formatter.reset( the_formatter );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** unit_test_log_formatter ************** //
+// ************************************************************************** //
+
+void
+unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value )
+{
+ log_entry_value( ostr, (wrap_stringstream().ref() << value).str() );
+}
+
+//____________________________________________________________________________//
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
diff --git a/ndnboost/test/impl/unit_test_main.ipp b/ndnboost/test/impl/unit_test_main.ipp
new file mode 100644
index 0000000..bde871f
--- /dev/null
+++ b/ndnboost/test/impl/unit_test_main.ipp
@@ -0,0 +1,246 @@
+// (C) Copyright Gennadiy Rozental 2001-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : main function implementation for Unit Test Framework
+// ***************************************************************************
+
+#ifndef BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER
+#define BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/results_reporter.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+#if !defined(__BORLANDC__) && !BOOST_WORKAROUND( BOOST_MSVC, < 1300 ) && !BOOST_WORKAROUND( __SUNPRO_CC, < 0x5100 )
+#define BOOST_TEST_SUPPORT_RUN_BY_NAME
+#include <ndnboost/test/utils/iterator/token_iterator.hpp>
+#endif
+
+// Boost
+#include <ndnboost/cstdlib.hpp>
+#include <ndnboost/bind.hpp>
+
+// STL
+#include <stdexcept>
+#include <iostream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** test_case_filter ************** //
+// ************************************************************************** //
+
+class test_case_filter : public test_tree_visitor {
+public:
+ struct single_filter {
+ single_filter( const_string in )
+ {
+ if( in == "*" )
+ m_kind = SFK_ALL;
+ else if( first_char( in ) == '*' && last_char( in ) == '*' ) {
+ m_kind = SFK_SUBSTR;
+ m_value = in.substr( 1, in.size()-1 );
+ }
+ else if( first_char( in ) == '*' ) {
+ m_kind = SFK_TRAILING;
+ m_value = in.substr( 1 );
+ }
+ else if( last_char( in ) == '*' ) {
+ m_kind = SFK_LEADING;
+ m_value = in.substr( 0, in.size()-1 );
+ }
+ else {
+ m_kind = SFK_MATCH;
+ m_value = in;
+ }
+ };
+
+ bool pass( test_unit const& tu ) const
+ {
+ const_string name( tu.p_name );
+
+ switch( m_kind ) {
+ default:
+ case SFK_ALL:
+ return true;
+
+ case SFK_LEADING:
+ return name.substr( 0, m_value.size() ) == m_value;
+
+ case SFK_TRAILING:
+ return name.size() >= m_value.size() && name.substr( name.size() - m_value.size() ) == m_value;
+
+ case SFK_SUBSTR:
+ return name.find( m_value ) != const_string::npos;
+
+ case SFK_MATCH:
+ return m_value == tu.p_name.get();
+ }
+ }
+ enum kind { SFK_ALL, SFK_LEADING, SFK_TRAILING, SFK_SUBSTR, SFK_MATCH };
+
+ kind m_kind;
+ const_string m_value;
+ };
+ // Constructor
+#ifndef BOOST_TEST_SUPPORT_RUN_BY_NAME
+ explicit test_case_filter( const_string ) : m_depth( 0 ) {}
+#else
+ explicit test_case_filter( const_string tc_to_run )
+ : m_depth( 0 )
+ {
+ string_token_iterator tit( tc_to_run, (dropped_delimeters = "/", kept_delimeters = dt_none) );
+
+ while( tit != string_token_iterator() ) {
+ m_filters.push_back(
+ std::vector<single_filter>( string_token_iterator( *tit, (dropped_delimeters = ",", kept_delimeters = dt_none) ),
+ string_token_iterator() ) );
+
+ ++tit;
+ }
+ }
+#endif
+
+ void filter_unit( test_unit const& tu )
+ {
+ if( (++m_depth - 1) > m_filters.size() ) {
+ tu.p_enabled.value = true;
+ return;
+ }
+
+ if( m_depth == 1 )
+ return;
+
+ std::vector<single_filter> const& filters = m_filters[m_depth-2];
+
+ tu.p_enabled.value =
+ std::find_if( filters.begin(), filters.end(), bind( &single_filter::pass, _1, ndnboost::ref(tu) ) ) != filters.end();
+ }
+
+ // test tree visitor interface
+ virtual void visit( test_case const& tc )
+ {
+ if( m_depth < m_filters.size() ) {
+ tc.p_enabled.value = false;
+ return;
+ }
+
+ filter_unit( tc );
+
+ --m_depth;
+ }
+
+ virtual bool test_suite_start( test_suite const& ts )
+ {
+ filter_unit( ts );
+
+ if( !ts.p_enabled )
+ --m_depth;
+
+ return ts.p_enabled;
+ }
+
+ virtual void test_suite_finish( test_suite const& ) { --m_depth; }
+
+private:
+ // Data members
+ std::vector<std::vector<single_filter> > m_filters;
+ unsigned m_depth;
+};
+
+// ************************************************************************** //
+// ************** unit_test_main ************** //
+// ************************************************************************** //
+
+int BOOST_TEST_DECL
+unit_test_main( init_unit_test_func init_func, int argc, char* argv[] )
+{
+ try {
+ framework::init( init_func, argc, argv );
+
+ if( !runtime_config::test_to_run().is_empty() ) {
+ test_case_filter filter( runtime_config::test_to_run() );
+
+ traverse_test_tree( framework::master_test_suite().p_id, filter );
+ }
+
+ framework::run();
+
+ results_reporter::make_report();
+
+ return runtime_config::no_result_code()
+ ? ndnboost::exit_success
+ : results_collector.results( framework::master_test_suite().p_id ).result_code();
+ }
+ catch( framework::nothing_to_test const& ) {
+ return ndnboost::exit_success;
+ }
+ catch( framework::internal_error const& ex ) {
+ results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl;
+
+ return ndnboost::exit_exception_failure;
+ }
+ catch( framework::setup_error const& ex ) {
+ results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl;
+
+ return ndnboost::exit_exception_failure;
+ }
+ catch( ... ) {
+ results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl;
+
+ return ndnboost::exit_exception_failure;
+ }
+}
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+#if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN)
+
+// ************************************************************************** //
+// ************** main function for tests using lib ************** //
+// ************************************************************************** //
+
+int BOOST_TEST_CALL_DECL
+main( int argc, char* argv[] )
+{
+ // prototype for user's unit test init function
+#ifdef BOOST_TEST_ALTERNATIVE_INIT_API
+ extern bool init_unit_test();
+
+ ndnboost::unit_test::init_unit_test_func init_func = &init_unit_test;
+#else
+ extern ::ndnboost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] );
+
+ ndnboost::unit_test::init_unit_test_func init_func = &init_unit_test_suite;
+#endif
+
+ return ::ndnboost::unit_test::unit_test_main( init_func, argc, argv );
+}
+
+#endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER
diff --git a/ndnboost/test/impl/unit_test_monitor.ipp b/ndnboost/test/impl/unit_test_monitor.ipp
new file mode 100644
index 0000000..0932bf3
--- /dev/null
+++ b/ndnboost/test/impl/unit_test_monitor.ipp
@@ -0,0 +1,101 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 49312 $
+//
+// Description : implements specific subclass of Executon Monitor used by Unit
+// Test Framework to monitor test cases run.
+// ***************************************************************************
+
+#ifndef BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER
+#define BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/unit_test_monitor.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/test_tools.hpp>
+#include <ndnboost/test/framework.hpp>
+
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace {
+
+template<typename F>
+struct zero_return_wrapper_t {
+ explicit zero_return_wrapper_t( F const& f ) : m_f( f ) {}
+
+ int operator()() { m_f(); return 0; }
+
+ F const& m_f;
+};
+
+template<typename F>
+zero_return_wrapper_t<F>
+zero_return_wrapper( F const& f )
+{
+ return zero_return_wrapper_t<F>( f );
+}
+
+}
+
+// ************************************************************************** //
+// ************** unit_test_monitor ************** //
+// ************************************************************************** //
+
+unit_test_monitor_t::error_level
+unit_test_monitor_t::execute_and_translate( test_case const& tc )
+{
+ try {
+ p_catch_system_errors.value = runtime_config::catch_sys_errors();
+ p_timeout.value = tc.p_timeout.get();
+ p_auto_start_dbg.value = runtime_config::auto_start_dbg();
+ p_use_alt_stack.value = runtime_config::use_alt_stack();
+ p_detect_fp_exceptions.value = runtime_config::detect_fp_exceptions();
+
+ execute( callback0<int>( zero_return_wrapper( tc.test_func() ) ) );
+ }
+ catch( execution_exception const& ex ) {
+ framework::exception_caught( ex );
+ framework::test_unit_aborted( framework::current_test_case() );
+
+ // translate execution_exception::error_code to error_level
+ switch( ex.code() ) {
+ case execution_exception::no_error: return test_ok;
+ case execution_exception::user_error: return unexpected_exception;
+ case execution_exception::cpp_exception_error: return unexpected_exception;
+ case execution_exception::system_error: return os_exception;
+ case execution_exception::timeout_error: return os_timeout;
+ case execution_exception::user_fatal_error:
+ case execution_exception::system_fatal_error: return fatal_error;
+ default: return unexpected_exception;
+ }
+ }
+
+ return test_ok;
+}
+
+//____________________________________________________________________________//
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER
diff --git a/ndnboost/test/impl/unit_test_parameters.ipp b/ndnboost/test/impl/unit_test_parameters.ipp
new file mode 100644
index 0000000..ffc29c9
--- /dev/null
+++ b/ndnboost/test/impl/unit_test_parameters.ipp
@@ -0,0 +1,527 @@
+// (C) Copyright Gennadiy Rozental 2001-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 63640 $
+//
+// Description : simple implementation for Unit Test Framework parameter
+// handling routines. May be rewritten in future to use some kind of
+// command-line arguments parsing facility and environment variable handling
+// facility
+// ***************************************************************************
+
+#ifndef BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER
+#define BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+#include <ndnboost/test/utils/basic_cstring/basic_cstring.hpp>
+#include <ndnboost/test/utils/basic_cstring/compare.hpp>
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+#include <ndnboost/test/utils/fixed_mapping.hpp>
+#include <ndnboost/test/debug.hpp>
+#include <ndnboost/test/framework.hpp>
+
+// Boost.Runtime.Param
+#include <ndnboost/test/utils/runtime/cla/dual_name_parameter.hpp>
+#include <ndnboost/test/utils/runtime/cla/parser.hpp>
+
+namespace rt = ndnboost::runtime;
+namespace cla = rt::cla;
+
+
+#ifndef UNDER_CE
+#include <ndnboost/test/utils/runtime/env/variable.hpp>
+
+namespace env = rt::env;
+#endif
+
+
+// Boost
+#include <ndnboost/config.hpp>
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+#include <ndnboost/lexical_cast.hpp>
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+// STL
+#include <map>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::getenv; using ::strncmp; using ::strcmp; }
+# endif
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** input operations for unit_test's enums ************** //
+// ************************************************************************** //
+
+std::istream&
+operator>>( std::istream& in, unit_test::log_level& ll )
+{
+ static fixed_mapping<const_string,unit_test::log_level,case_ins_less<char const> > log_level_name(
+ "all" , log_successful_tests,
+ "success" , log_successful_tests,
+ "test_suite" , log_test_units,
+ "unit_scope" , log_test_units,
+ "message" , log_messages,
+ "warning" , log_warnings,
+ "error" , log_all_errors,
+ "cpp_exception" , log_cpp_exception_errors,
+ "system_error" , log_system_errors,
+ "fatal_error" , log_fatal_errors,
+ "nothing" , log_nothing,
+
+ invalid_log_level
+ );
+
+ std::string val;
+ in >> val;
+
+ ll = log_level_name[val];
+ BOOST_TEST_SETUP_ASSERT( ll != unit_test::invalid_log_level, "invalid log level " + val );
+
+ return in;
+}
+
+//____________________________________________________________________________//
+
+std::istream&
+operator>>( std::istream& in, unit_test::report_level& rl )
+{
+ fixed_mapping<const_string,unit_test::report_level,case_ins_less<char const> > report_level_name (
+ "confirm", CONFIRMATION_REPORT,
+ "short", SHORT_REPORT,
+ "detailed", DETAILED_REPORT,
+ "no", NO_REPORT,
+
+ INV_REPORT_LEVEL
+ );
+
+ std::string val;
+ in >> val;
+
+ rl = report_level_name[val];
+ BOOST_TEST_SETUP_ASSERT( rl != INV_REPORT_LEVEL, "invalid report level " + val );
+
+ return in;
+}
+
+//____________________________________________________________________________//
+
+std::istream&
+operator>>( std::istream& in, unit_test::output_format& of )
+{
+ fixed_mapping<const_string,unit_test::output_format,case_ins_less<char const> > output_format_name (
+ "HRF", unit_test::CLF,
+ "CLF", unit_test::CLF,
+ "XML", unit_test::XML,
+
+ unit_test::INV_OF
+ );
+
+ std::string val;
+ in >> val;
+
+ of = output_format_name[val];
+ BOOST_TEST_SETUP_ASSERT( of != unit_test::INV_OF, "invalid output format " + val );
+
+ return in;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** runtime_config ************** //
+// ************************************************************************** //
+
+namespace runtime_config {
+
+namespace {
+
+// framework parameters and corresponding command-line arguments
+std::string AUTO_START_DBG = "auto_start_dbg";
+std::string BREAK_EXEC_PATH = "break_exec_path";
+std::string BUILD_INFO = "build_info";
+std::string CATCH_SYS_ERRORS = "catch_system_errors";
+std::string DETECT_FP_EXCEPT = "detect_fp_exceptions";
+std::string DETECT_MEM_LEAKS = "detect_memory_leaks";
+std::string LOG_FORMAT = "log_format";
+std::string LOG_LEVEL = "log_level";
+std::string LOG_SINK = "log_sink";
+std::string OUTPUT_FORMAT = "output_format";
+std::string RANDOM_SEED = "random";
+std::string REPORT_FORMAT = "report_format";
+std::string REPORT_LEVEL = "report_level";
+std::string REPORT_SINK = "report_sink";
+std::string RESULT_CODE = "result_code";
+std::string TESTS_TO_RUN = "run_test";
+std::string SAVE_TEST_PATTERN = "save_pattern";
+std::string SHOW_PROGRESS = "show_progress";
+std::string USE_ALT_STACK = "use_alt_stack";
+
+fixed_mapping<const_string,const_string> parameter_2_env_var(
+ AUTO_START_DBG , "BOOST_TEST_AUTO_START_DBG",
+ BREAK_EXEC_PATH , "BOOST_TEST_BREAK_EXEC_PATH",
+ BUILD_INFO , "BOOST_TEST_BUILD_INFO",
+ CATCH_SYS_ERRORS , "BOOST_TEST_CATCH_SYSTEM_ERRORS",
+ DETECT_FP_EXCEPT , "BOOST_TEST_DETECT_FP_EXCEPTIONS",
+ DETECT_MEM_LEAKS , "BOOST_TEST_DETECT_MEMORY_LEAK",
+ LOG_FORMAT , "BOOST_TEST_LOG_FORMAT",
+ LOG_LEVEL , "BOOST_TEST_LOG_LEVEL",
+ LOG_SINK , "BOOST_TEST_LOG_SINK",
+ OUTPUT_FORMAT , "BOOST_TEST_OUTPUT_FORMAT",
+ RANDOM_SEED , "BOOST_TEST_RANDOM",
+ REPORT_FORMAT , "BOOST_TEST_REPORT_FORMAT",
+ REPORT_LEVEL , "BOOST_TEST_REPORT_LEVEL",
+ REPORT_SINK , "BOOST_TEST_REPORT_SINK",
+ RESULT_CODE , "BOOST_TEST_RESULT_CODE",
+ TESTS_TO_RUN , "BOOST_TESTS_TO_RUN",
+ SAVE_TEST_PATTERN , "BOOST_TEST_SAVE_PATTERN",
+ SHOW_PROGRESS , "BOOST_TEST_SHOW_PROGRESS",
+ USE_ALT_STACK , "BOOST_TEST_USE_ALT_STACK",
+
+ ""
+);
+
+//____________________________________________________________________________//
+
+// storage for the CLAs
+cla::parser s_cla_parser;
+std::string s_empty;
+
+output_format s_report_format;
+output_format s_log_format;
+
+//____________________________________________________________________________//
+
+template<typename T>
+T
+retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser, T const& default_value = T(), T const& optional_value = T() )
+{
+ rt::const_argument_ptr arg = s_cla_parser[parameter_name];
+ if( arg ) {
+ if( rtti::type_id<T>() == rtti::type_id<bool>() ||
+ !static_cast<cla::parameter const&>( arg->p_formal_parameter.get() ).p_optional_value )
+ return s_cla_parser.get<T>( parameter_name );
+
+ optional<T> val = s_cla_parser.get<optional<T> >( parameter_name );
+ if( val )
+ return *val;
+ else
+ return optional_value;
+ }
+
+ ndnboost::optional<T> v;
+
+#ifndef UNDER_CE
+ env::get( parameter_2_env_var[parameter_name], v );
+#endif
+
+ if( v )
+ return *v;
+ else
+ return default_value;
+}
+
+//____________________________________________________________________________//
+
+} // local namespace
+
+void
+init( int& argc, char** argv )
+{
+ using namespace cla;
+
+ try {
+ s_cla_parser - cla::ignore_mismatch
+ << cla::dual_name_parameter<bool>( AUTO_START_DBG + "|d" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Automatically starts debugger if system level error (signal) occurs")
+ << cla::named_parameter<std::string>( BREAK_EXEC_PATH )
+ - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "For the exception safety testing allows to break at specific execution path")
+ << cla::dual_name_parameter<bool>( BUILD_INFO + "|i" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Shows library build information" )
+ << cla::dual_name_parameter<bool>( CATCH_SYS_ERRORS + "|s" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Allows to switch between catching and ignoring system errors (signals)")
+ << cla::named_parameter<bool>( DETECT_FP_EXCEPT )
+ - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "Allows to switch between catching and ignoring floating point exceptions")
+ << cla::named_parameter<long>( DETECT_MEM_LEAKS )
+ - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "Allows to switch between catching and ignoring memory leaks")
+ << cla::dual_name_parameter<unit_test::output_format>( LOG_FORMAT + "|f" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies log format")
+ << cla::dual_name_parameter<unit_test::log_level>( LOG_LEVEL + "|l" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies log level")
+ << cla::dual_name_parameter<std::string>( LOG_SINK + "|k" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies log sink:stdout(default),stderr or file name")
+ << cla::dual_name_parameter<unit_test::output_format>( OUTPUT_FORMAT + "|o" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies output format (both log and report)")
+ << cla::dual_name_parameter<int>( RANDOM_SEED + "|a" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value,
+ cla::description = "Allows to switch between sequential and random order of test units execution.\n"
+ "Optionally allows to specify concrete seed for random number generator")
+ << cla::dual_name_parameter<unit_test::output_format>( REPORT_FORMAT + "|m" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies report format")
+ << cla::dual_name_parameter<unit_test::report_level>(REPORT_LEVEL + "|r")
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies report level")
+ << cla::dual_name_parameter<std::string>( REPORT_SINK + "|e" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Specifies report sink:stderr(default),stdout or file name")
+ << cla::dual_name_parameter<bool>( RESULT_CODE + "|c" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Allows to disable test modules's result code generation")
+ << cla::dual_name_parameter<std::string>( TESTS_TO_RUN + "|t" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Allows to filter which test units to run")
+ << cla::named_parameter<bool>( SAVE_TEST_PATTERN )
+ - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "Allows to switch between saving and matching against test pattern file")
+ << cla::dual_name_parameter<bool>( SHOW_PROGRESS + "|p" )
+ - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,
+ cla::description = "Turns on progress display")
+ << cla::named_parameter<bool>( USE_ALT_STACK )
+ - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "Turns on/off usage of an alternative stack for signal handling")
+
+ << cla::dual_name_parameter<bool>( "help|?" )
+ - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional,
+ cla::description = "this help message")
+ ;
+
+ s_cla_parser.parse( argc, argv );
+
+ if( s_cla_parser["help"] ) {
+ s_cla_parser.help( std::cout );
+ throw framework::nothing_to_test();
+ }
+
+ s_report_format = retrieve_parameter( REPORT_FORMAT, s_cla_parser, unit_test::CLF );
+ s_log_format = retrieve_parameter( LOG_FORMAT, s_cla_parser, unit_test::CLF );
+
+ unit_test::output_format of = retrieve_parameter( OUTPUT_FORMAT, s_cla_parser, unit_test::INV_OF );
+
+ if( of != unit_test::INV_OF )
+ s_report_format = s_log_format = of;
+ }
+ catch( rt::logic_error const& ex ) {
+ std::ostringstream err;
+
+ err << "Fail to process runtime parameters: " << ex.msg() << std::endl;
+ s_cla_parser.usage( err );
+
+ throw framework::setup_error( err.str() );
+ }
+}
+
+//____________________________________________________________________________//
+
+unit_test::log_level
+log_level()
+{
+ return retrieve_parameter( LOG_LEVEL, s_cla_parser, unit_test::log_all_errors );
+}
+
+//____________________________________________________________________________//
+
+bool
+no_result_code()
+{
+ return !retrieve_parameter( RESULT_CODE, s_cla_parser, true );
+}
+
+//____________________________________________________________________________//
+
+unit_test::report_level
+report_level()
+{
+ return retrieve_parameter( REPORT_LEVEL, s_cla_parser, unit_test::CONFIRMATION_REPORT );
+}
+
+//____________________________________________________________________________//
+
+const_string
+test_to_run()
+{
+ static std::string s_test_to_run = retrieve_parameter( TESTS_TO_RUN, s_cla_parser, s_empty );
+
+ return s_test_to_run;
+}
+
+//____________________________________________________________________________//
+
+const_string
+break_exec_path()
+{
+ static std::string s_break_exec_path = retrieve_parameter( BREAK_EXEC_PATH, s_cla_parser, s_empty );
+
+ return s_break_exec_path;
+}
+
+//____________________________________________________________________________//
+
+bool
+save_pattern()
+{
+ return retrieve_parameter( SAVE_TEST_PATTERN, s_cla_parser, false );
+}
+
+//____________________________________________________________________________//
+
+bool
+show_progress()
+{
+ return retrieve_parameter( SHOW_PROGRESS, s_cla_parser, false );
+}
+
+//____________________________________________________________________________//
+
+bool
+show_build_info()
+{
+ return retrieve_parameter( BUILD_INFO, s_cla_parser, false );
+}
+
+//____________________________________________________________________________//
+
+bool
+catch_sys_errors()
+{
+ return retrieve_parameter( CATCH_SYS_ERRORS, s_cla_parser,
+#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP
+ false
+#else
+ true
+#endif
+ );
+}
+
+//____________________________________________________________________________//
+
+bool
+auto_start_dbg()
+{
+ // !! set debugger as an option
+ return retrieve_parameter( AUTO_START_DBG, s_cla_parser, false );
+;
+}
+
+//____________________________________________________________________________//
+
+bool
+use_alt_stack()
+{
+ return retrieve_parameter( USE_ALT_STACK, s_cla_parser, true );
+}
+
+//____________________________________________________________________________//
+
+bool
+detect_fp_exceptions()
+{
+ return retrieve_parameter( DETECT_FP_EXCEPT, s_cla_parser, false );
+}
+
+//____________________________________________________________________________//
+
+output_format
+report_format()
+{
+ return s_report_format;
+}
+
+//____________________________________________________________________________//
+
+output_format
+log_format()
+{
+ return s_log_format;
+}
+
+//____________________________________________________________________________//
+
+std::ostream*
+report_sink()
+{
+ std::string sink_name = retrieve_parameter( REPORT_SINK, s_cla_parser, s_empty );
+
+ if( sink_name.empty() || sink_name == "stderr" )
+ return &std::cerr;
+
+ if( sink_name == "stdout" )
+ return &std::cout;
+
+ static std::ofstream log_file( sink_name.c_str() );
+ return &log_file;
+}
+
+//____________________________________________________________________________//
+
+std::ostream*
+log_sink()
+{
+ std::string sink_name = retrieve_parameter( LOG_SINK, s_cla_parser, s_empty );
+
+ if( sink_name.empty() || sink_name == "stdout" )
+ return &std::cout;
+
+ if( sink_name == "stderr" )
+ return &std::cerr;
+
+ static std::ofstream report_file( sink_name.c_str() );
+ return &report_file;
+}
+
+//____________________________________________________________________________//
+
+long
+detect_memory_leaks()
+{
+ return retrieve_parameter( DETECT_MEM_LEAKS, s_cla_parser, static_cast<long>(1) );
+}
+
+//____________________________________________________________________________//
+
+int
+random_seed()
+{
+ return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0, 1 );
+}
+
+//____________________________________________________________________________//
+
+} // namespace runtime_config
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER
diff --git a/ndnboost/test/impl/unit_test_suite.ipp b/ndnboost/test/impl/unit_test_suite.ipp
new file mode 100644
index 0000000..983682d
--- /dev/null
+++ b/ndnboost/test/impl/unit_test_suite.ipp
@@ -0,0 +1,346 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 54633 $
+//
+// Description : privides core implementation for Unit Test Framework.
+// Extensions can be provided in separate files
+// ***************************************************************************
+
+#ifndef BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER
+#define BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER
+
+// Boost.Test
+#include <ndnboost/detail/workaround.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/utils/foreach.hpp>
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/detail/unit_test_parameters.hpp>
+
+// Boost
+#include <ndnboost/timer.hpp>
+
+// STL
+#include <algorithm>
+#include <vector>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \
+ BOOST_WORKAROUND(_STLPORT_VERSION, <= 0x450) \
+ /**/
+ using std::rand; // rand is in std and random_shuffle is in _STL
+#endif
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+// ************************************************************************** //
+// ************** test_unit ************** //
+// ************************************************************************** //
+
+test_unit::test_unit( const_string name, test_unit_type t )
+: p_type( t )
+, p_type_name( t == tut_case ? "case" : "suite" )
+, p_id( INV_TEST_UNIT_ID )
+, p_name( std::string( name.begin(), name.size() ) )
+, p_enabled( true )
+{
+}
+
+//____________________________________________________________________________//
+
+test_unit::~test_unit()
+{
+ framework::deregister_test_unit( this );
+}
+
+//____________________________________________________________________________//
+
+void
+test_unit::depends_on( test_unit* tu )
+{
+ m_dependencies.push_back( tu->p_id );
+}
+
+//____________________________________________________________________________//
+
+bool
+test_unit::check_dependencies() const
+{
+ BOOST_TEST_FOREACH( test_unit_id, tu_id, m_dependencies ) {
+ if( !unit_test::results_collector.results( tu_id ).passed() )
+ return false;
+ }
+
+ return true;
+}
+
+//____________________________________________________________________________//
+
+void
+test_unit::increase_exp_fail( unsigned num )
+{
+ p_expected_failures.value += num;
+
+ if( p_parent_id != 0 )
+ framework::get<test_suite>( p_parent_id ).increase_exp_fail( num );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** test_case ************** //
+// ************************************************************************** //
+
+test_case::test_case( const_string name, callback0<> const& test_func )
+: test_unit( name, static_cast<test_unit_type>(type) )
+, m_test_func( test_func )
+{
+ // !! weirdest MSVC BUG; try to remove this statement; looks like it eats first token of next statement
+#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
+ 0;
+#endif
+ framework::register_test_unit( this );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** test_suite ************** //
+// ************************************************************************** //
+
+//____________________________________________________________________________//
+
+test_suite::test_suite( const_string name )
+: test_unit( name, static_cast<test_unit_type>(type) )
+{
+ framework::register_test_unit( this );
+}
+
+//____________________________________________________________________________//
+
+void
+test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout )
+{
+ if( timeout != 0 )
+ tu->p_timeout.value = timeout;
+
+ m_members.push_back( tu->p_id );
+ tu->p_parent_id.value = p_id;
+
+ if( tu->p_expected_failures )
+ increase_exp_fail( tu->p_expected_failures );
+
+ if( expected_failures )
+ tu->increase_exp_fail( expected_failures );
+}
+
+//____________________________________________________________________________//
+
+void
+test_suite::add( test_unit_generator const& gen, unsigned timeout )
+{
+ test_unit* tu;
+ while((tu = gen.next(), tu))
+ add( tu, 0, timeout );
+}
+
+//____________________________________________________________________________//
+
+void
+test_suite::remove( test_unit_id id )
+{
+ std::vector<test_unit_id>::iterator it = std::find( m_members.begin(), m_members.end(), id );
+
+ if( it != m_members.end() )
+ m_members.erase( it );
+}
+
+//____________________________________________________________________________//
+
+test_unit_id
+test_suite::get( const_string tu_name ) const
+{
+ BOOST_TEST_FOREACH( test_unit_id, id, m_members ) {
+ if( tu_name == framework::get( id, ut_detail::test_id_2_unit_type( id ) ).p_name.get() )
+ return id;
+ }
+
+ return INV_TEST_UNIT_ID;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** traverse_test_tree ************** //
+// ************************************************************************** //
+
+void
+traverse_test_tree( test_case const& tc, test_tree_visitor& V )
+{
+ if( tc.p_enabled )
+ V.visit( tc );
+}
+
+//____________________________________________________________________________//
+
+void
+traverse_test_tree( test_suite const& suite, test_tree_visitor& V )
+{
+ if( !suite.p_enabled || !V.test_suite_start( suite ) )
+ return;
+
+ try {
+ if( runtime_config::random_seed() == 0 ) {
+ BOOST_TEST_FOREACH( test_unit_id, id, suite.m_members )
+ traverse_test_tree( id, V );
+ }
+ else {
+ std::vector<test_unit_id> members( suite.m_members );
+ std::random_shuffle( members.begin(), members.end() );
+ BOOST_TEST_FOREACH( test_unit_id, id, members )
+ traverse_test_tree( id, V );
+ }
+
+ } catch( test_being_aborted const& ) {
+ V.test_suite_finish( suite );
+ framework::test_unit_aborted( suite );
+
+ throw;
+ }
+
+ V.test_suite_finish( suite );
+}
+
+//____________________________________________________________________________//
+
+void
+traverse_test_tree( test_unit_id id, test_tree_visitor& V )
+{
+ if( ut_detail::test_id_2_unit_type( id ) == tut_case )
+ traverse_test_tree( framework::get<test_case>( id ), V );
+ else
+ traverse_test_tree( framework::get<test_suite>( id ), V );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** test_case_counter ************** //
+// ************************************************************************** //
+
+void
+test_case_counter::visit( test_case const& tc )
+{
+ if( tc.p_enabled )
+ ++p_count.value;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** object generators ************** //
+// ************************************************************************** //
+
+namespace ut_detail {
+
+std::string
+normalize_test_case_name( const_string name )
+{
+ return ( name[0] == '&'
+ ? std::string( name.begin()+1, name.size()-1 )
+ : std::string( name.begin(), name.size() ) );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** auto_test_unit_registrar ************** //
+// ************************************************************************** //
+
+auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, counter_t exp_fail )
+{
+ curr_ts_store().back()->add( tc, exp_fail );
+}
+
+//____________________________________________________________________________//
+
+auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name )
+{
+ test_unit_id id = curr_ts_store().back()->get( ts_name );
+
+ test_suite* ts;
+
+ if( id != INV_TEST_UNIT_ID ) {
+ ts = &framework::get<test_suite>( id ); // !! test for invalid tu type
+ BOOST_ASSERT( ts->p_parent_id == curr_ts_store().back()->p_id );
+ }
+ else {
+ ts = new test_suite( ts_name );
+ curr_ts_store().back()->add( ts );
+ }
+
+ curr_ts_store().push_back( ts );
+}
+
+//____________________________________________________________________________//
+
+auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen )
+{
+ curr_ts_store().back()->add( tc_gen );
+}
+
+//____________________________________________________________________________//
+
+auto_test_unit_registrar::auto_test_unit_registrar( int )
+{
+ if( curr_ts_store().size() == 0 )
+ return; // report error?
+
+ curr_ts_store().pop_back();
+}
+
+//____________________________________________________________________________//
+
+std::list<test_suite*>&
+auto_test_unit_registrar::curr_ts_store()
+{
+ static std::list<test_suite*> inst( 1, &framework::master_test_suite() );
+ return inst;
+}
+
+//____________________________________________________________________________//
+
+} // namespace ut_detail
+
+// ************************************************************************** //
+// ************** global_fixture ************** //
+// ************************************************************************** //
+
+global_fixture::global_fixture()
+{
+ framework::register_observer( *this );
+}
+
+//____________________________________________________________________________//
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER
diff --git a/ndnboost/test/impl/xml_log_formatter.ipp b/ndnboost/test/impl/xml_log_formatter.ipp
new file mode 100644
index 0000000..0bf6460
--- /dev/null
+++ b/ndnboost/test/impl/xml_log_formatter.ipp
@@ -0,0 +1,180 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : implements XML Log formatter
+// ***************************************************************************
+
+#ifndef BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER
+#define BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/output/xml_log_formatter.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/framework.hpp>
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+
+#include <ndnboost/test/utils/xml_printer.hpp>
+
+// Boost
+#include <ndnboost/version.hpp>
+
+// STL
+#include <iostream>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace output {
+
+static const_string tu_type_name( test_unit const& tu )
+{
+ return tu.p_type == tut_case ? "TestCase" : "TestSuite";
+}
+
+// ************************************************************************** //
+// ************** xml_log_formatter ************** //
+// ************************************************************************** //
+
+void
+xml_log_formatter::log_start( std::ostream& ostr, counter_t )
+{
+ ostr << "<TestLog>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_finish( std::ostream& ostr )
+{
+ ostr << "</TestLog>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_build_info( std::ostream& ostr )
+{
+ ostr << "<BuildInfo"
+ << " platform" << attr_value() << BOOST_PLATFORM
+ << " compiler" << attr_value() << BOOST_COMPILER
+ << " stl" << attr_value() << BOOST_STDLIB
+ << " boost=\"" << BOOST_VERSION/100000 << "."
+ << BOOST_VERSION/100 % 1000 << "."
+ << BOOST_VERSION % 100 << '\"'
+ << "/>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu )
+{
+ ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get() << ">";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed )
+{
+ if( tu.p_type == tut_case )
+ ostr << "<TestingTime>" << elapsed << "</TestingTime>";
+
+ ostr << "</" << tu_type_name( tu ) << ">";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu )
+{
+ ostr << "<" << tu_type_name( tu )
+ << " name" << attr_value() << tu.p_name.get()
+ << " skipped" << attr_value() << "yes"
+ << "/>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_exception( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
+{
+ execution_exception::location const& loc = ex.where();
+
+ ostr << "<Exception file" << attr_value() << loc.m_file_name
+ << " line" << attr_value() << loc.m_line_num;
+
+ if( !loc.m_function.is_empty() )
+ ostr << " function" << attr_value() << loc.m_function;
+
+ ostr << ">" << cdata() << ex.what();
+
+ if( !checkpoint_data.m_file_name.is_empty() ) {
+ ostr << "<LastCheckpoint file" << attr_value() << checkpoint_data.m_file_name
+ << " line" << attr_value() << checkpoint_data.m_line_num
+ << ">"
+ << cdata() << checkpoint_data.m_message
+ << "</LastCheckpoint>";
+ }
+
+ ostr << "</Exception>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& entry_data, log_entry_types let )
+{
+ static literal_string xml_tags[] = { "Info", "Message", "Warning", "Error", "FatalError" };
+
+ m_curr_tag = xml_tags[let];
+ ostr << '<' << m_curr_tag
+ << 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[" );
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_entry_value( std::ostream& ostr, const_string value )
+{
+ ostr << value;
+}
+
+//____________________________________________________________________________//
+
+void
+xml_log_formatter::log_entry_finish( std::ostream& ostr )
+{
+ ostr << BOOST_TEST_L( "]]></" ) << m_curr_tag << BOOST_TEST_L( ">" );
+
+ m_curr_tag.clear();
+}
+
+//____________________________________________________________________________//
+
+} // namespace output
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER
diff --git a/ndnboost/test/impl/xml_report_formatter.ipp b/ndnboost/test/impl/xml_report_formatter.ipp
new file mode 100644
index 0000000..92655ee
--- /dev/null
+++ b/ndnboost/test/impl/xml_report_formatter.ipp
@@ -0,0 +1,115 @@
+// (C) Copyright Gennadiy Rozental 2005-2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 49312 $
+//
+// Description : XML report formatter
+// ***************************************************************************
+
+#ifndef BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER
+#define BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER
+
+// Boost.Test
+#include <ndnboost/test/results_collector.hpp>
+#include <ndnboost/test/unit_test_suite_impl.hpp>
+#include <ndnboost/test/output/xml_report_formatter.hpp>
+
+#include <ndnboost/test/utils/xml_printer.hpp>
+#include <ndnboost/test/utils/basic_cstring/io.hpp>
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace unit_test {
+
+namespace output {
+
+void
+xml_report_formatter::results_report_start( std::ostream& ostr )
+{
+ ostr << "<TestResult>";
+}
+
+//____________________________________________________________________________//
+
+void
+xml_report_formatter::results_report_finish( std::ostream& ostr )
+{
+ ostr << "</TestResult>";
+}
+
+
+//____________________________________________________________________________//
+
+void
+xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& ostr )
+{
+ test_results const& tr = results_collector.results( tu.p_id );
+
+ const_string descr;
+
+ if( tr.passed() )
+ descr = "passed";
+ else if( tr.p_skipped )
+ descr = "skipped";
+ else if( tr.p_aborted )
+ descr = "aborted";
+ else
+ descr = "failed";
+
+ ostr << '<' << ( tu.p_type == tut_case ? "TestCase" : "TestSuite" )
+ << " name" << attr_value() << tu.p_name.get()
+ << " result" << attr_value() << descr
+ << " assertions_passed" << attr_value() << tr.p_assertions_passed
+ << " assertions_failed" << attr_value() << tr.p_assertions_failed
+ << " expected_failures" << attr_value() << tr.p_expected_failures;
+
+ if( tu.p_type == tut_suite )
+ ostr << " test_cases_passed" << attr_value() << tr.p_test_cases_passed
+ << " test_cases_failed" << attr_value() << tr.p_test_cases_failed
+ << " test_cases_skipped" << attr_value() << tr.p_test_cases_skipped
+ << " test_cases_aborted" << attr_value() << tr.p_test_cases_aborted;
+
+
+ ostr << '>';
+}
+
+//____________________________________________________________________________//
+
+void
+xml_report_formatter::test_unit_report_finish( test_unit const& tu, std::ostream& ostr )
+{
+ ostr << "</" << ( tu.p_type == tut_case ? "TestCase" : "TestSuite" ) << '>';
+}
+
+//____________________________________________________________________________//
+
+void
+xml_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr )
+{
+ test_unit_report_start( tu, ostr );
+ test_unit_report_finish( tu, ostr );
+}
+
+//____________________________________________________________________________//
+
+} // namespace output
+
+} // namespace unit_test
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER