/** @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/04/07 20:55:21  marc
    Oops, there's a make distcheck...? Now it works.

    Revision 1.2  2005/03/11 23:18:02  marc
    bugfix: linenumbers change at checkin...

    Revision 1.1  2005/03/11 21:07:55  marc
    initial version


         1         2         3         4         5         6         7         8
    5678901234567890123456789012345678901234567890123456789012345678901234567890
*/

#include <mrw/functiontrace.hxx>
#include <mrw/regexp.hxx>
#include <mrw/file.hxx>
#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>

class A {
  public:
    A() {
      MRW_METHOD("A::A()");
    }
    ~A() {
      MRW_METHOD("A::~A()");
    }
    void fn1() {
      MRW_METHOD("A::fn1()");
      fn2();
    }
    void fn2() {
      MRW_METHOD("A::fn2()");
      fn3();
      fn4();
    }
    void fn3() {
      MRW_METHOD("A::fn3()");
      fn4();
    }
    void fn4(bool flag=true) {
      MRW_METHOD("A::fn4()");
      if (flag) fn4(false);
    }
};

void fn(A a) {
  MRW_FUNCTION("fn(A)");
  a.fn1();
}

class FunctionTraceTest: public CppUnit::TestFixture { 
  public:
    void Init() {
      try {mrw::File::remove("functiontrace_test.trace");} catch (...) {}
      log4cxx::helpers::Properties properties;
      std::string name, cont;
      properties.setProperty((name="log4j.rootLogger",
                              std::string(name.begin(), name.end())),
                             (cont="DEBUG, A1",
                              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())));
      properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
                              std::string(name.begin(), name.end())),
                             (cont="%F:%L - %m%n",
                              std::string(cont.begin(), cont.end())));
      properties.setProperty((name="log4j.appender.A1.filename",
                              std::string(name.begin(), name.end())),
                             (cont="functiontrace_test.trace",
                              std::string(cont.begin(), cont.end())));
      log4cxx::PropertyConfigurator::configure(properties);
    }
    void Calls() {
      fn(A());
      mrw::RegExp match
        (".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::A\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::A\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ -                  \\\\ fn\\(A\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:  \\\\ A::fn1\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:   \\\\ A::fn2\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:    \\\\ A::fn3\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:     \\\\ A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:      \\\\ A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:      / A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:     / A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:    / A::fn3\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:    \\\\ A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:     \\\\ A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:     / A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:    / A::fn4\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:   / A::fn2\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+:  / A::fn1\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ -                  / fn\\(A\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::~A\\(\\)\n"
         ".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::~A\\(\\)\n");
      CPPUNIT_ASSERT(match(mrw::File::read("functiontrace_test.trace")));
      mrw::File::remove("functiontrace_test.trace");
    }
    CPPUNIT_TEST_SUITE(FunctionTraceTest);
    CPPUNIT_TEST(Init);
    CPPUNIT_TEST(Calls);
    CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(FunctionTraceTest);

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;
 }
