summaryrefslogtreecommitdiff
path: root/examples/ClockerPlugIn
diff options
context:
space:
mode:
authorBaptiste Lepilleur <gaiacrtn@free.fr>2002-06-14 19:21:01 +0000
committerBaptiste Lepilleur <gaiacrtn@free.fr>2002-06-14 19:21:01 +0000
commit73a038f1eaa268cec330d971fb550befec6f7798 (patch)
treec3eba5d793e37413889acad5b0b9f70caf89b0f6 /examples/ClockerPlugIn
parentf39e160fba25476de7d41e2f19d756db7ee76dc7 (diff)
downloadcppunit-73a038f1eaa268cec330d971fb550befec6f7798.tar.gz
Include/cppunit/plugin/PlugInManager.
include/cppunit/plugin/PlugInManager.h: * src/cppunit/PlugInManager.cpp: added two methods to use the plug-in interface for Xml Outputter hooks. * include/cppunit/plugin/TestPlugIn.h: added two methods to the plug-in interface for Xml Outputter hooks. * include/cppunit/plugin/TestPlugInAdapter.h: * src/cppunit/plugin/TestPlugInAdapter.cpp: renamed TestPlugInDefaultImpl. Added empty implementation for Xml outputter hook methods. * include/cppunit/tools/StringTools.h: * src/cppunit/tools/StringTools.cpp: added. Functions to manipulate string (conversion, wrapping...) * include/cppunit/tools/XmlElement.h: * src/cppunit/XmlElement.cpp: renamed addNode() to addElement(). Added methods to walk and modify XmlElement (for hook). Added documentation. Use StringTools. * include/cppunit/XmlOutputter.h: * src/cppunit/XmlOutputter.cpp: added hook calls & management. * include/cppunit/XmlOutputterHook.h: * src/cppunit/XmlOutputterHook.cpp: added. Hook to customize XML output. * src/DllPlugInTester/DllPlugInTester.cpp: call plug-in XmlOutputterHook when writing XML output. Modified so that memory is freed before unloading the test plug-in (caused crash when freeing the XmlDocument). * examples/ReadMe.txt: * examples/ClockerPlugIn/ReadMe.txt: added details about the plug-in (usage, xml content...) * examples/ClockerPlugIn/ClockerModel.h: * examples/ClockerPlugIn/ClockerModel.cpp: extracted from ClockerListener. Represents the test hierarchy and tracked time for each test. * examples/ClockerPlugIn/ClockerListener.h: * examples/ClockerPlugIn/ClockerListener.cpp: extracted test hierarchy tracking to ClockerModel. Replaced the 'flat' view option with a 'text' option to print the timed test tree to stdout. * examples/ClockerPlugIn/ClockerPlugIn.cpp: updated to hook the XML output and use the new classes. * examples/ClockerPlugIn/ClockerXmlHook.h: * examples/ClockerPlugIn/ClockerXmlHook.cpp: added. XmlOutputterHook to includes the timed test hierarchy and test timing in the XML output. * examples/cppunittest/XmlElementTest.h: * examples/cppunittest/XmlElementTest.cpp: added new test cases. * examples/cppunittest/XmlOutputterTest.h: * examples/cppunittest/XmlOutputterTest.cpp: added tests for XmlOutputterHook.
Diffstat (limited to 'examples/ClockerPlugIn')
-rw-r--r--examples/ClockerPlugIn/ClockerListener.cpp130
-rw-r--r--examples/ClockerPlugIn/ClockerListener.h52
-rw-r--r--examples/ClockerPlugIn/ClockerModel.cpp145
-rw-r--r--examples/ClockerPlugIn/ClockerModel.h95
-rw-r--r--examples/ClockerPlugIn/ClockerPlugIn.cpp30
-rw-r--r--examples/ClockerPlugIn/ClockerPlugIn.dsp22
-rw-r--r--examples/ClockerPlugIn/ClockerXmlHook.cpp94
-rw-r--r--examples/ClockerPlugIn/ClockerXmlHook.h62
-rw-r--r--examples/ClockerPlugIn/ReadMe.txt42
9 files changed, 520 insertions, 152 deletions
diff --git a/examples/ClockerPlugIn/ClockerListener.cpp b/examples/ClockerPlugIn/ClockerListener.cpp
index 9ac9c52..a93cd38 100644
--- a/examples/ClockerPlugIn/ClockerListener.cpp
+++ b/examples/ClockerPlugIn/ClockerListener.cpp
@@ -6,13 +6,14 @@
#include <cppunit/Test.h>
#include <iostream>
#include "ClockerListener.h"
+#include "ClockerModel.h"
#include <stdio.h>
-ClockerListener::ClockerListener( bool flatten )
- : m_flatten( flatten )
- , m_testCount( 0 )
- , m_totalTestCaseTime( 0 )
+ClockerListener::ClockerListener( ClockerModel *model,
+ bool text )
+ : m_model( model )
+ , m_text( text )
{
}
@@ -26,121 +27,79 @@ void
ClockerListener::startTestRun( CppUnit::Test *test,
CppUnit::TestResult *eventManager )
{
- m_tests.reserve( test->countTestCases() *2 );
+ m_model->setExpectedTestCount( test->countTestCases() *2 );
}
void
-ClockerListener::startTest( CppUnit::Test *test )
-{
- enterTest( test, false );
- ++m_testCount;
-}
-
-
-void
-ClockerListener::endTest( CppUnit::Test *test )
-{
- exitTest( test, false );
-}
-
-
-void
-ClockerListener::startSuite( CppUnit::Test *suite )
+ClockerListener::endTestRun( CppUnit::Test *test,
+ CppUnit::TestResult *eventManager )
{
- enterTest( suite, true );
+ if ( m_text )
+ printStatistics();
}
void
-ClockerListener::endSuite( CppUnit::Test *suite )
+ClockerListener::startTest( CppUnit::Test *test )
{
- exitTest( suite, true );
+ m_model->enterTest( test, false );
}
void
-ClockerListener::endTestRun( CppUnit::Test *test,
- CppUnit::TestResult *eventManager )
+ClockerListener::endTest( CppUnit::Test *test )
{
- printStatistics();
+ m_model->exitTest( test, false );
}
void
-ClockerListener::enterTest( CppUnit::Test *test,
- bool isSuite )
+ClockerListener::startSuite( CppUnit::Test *suite )
{
- m_currentPath.add( test );
-
- int testIndex = m_tests.size();
- if ( !m_testIndexes.empty() )
- m_tests[ m_testIndexes.top() ].m_childIndexes.push_back( testIndex );
- m_testIndexes.push( testIndex );
-
- TestInfo info;
- info.m_timer.start();
- info.m_path = m_currentPath;
- info.m_isSuite = isSuite;
-
- m_tests.push_back( info );
+ m_model->enterTest( suite, true );
}
void
-ClockerListener::exitTest( CppUnit::Test *test,
- bool isSuite )
+ClockerListener::endSuite( CppUnit::Test *suite )
{
- m_tests[ m_testIndexes.top() ].m_timer.finish();
- if ( !isSuite )
- m_totalTestCaseTime += m_tests.back().m_timer.elapsedTime();
-
- m_currentPath.up();
- m_testIndexes.pop();
+ m_model->exitTest( suite, true );
}
void
ClockerListener::printStatistics() const
{
- printTest( m_tests[0], "" );
+ printTest( 0, "" );
std::cout << std::endl;
std::cout << "Total elapsed time: ";
- printTestTime( m_tests[0].m_timer.elapsedTime() );
+ printTime( m_model->totalElapsedTime() );
std::cout << ", average test case time: ";
- double average = 0;
- if ( m_testCount > 0 )
- average = m_totalTestCaseTime / m_testCount;
- printTestTime( average );
+ printTime( m_model->averageTestCaseTime() );
}
void
-ClockerListener::printTest( const TestInfo &info,
+ClockerListener::printTest( int testIndex,
const std::string &indentString ) const
{
std::string indent = indentString;
const int indentLength = 3;
- if ( !m_flatten )
- printTestIndent( indentString, indentLength );
-
- printTestTime( info.m_timer.elapsedTime() );
-
- if ( m_flatten )
- printFlattenedTestName( info );
- else
- printTestName( info );
+ printTestIndent( indentString, indentLength );
+ printTime( m_model->testTimeFor( testIndex ) );
+ std::cout << m_model->testPathFor( testIndex ).getChildTest()->getName();
std::cout << std::endl;
- if ( info.m_childIndexes.empty() )
+ if ( m_model->childCountFor( testIndex ) == 0 )
indent+= std::string( indentLength, ' ' );
else
indent+= "|" + std::string( indentLength -1, ' ' );
- for ( int index =0; index < info.m_childIndexes.size(); ++index )
- printTest( m_tests[ info.m_childIndexes[ index ] ], indent );
+ for ( int index =0; index < m_model->childCountFor( testIndex ); ++index )
+ printTest( m_model->childAtFor( testIndex, index ), indent );
}
@@ -158,36 +117,7 @@ ClockerListener::printTestIndent( const std::string &indent,
void
-ClockerListener::printTestTime( double elapsedSeconds ) const
-{
- char buffer[320];
- const char *format;
- if ( elapsedSeconds < 1 )
- format = "(%2.3fs) ";
- else if ( elapsedSeconds < 10 )
- format = "(%3.2fs) ";
- else if (elapsedSeconds < 100 )
- format = "(%4.1fs) ";
- else
- format = "(%5fs) ";
-
- ::sprintf( buffer, format, elapsedSeconds );
-
- std::cout << buffer;
-}
-
-
-void
-ClockerListener::printFlattenedTestName( const TestInfo &info ) const
-{
- std::cout << info.m_path.toString();
- if ( info.m_isSuite )
- std::cout << "/";
-}
-
-
-void
-ClockerListener::printTestName( const TestInfo &info ) const
+ClockerListener::printTime( double time ) const
{
- std::cout << info.m_path.getChildTest()->getName();
+ std::cout << '(' << ClockerModel::timeStringFor( time ) << "s) ";
}
diff --git a/examples/ClockerPlugIn/ClockerListener.h b/examples/ClockerPlugIn/ClockerListener.h
index b256380..e3c84e4 100644
--- a/examples/ClockerPlugIn/ClockerListener.h
+++ b/examples/ClockerPlugIn/ClockerListener.h
@@ -7,28 +7,25 @@
#define CLOCKERLISTENER_H
#include <cppunit/TestListener.h>
-#include <cppunit/TestPath.h>
-#include <stack>
-#include <vector>
-#ifdef CLOCKER_USE_WINNTTIMER
-#include "WinNtTimer.h"
-typedef WinNtTimer Timer;
-#else
-#include "Timer.h"
-#endif
+class ClockerModel;
+
/// TestListener that prints a flatten or hierarchical view of the test tree.
class ClockerListener : public CppUnit::TestListener
{
public:
- ClockerListener( bool flatten );
+ ClockerListener( ClockerModel *model,
+ bool text );
virtual ~ClockerListener();
void startTestRun( CppUnit::Test *test,
CppUnit::TestResult *eventManager );
+ void endTestRun( CppUnit::Test *test,
+ CppUnit::TestResult *eventManager );
+
void startTest( CppUnit::Test *test );
void endTest( CppUnit::Test *test );
@@ -37,37 +34,16 @@ public:
void endSuite( CppUnit::Test *suite );
- void endTestRun( CppUnit::Test *test,
- CppUnit::TestResult *eventManager );
-
private:
- struct TestInfo
- {
- CppUnit::TestPath m_path;
- Timer m_timer;
- bool m_isSuite;
- std::vector<int> m_childIndexes;
- };
-
- void enterTest( CppUnit::Test *test,
- bool isSuite );
-
- void exitTest( CppUnit::Test *test,
- bool isSuite );
-
void printStatistics() const;
- void printTest( const TestInfo &info,
+ void printTest( int testIndex,
const std::string &indentString ) const;
void printTestIndent( const std::string &indent,
const int indentLength ) const;
- void printTestTime( double elapsedSeconds ) const;
-
- void printFlattenedTestName( const TestInfo &info ) const;
-
- void printTestName( const TestInfo &info ) const;
+ void printTime( double time ) const;
/// Prevents the use of the copy constructor.
ClockerListener( const ClockerListener &other );
@@ -76,14 +52,8 @@ private:
void operator =( const ClockerListener &other );
private:
- bool m_flatten;
- CppUnit::TestPath m_currentPath;
-
- int m_testCount;
- double m_totalTestCaseTime;
-
- std::stack<int> m_testIndexes;
- std::vector<TestInfo> m_tests;
+ ClockerModel *m_model;
+ bool m_text;
};
diff --git a/examples/ClockerPlugIn/ClockerModel.cpp b/examples/ClockerPlugIn/ClockerModel.cpp
new file mode 100644
index 0000000..60e87ad
--- /dev/null
+++ b/examples/ClockerPlugIn/ClockerModel.cpp
@@ -0,0 +1,145 @@
+// //////////////////////////////////////////////////////////////////////////
+// Implementation file ClockerModel.cpp for class ClockerModel
+// (c)Copyright 2000, Baptiste Lepilleur.
+// Created: 2002/06/14
+// //////////////////////////////////////////////////////////////////////////
+#include "ClockerModel.h"
+
+
+ClockerModel::ClockerModel()
+ : m_testCaseCount( 0 )
+ , m_totalTestCaseTime( 0 )
+{
+}
+
+
+ClockerModel::~ClockerModel()
+{
+}
+
+
+void
+ClockerModel::setExpectedTestCount( int count )
+{
+ m_tests.reserve( count );
+}
+
+
+void
+ClockerModel::enterTest( CppUnit::Test *test,
+ bool isSuite )
+{
+ m_currentPath.add( test );
+
+ int testIndex = m_tests.size();
+ if ( !m_testIndexes.empty() )
+ m_tests[ m_testIndexes.top() ].m_childIndexes.push_back( testIndex );
+ m_testIndexes.push( testIndex );
+ m_testToIndexes.insert( TestToIndexes::value_type( test, testIndex ) );
+
+ TestInfo info;
+ info.m_timer.start();
+ info.m_path = m_currentPath;
+ info.m_isSuite = isSuite;
+
+ m_tests.push_back( info );
+
+ if ( !isSuite )
+ ++m_testCaseCount;
+}
+
+
+void
+ClockerModel::exitTest( CppUnit::Test *test,
+ bool isSuite )
+{
+ m_tests[ m_testIndexes.top() ].m_timer.finish();
+ if ( !isSuite )
+ m_totalTestCaseTime += m_tests.back().m_timer.elapsedTime();
+
+ m_currentPath.up();
+ m_testIndexes.pop();
+}
+
+
+double
+ClockerModel::totalElapsedTime() const
+{
+ return m_tests[0].m_timer.elapsedTime();
+}
+
+
+double
+ClockerModel::averageTestCaseTime() const
+{
+ double average = 0;
+ if ( m_testCaseCount > 0 )
+ average = m_totalTestCaseTime / m_testCaseCount;
+ return average;
+}
+
+
+double
+ClockerModel::testTimeFor( int testIndex ) const
+{
+ return m_tests[ testIndex ].m_timer.elapsedTime();
+}
+
+
+std::string
+ClockerModel::timeStringFor( double time )
+{
+ char buffer[320];
+ const char *format;
+ if ( time < 1 )
+ format = "%2.3f";
+ else if ( time < 10 )
+ format = "%3.2f";
+ else if (time < 100 )
+ format = "%4.1f";
+ else
+ format = "%6f";
+
+ ::sprintf( buffer, format, time );
+
+ return buffer;
+}
+
+
+bool
+ClockerModel::isSuite( int testIndex ) const
+{
+ return m_tests[ testIndex ].m_isSuite;
+}
+
+
+const CppUnit::TestPath &
+ClockerModel::testPathFor( int testIndex ) const
+{
+ return m_tests[ testIndex ].m_path;
+}
+
+
+int
+ClockerModel::indexOf( CppUnit::Test *test ) const
+{
+ TestToIndexes::const_iterator itFound = m_testToIndexes.find( test );
+ if ( itFound != m_testToIndexes.end() )
+ return itFound->second;
+ return -1;
+}
+
+
+int
+ClockerModel::childCountFor( int testIndex ) const
+{
+ return m_tests[ testIndex ].m_childIndexes.size();
+}
+
+
+int
+ClockerModel::childAtFor( int testIndex,
+ int chidIndex ) const
+{
+ return m_tests[ testIndex ].m_childIndexes[ chidIndex ];
+}
diff --git a/examples/ClockerPlugIn/ClockerModel.h b/examples/ClockerPlugIn/ClockerModel.h
new file mode 100644
index 0000000..c61a4b7
--- /dev/null
+++ b/examples/ClockerPlugIn/ClockerModel.h
@@ -0,0 +1,95 @@
+// //////////////////////////////////////////////////////////////////////////
+// Header file ClockerModel.h for class ClockerModel
+// (c)Copyright 2000, Baptiste Lepilleur.
+// Created: 2002/06/14
+// //////////////////////////////////////////////////////////////////////////
+#ifndef CLOCKERMODEL_H
+#define CLOCKERMODEL_H
+
+#include <cppunit/TestPath.h>
+#include <map>
+#include <stack>
+#include <string>
+#include <vector>
+
+#ifdef CLOCKER_USE_WINNTTIMER
+#include "WinNtTimer.h"
+typedef WinNtTimer Timer;
+#else
+#include "Timer.h"
+#endif
+
+
+/// Model that represents test timing.
+class ClockerModel
+{
+public:
+ /*! Constructs a ClockerModel object.
+ */
+ ClockerModel();
+
+ /// Destructor.
+ virtual ~ClockerModel();
+
+ void setExpectedTestCount( int count );
+
+ void enterTest( CppUnit::Test *test,
+ bool isSuite );
+
+ void exitTest( CppUnit::Test *test,
+ bool isSuite );
+
+ double totalElapsedTime() const;
+
+ double averageTestCaseTime() const;
+
+ double testTimeFor( CppUnit::Test *test ) const;
+
+ double testTimeFor( int testIndex ) const;
+
+ static std::string timeStringFor( double time );
+
+ bool isSuite( int testIndex ) const;
+
+ const CppUnit::TestPath &testPathFor( int testIndex ) const;
+
+ // -1 is none
+ int indexOf( CppUnit::Test *test ) const;
+
+ int childCountFor( int testIndex ) const;
+
+ int childAtFor( int testIndex,
+ int chidIndex ) const;
+
+private:
+ struct TestInfo
+ {
+ CppUnit::TestPath m_path;
+ Timer m_timer;
+ bool m_isSuite;
+ std::vector<int> m_childIndexes;
+ };
+
+ /// Prevents the use of the copy constructor.
+ ClockerModel( const ClockerModel &other );
+
+ /// Prevents the use of the copy operator.
+ void operator =( const ClockerModel &other );
+
+private:
+ CppUnit::TestPath m_currentPath;
+
+ int m_testCaseCount;
+ double m_totalTestCaseTime;
+
+ typedef std::map<CppUnit::Test *, int> TestToIndexes;
+
+ TestToIndexes m_testToIndexes;
+ std::stack<int> m_testIndexes;
+ std::vector<TestInfo> m_tests;
+};
+
+
+
+
+#endif // CLOCKERMODEL_H
diff --git a/examples/ClockerPlugIn/ClockerPlugIn.cpp b/examples/ClockerPlugIn/ClockerPlugIn.cpp
index 8943629..dbdd672 100644
--- a/examples/ClockerPlugIn/ClockerPlugIn.cpp
+++ b/examples/ClockerPlugIn/ClockerPlugIn.cpp
@@ -1,6 +1,9 @@
#include <cppunit/TestResult.h>
+#include <cppunit/XmlOutputter.h>
#include <cppunit/plugin/TestPlugIn.h>
+#include "ClockerXmlHook.h"
#include "ClockerListener.h"
+#include "ClockerModel.h"
@@ -9,23 +12,29 @@ class ClockerPlugIn : public CppUnitTestPlugIn
public:
ClockerPlugIn()
: m_dumper( NULL )
+ , m_model( NULL )
+ , m_xmlHook( NULL )
{
}
~ClockerPlugIn()
{
delete m_dumper;
+ delete m_model;
+ delete m_xmlHook;
}
void initialize( CppUnit::TestFactoryRegistry *registry,
const CppUnit::Parameters &parameters )
{
- bool flatten = false;
- if ( parameters.size() > 0 && parameters[0] == "flat" )
- flatten = true;
+ bool text = false;
+ if ( parameters.size() > 0 && parameters[0] == "text" )
+ text = true;
- m_dumper = new ClockerListener( flatten );
+ m_model = new ClockerModel();
+ m_dumper = new ClockerListener( m_model, text );
+ m_xmlHook = new ClockerXmlHook( m_model );
}
@@ -41,12 +50,25 @@ public:
}
+ void addXmlOutputterHooks( CppUnit::XmlOutputter *outputter )
+ {
+ outputter->addHook( m_xmlHook );
+ }
+
+
+ void removeXmlOutputterHooks()
+ {
+ }
+
+
void uninitialize( CppUnit::TestFactoryRegistry *registry )
{
}
private:
ClockerListener *m_dumper;
+ ClockerModel *m_model;
+ ClockerXmlHook *m_xmlHook;
};
diff --git a/examples/ClockerPlugIn/ClockerPlugIn.dsp b/examples/ClockerPlugIn/ClockerPlugIn.dsp
index 98e206a..8d865e1 100644
--- a/examples/ClockerPlugIn/ClockerPlugIn.dsp
+++ b/examples/ClockerPlugIn/ClockerPlugIn.dsp
@@ -44,7 +44,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CLOCKERPLUGIN_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MDd /W3 /GX /O2 /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CPPUNIT_DLL" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CPPUNIT_DLL" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -130,14 +130,34 @@ SOURCE=.\ClockerListener.h
# End Source File
# Begin Source File
+SOURCE=.\ClockerModel.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ClockerModel.h
+# End Source File
+# Begin Source File
+
SOURCE=.\ClockerPlugIn.cpp
# End Source File
# Begin Source File
+SOURCE=.\ClockerXmlHook.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ClockerXmlHook.h
+# End Source File
+# Begin Source File
+
SOURCE=.\Makefile.am
# End Source File
# Begin Source File
+SOURCE=.\ReadMe.txt
+# End Source File
+# Begin Source File
+
SOURCE=.\Timer.cpp
!IF "$(CFG)" == "ClockerPlugIn - Win32 Release"
diff --git a/examples/ClockerPlugIn/ClockerXmlHook.cpp b/examples/ClockerPlugIn/ClockerXmlHook.cpp
new file mode 100644
index 0000000..445b868
--- /dev/null
+++ b/examples/ClockerPlugIn/ClockerXmlHook.cpp
@@ -0,0 +1,94 @@
+// //////////////////////////////////////////////////////////////////////////
+// Implementation file ClockerXmlHook.cpp for class ClockerXmlHook
+// (c)Copyright 2000, Baptiste Lepilleur.
+// Created: 2002/06/14
+// //////////////////////////////////////////////////////////////////////////
+
+#include <cppunit/Test.h>
+#include <cppunit/tools/XmlElement.h>
+#include "ClockerModel.h"
+#include "ClockerXmlHook.h"
+
+
+ClockerXmlHook::ClockerXmlHook( ClockerModel *model )
+ : m_model( model )
+{
+}
+
+
+ClockerXmlHook::~ClockerXmlHook()
+{
+}
+
+
+void
+ClockerXmlHook::endDocument( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *rootNode )
+{
+ CppUnit::XmlElement *testTreeElement = new CppUnit::XmlElement( "TimedTestTree" );
+ rootNode->addElement( testTreeElement );
+
+ addTimedTest( testTreeElement, 0 );
+}
+
+
+void
+ClockerXmlHook::addTimedTest( CppUnit::XmlElement *parentElement,
+ int testIndex )
+{
+ std::string elementName = m_model->isSuite( testIndex ) ? "TimedSuite" : "TimedTest";
+ CppUnit::XmlElement *testElement = new CppUnit::XmlElement( elementName );
+ parentElement->addElement( testElement );
+ testElement->addAttribute( "id", testIndex );
+
+ const CppUnit::TestPath &path = m_model->testPathFor( testIndex );
+ testElement->addElement( new CppUnit::XmlElement( "Name",
+ path.getChildTest()->getName() ) );
+ testElement->addElement( new CppUnit::XmlElement( "TestPath", path.toString() ) );
+ testElement->addElement( new CppUnit::XmlElement( "Time",
+ ClockerModel::timeStringFor(
+ m_model->testTimeFor( testIndex ) ) ) );
+
+ if ( m_model->isSuite( testIndex ) )
+ {
+ for ( int childIndex =0; childIndex < m_model->childCountFor( testIndex ); ++childIndex )
+ addTimedTest( testElement, m_model->childAtFor( testIndex, childIndex ) );
+ }
+}
+
+
+void
+ClockerXmlHook::failTestAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *testNode,
+ CppUnit::Test *test,
+ CppUnit::TestFailure *failure )
+{
+ successfulTestAdded( document, testNode, test );
+}
+
+
+void
+ClockerXmlHook::successfulTestAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *testNode,
+ CppUnit::Test *test )
+{
+ int testIndex = m_model->indexOf( test );
+ double time = (testIndex >= 0) ? m_model->testTimeFor( testIndex ) : 0.0;
+ const CppUnit::TestPath &path = m_model->testPathFor( testIndex );
+ testNode->addElement( new CppUnit::XmlElement( "TestPath", path.toString() ) );
+ testNode->addElement( new CppUnit::XmlElement( "Time",
+ ClockerModel::timeStringFor( time ) ) );
+}
+
+
+void
+ClockerXmlHook::statisticsAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *statisticsNode )
+{
+ statisticsNode->addElement(
+ new CppUnit::XmlElement( "TotalElapsedTime",
+ ClockerModel::timeStringFor( m_model->totalElapsedTime() ) ) );
+ statisticsNode->addElement(
+ new CppUnit::XmlElement( "AverageTestCaseTime",
+ ClockerModel::timeStringFor( m_model->averageTestCaseTime() ) ) );
+}
diff --git a/examples/ClockerPlugIn/ClockerXmlHook.h b/examples/ClockerPlugIn/ClockerXmlHook.h
new file mode 100644
index 0000000..fa86245
--- /dev/null
+++ b/examples/ClockerPlugIn/ClockerXmlHook.h
@@ -0,0 +1,62 @@
+// //////////////////////////////////////////////////////////////////////////
+// Header file ClockerXmlHook.h for class ClockerXmlHook
+// (c)Copyright 2000, Baptiste Lepilleur.
+// Created: 2002/06/14
+// //////////////////////////////////////////////////////////////////////////
+#ifndef CLOCKERXMLHOOK_H
+#define CLOCKERXMLHOOK_H
+
+#include <cppunit/XmlOutputterHook.h>
+
+class ClockerModel;
+
+
+
+/// XML output hook to add test timing and test hierarchy timing.
+class ClockerXmlHook : public CppUnit::XmlOutputterHook
+{
+public:
+ /*! Constructs a ClockerXmlHook object.
+ */
+ ClockerXmlHook( ClockerModel *model );
+
+ /// Destructor.
+ virtual ~ClockerXmlHook();
+
+ void endDocument( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *rootNode );
+
+ void failTestAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *testNode,
+ CppUnit::Test *test,
+ CppUnit::TestFailure *failure );
+
+ void successfulTestAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *testNode,
+ CppUnit::Test *test );
+
+ void statisticsAdded( CppUnit::XmlDocument *document,
+ CppUnit::XmlElement *statisticsNode );
+
+private:
+ /// Prevents the use of the copy constructor.
+ ClockerXmlHook( const ClockerXmlHook &other );
+
+ /// Prevents the use of the copy operator.
+ void operator =( const ClockerXmlHook &other );
+
+ void addTimedTest( CppUnit::XmlElement *parentElement,
+ int testIndex );
+
+private:
+ ClockerModel *m_model;
+};
+
+
+
+// Inlines methods for ClockerXmlHook:
+// -----------------------------------
+
+
+
+#endif // CLOCKERXMLHOOK_H
diff --git a/examples/ClockerPlugIn/ReadMe.txt b/examples/ClockerPlugIn/ReadMe.txt
index 6893fc6..57e4fc5 100644
--- a/examples/ClockerPlugIn/ReadMe.txt
+++ b/examples/ClockerPlugIn/ReadMe.txt
@@ -1,14 +1,44 @@
-A plug-ins that track tests and test suites running time. A demonstration of TestListener and
-test plug-in.
+A test plug-ins that track tests and test suites running time. It demonstrates
+TestListener, TestPlugIn, and XmlOutputterHook.
-Don't use this to profile your application, use a Profiler.
+Both suite and test case times are tracked. The plug-in include in the XML
+output the TestPath of each test cases and its tracked time.
-Usage:
+The timed test hierarchy is also included in the XML output. This way it is
+possible to see the time each suite takes to run.
-The plug-in accept the option "flat" to generate a flattened view of the test tree.
+
+
+* Usage:
+
+Just add this plug-in to DllPlugInTester command line. It will add a test
+listener to track test time, and add a hook to the XmlOutputter to include
+test time to the XmlOutput.
+
+If the option "text" is passed to the plug-in, the timed test tree will be
+printed to stdout.
DllPlugInRunnerd.exe ClockerPlugInd.dll
or
-DllPlugInRunnerd.exe ClockerPlugInd.dll=flat
+DllPlugInRunnerd.exe ClockerPlugInd.dll=text
+
+* Example:
+
+DllPlugInTesterd_dll.exe -x timed.xml ClockerPlugInd.dll CppUnitTestPlugInd.dll
+
+Will track time of all tests contains in CppUnitTestPlugInd.dll and save the
+result in timed.xml.
+
+* Notes:
+
+The id of the <TimedTestTree> are different than those of the
+<SuccessfulTests> and <FailedTests> trees. You can use the <TestPath> to
+cross-reference the datas.
+
+* Remarks:
+You may want to review ClockerModel before using this plug-in for serious
+purpose, add timing based on the process cpu time.
+A version is provided for NT that use the main thread cpu time. This is an issue
+if the test cases are multithreaded.