/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; ckerlin
@ license LGPL , see file < a href = " license.html " > COPYING < / a >
$ Log $
Revision 1.3 2005 / 11 / 29 12 : 39 : 42 marc
make it compilable with gcc 4.0 .2 and newer doxygen
Revision 1.2 2005 / 04 / 07 20 : 42 : 38 marc
renamed loggerhierarchy from mrw . gccfunctiontrace to mrw . fn
Revision 1.1 2005 / 03 / 11 21 : 07 : 55 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
# include <log4cxx/propertyconfigurator.h>
# include <log4cxx/helpers/properties.h>
# include <cppunit/TestFixture.h>
# include <cppunit/ui/text/TestRunner.h>
# include <cppunit/extensions/HelperMacros.h>
# include <cppunit/extensions/TestFactoryRegistry.h>
# include <cppunit/XmlOutputter.h>
# include <fstream>
# include <mrw/file.hxx>
# include <mrw/regexp.hxx>
# include <mrw/string.hxx>
# include <mrw/stacktrace.hxx>
# include <map>
# if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
& & defined ( _REENTRANT ) & & ! defined ( _MT )
# define _MT
# endif
namespace HalloWelt {
class A {
public :
void method ( ) {
}
} ;
void fn ( int ) {
A ( ) . method ( ) ;
A ( ) . method ( ) ;
}
void fn1 ( ) {
fn ( 1 ) ;
fn ( 2 ) ;
}
}
void anotherFunction ( ) {
HalloWelt : : fn1 ( ) ;
}
# ifdef _MT
# include <boost/thread/thread.hpp>
//#include <unistd.h> // sleep, the one from boost::thread does not work!
class Thread {
public :
void operator ( ) ( ) {
anotherFunction ( ) ;
}
} ;
# endif
namespace mrw {
class AutoFunctionTraceLog4CxxTest : public CppUnit : : TestFixture {
public :
void testcase ( ) {
mrw : : StackTrace : : createSymtable ( ) ;
# ifdef _MT
try { mrw : : File : : remove ( " mrwautofunctiontracelog4cxx_test-mt.trace " ) ; }
# else
try { mrw : : File : : remove ( " mrwautofunctiontracelog4cxx_test.trace " ) ; }
# endif
catch ( . . . ) { }
log4cxx : : helpers : : Properties properties ;
std : : string name , cont ;
properties . setProperty ( ( name = " log4j.rootLogger " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF, A1 " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " DEBUG " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.global " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.allocator " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.std.* " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.log4cxx " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.boost " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.Thread " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.mrw " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.std " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.new " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.CppUnit " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.logger.mrw.fn.__gnu_cxx " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " OFF " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.appender.A1 " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " org.apache.log4j.FileAppender " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.appender.A1.layout " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " org.apache.log4j.PatternLayout " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
# ifdef _MT
properties . setProperty ( ( name = " log4j.appender.A1.layout.ConversionPattern " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " %t-%-27c%m%n " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.appender.A1.filename " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " mrwautofunctiontracelog4cxx_test-mt.trace " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
# else
properties . setProperty ( ( name = " log4j.appender.A1.layout.ConversionPattern " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " %-27c%m%n " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
properties . setProperty ( ( name = " log4j.appender.A1.filename " ,
std : : string ( name . begin ( ) , name . end ( ) ) ) ,
( cont = " mrwautofunctiontracelog4cxx_test.trace " ,
std : : string ( cont . begin ( ) , cont . end ( ) ) ) ) ;
# endif
log4cxx : : PropertyConfigurator : : configure ( properties ) ;
# ifdef _MT
// sleep(4); // to be reproducable, wait for "main" flag
Thread threadFunction ;
boost : : thread thread1 ( threadFunction ) ;
boost : : thread thread2 ( threadFunction ) ;
boost : : thread thread3 ( threadFunction ) ;
# endif
anotherFunction ( ) ;
# ifdef _MT
thread1 . join ( ) ;
thread2 . join ( ) ;
thread3 . join ( ) ;
# endif
}
void checkfile ( ) {
mrw : : RegExp match
( " ^mrw \\ .fn \\ .anotherFunction ( ? ? ?) \\ \\ anotherFunction \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn1 \\ 1 \\ \\ HalloWelt::fn1 \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn \\ 1 \\ \\ HalloWelt::fn \\ (int \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 \\ \\ HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 / HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 \\ \\ HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 / HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn \\ 1 / HalloWelt::fn \\ (int \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn \\ 1 \\ \\ HalloWelt::fn \\ (int \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 \\ \\ HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 / HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 \\ \\ HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .A \\ .method \\ 1 / HalloWelt::A::method \\ ( \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn \\ 1 / HalloWelt::fn \\ (int \\ ) \n "
" mrw \\ .fn \\ .HalloWelt \\ .fn1 \\ 1 / HalloWelt::fn1 \\ ( \\ ) \n "
" mrw \\ .fn \\ .anotherFunction \\ 1/ anotherFunction \\ ( \\ ) \n $ " ) ;
# ifdef _MT
std : : string log ( mrw : : File : : read ( " mrwautofunctiontracelog4cxx_test-mt.trace " ) ) ;
typedef std : : map < unsigned long , std : : string > Logs ;
Logs logs ;
for ( std : : string : : size_type pos ( 0 ) , last ( 0 ) ;
( pos = log . find ( ' \n ' , pos + 1 ) ) ! = std : : string : : npos ; last = pos ) {
std : : string : : size_type dash ( log . find ( ' - ' , last ) ) ;
CPPUNIT_ASSERT_MESSAGE ( " \" - \" not found " ,
dash ! = std : : string : : npos ) ;
logs [ mrw : : to < unsigned long > ( log . substr ( last , dash - last ) ) ] + =
log . substr ( dash + 1 , pos - dash ) ;
}
CPPUNIT_ASSERT_EQUAL ( ( Logs : : size_type ) 4 , logs . size ( ) ) ; // 4 threads
for ( Logs : : iterator it ( logs . begin ( ) ) ; it ! = logs . end ( ) ; + + it )
CPPUNIT_ASSERT_MESSAGE ( " The following text does not match the "
" Expectation: \n -------------------- \n "
+ it - > second + " -------------------- " ,
match ( it - > second ) ) ;
mrw : : File : : remove ( " mrwautofunctiontracelog4cxx_test-mt.trace " ) ;
# else
CPPUNIT_ASSERT_MESSAGE
( " The following text does not match the "
" Expectation: \n -------------------- \n "
+ mrw : : File : : read ( " mrwautofunctiontracelog4cxx_test.trace " )
+ " -------------------- " ,
match ( mrw : : File : : read ( " mrwautofunctiontracelog4cxx_test.trace " ) ) ) ;
mrw : : File : : remove ( " mrwautofunctiontracelog4cxx_test.trace " ) ;
# endif
}
CPPUNIT_TEST_SUITE ( AutoFunctionTraceLog4CxxTest ) ;
CPPUNIT_TEST ( testcase ) ;
CPPUNIT_TEST ( checkfile ) ;
CPPUNIT_TEST_SUITE_END ( ) ;
} ;
CPPUNIT_TEST_SUITE_REGISTRATION ( AutoFunctionTraceLog4CxxTest ) ;
}
int main ( int argc , char * * argv ) try {
std : : ofstream ofs ( ( * argv + std : : string ( " .xml " ) ) . c_str ( ) ) ;
CppUnit : : TextUi : : TestRunner runner ;
runner . setOutputter ( new CppUnit : : XmlOutputter ( & runner . result ( ) , ofs ) ) ;
runner . addTest ( CppUnit : : TestFactoryRegistry : : getRegistry ( ) . makeTest ( ) ) ;
return runner . run ( ) ? 0 : 1 ;
} catch ( std : : exception & e ) {
std : : cerr < < " ***Exception: " < < e . what ( ) < < std : : endl ;
return 1 ;
}