Integrate testcocoon support into Qt build system.
To instrument a Qt application or library with the TestCocoon coverage tool, do `CONFIG+=testcocoon' in the application .pro file. To instrument Qt itself with testcocoon, use the `-testcocoon' configure option. Change-Id: Ie77109a078d11ea51f7a073621e0df9c752c44ae Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com> Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
This commit is contained in:
parent
b4d23e61ed
commit
4e014ace45
9
configure
vendored
9
configure
vendored
@ -1038,7 +1038,7 @@ while [ "$#" -gt 0 ]; do
|
|||||||
VAL=no
|
VAL=no
|
||||||
;;
|
;;
|
||||||
#Qt style yes options
|
#Qt style yes options
|
||||||
-incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-harfbuzz|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-v8|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-icu|-force-asserts)
|
-incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-harfbuzz|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-v8|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon)
|
||||||
VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
|
VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
|
||||||
VAL=yes
|
VAL=yes
|
||||||
;;
|
;;
|
||||||
@ -1520,6 +1520,11 @@ while [ "$#" -gt 0 ]; do
|
|||||||
UNKNOWN_OPT=yes
|
UNKNOWN_OPT=yes
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
testcocoon)
|
||||||
|
if [ "$VAL" = "yes" ]; then
|
||||||
|
QTCONFIG_CONFIG="$QTCONFIG_CONFIG testcocoon"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
exceptions|g++-exceptions)
|
exceptions|g++-exceptions)
|
||||||
if [ "$VAL" = "no" ]; then
|
if [ "$VAL" = "no" ]; then
|
||||||
CFG_EXCEPTIONS=no
|
CFG_EXCEPTIONS=no
|
||||||
@ -3925,6 +3930,8 @@ cat << EOF
|
|||||||
-qtnamespace <name> Wraps all Qt library code in 'namespace <name> {...}'.
|
-qtnamespace <name> Wraps all Qt library code in 'namespace <name> {...}'.
|
||||||
-qtlibinfix <infix> Renames all libQt*.so to libQt*<infix>.so.
|
-qtlibinfix <infix> Renames all libQt*.so to libQt*<infix>.so.
|
||||||
|
|
||||||
|
-testcocoon Instrument Qt with the TestCocoon code coverage tool.
|
||||||
|
|
||||||
-D <string> ........ Add an explicit define to the preprocessor.
|
-D <string> ........ Add an explicit define to the preprocessor.
|
||||||
-I <string> ........ Add an explicit include path.
|
-I <string> ........ Add an explicit include path.
|
||||||
-L <string> ........ Add an explicit library path.
|
-L <string> ........ Add an explicit library path.
|
||||||
|
57
mkspecs/features/testcocoon.prf
Normal file
57
mkspecs/features/testcocoon.prf
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#
|
||||||
|
# Tested with TestCocoon 1.6.14
|
||||||
|
#
|
||||||
|
|
||||||
|
load(resolve_target)
|
||||||
|
|
||||||
|
# Retrieve the target basename
|
||||||
|
TARGET_BASENAME = $$basename(QMAKE_RESOLVED_TARGET)
|
||||||
|
|
||||||
|
# Configure testcocoon for a full instrumentation - excluding the moc, ui and qrc files from the instrumentation
|
||||||
|
# --cs-output defines the name to give to the execution report (.csexe).
|
||||||
|
TESTCOCOON_COVERAGE_OPTIONS = \
|
||||||
|
--cs-qt4 \
|
||||||
|
--cs-exclude-file-regex=\'(^|[/\\\\])ui_.*\\.h\$\$\' \
|
||||||
|
--cs-exclude-file-regex=\'(^|[/\\\\])(qrc|moc)_.*\\.cpp\$\$\' \
|
||||||
|
--cs-exclude-file-regex=\'.*\\.moc\$\$\' \
|
||||||
|
--cs-exclude-file-regex=\'.*\\.g\$\$\' \
|
||||||
|
--cs-output=\'$$TARGET_BASENAME\' # name of the csexe file (execution report)
|
||||||
|
|
||||||
|
# The .csmes file should be placed alongside the .so or binary.
|
||||||
|
# Unfortunately, testcocoon has no option to specify the output directory,
|
||||||
|
# so we must move it into place if a custom destdir was used.
|
||||||
|
# We don't move applications' csmes because some qt applications (tools, examples)
|
||||||
|
# are using DESTDIR in some cases but always alongside target.path, so the binary
|
||||||
|
# is built directly in target.path and there is no need to move the csmes.
|
||||||
|
!isEmpty(DESTDIR):contains(TEMPLATE, lib) {
|
||||||
|
!isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
|
||||||
|
QMAKE_POST_LINK = -$(MOVE) $${TARGET_BASENAME}.csmes $${QMAKE_RESOLVED_TARGET}.csmes$$QMAKE_POST_LINK
|
||||||
|
}
|
||||||
|
|
||||||
|
QMAKE_CLEAN += *.csexe *.csmes
|
||||||
|
|
||||||
|
# The compiler/linker is replaced by the coveragescanner which is named after the name of the
|
||||||
|
# compiler/linker preceded by cs (ie gcc is replaced by csgcc).
|
||||||
|
# Testcocoon options defined in TESTCOCOON_COVERAGE_OPTIONS are added as argument to the coveragescanner (ie csgcc).
|
||||||
|
# In practice they are added as compiler/linker flags.
|
||||||
|
|
||||||
|
*-g++* {
|
||||||
|
QMAKE_CXX ~= s/(\\S*g\\+\\+)/cs\\1/
|
||||||
|
QMAKE_CC ~= s/(\\S*gcc)/cs\\1/
|
||||||
|
QMAKE_LINK ~= s/(\\S*g\\+\\+|\\S*gcc)/cs\\1/
|
||||||
|
QMAKE_AR ~= s/(\\S*ar)/cs\\1/
|
||||||
|
QMAKE_AR += $$TESTCOCOON_COVERAGE_OPTIONS
|
||||||
|
} else {
|
||||||
|
error("Non-gcc qmake specs not supported by TestCocoon integration yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
QMAKE_CFLAGS += $$TESTCOCOON_COVERAGE_OPTIONS
|
||||||
|
QMAKE_CXXFLAGS += $$TESTCOCOON_COVERAGE_OPTIONS
|
||||||
|
QMAKE_LFLAGS += $$TESTCOCOON_COVERAGE_OPTIONS
|
||||||
|
|
||||||
|
unix {
|
||||||
|
QMAKE_LFLAGS += --cs-libgen=-fPIC
|
||||||
|
}
|
||||||
|
|
||||||
|
unset(TARGET_BASENAME)
|
||||||
|
unset(TESTCOCOON_COVERAGE_OPTIONS)
|
@ -400,6 +400,60 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QL
|
|||||||
|
|
||||||
#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
|
#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK)
|
||||||
|
|
||||||
|
static void installCoverageTool(QLibraryPrivate *libPrivate)
|
||||||
|
{
|
||||||
|
#ifdef __COVERAGESCANNER__
|
||||||
|
/*
|
||||||
|
__COVERAGESCANNER__ is defined when Qt has been instrumented for code
|
||||||
|
coverage by TestCocoon. CoverageScanner is the name of the tool that
|
||||||
|
generates the code instrumentation.
|
||||||
|
This code is required here when code coverage analysis with TestCocoon
|
||||||
|
is enabled in order to allow the loading application to register the plugin
|
||||||
|
and then store its execution report. The execution report gathers information
|
||||||
|
about each part of the plugin's code that has been used when
|
||||||
|
the plugin was loaded by the launching application.
|
||||||
|
The execution report for the plugin will go to the same execution report
|
||||||
|
as the one defined for the application loading it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ret = __coveragescanner_register_library(libPrivate->fileName.toLocal8Bit());
|
||||||
|
|
||||||
|
if (qt_debug_component()) {
|
||||||
|
if (ret >= 0) {
|
||||||
|
qDebug("%s: coverage data for %s registered",
|
||||||
|
Q_FUNC_INFO,
|
||||||
|
qPrintable(libPrivate->fileName));
|
||||||
|
} else {
|
||||||
|
qWarning("%s: could not register %s: error %d; coverage data may be incomplete",
|
||||||
|
Q_FUNC_INFO,
|
||||||
|
qPrintable(libPrivate->fileName),
|
||||||
|
ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(libPrivate);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void releaseCoverageTool(QLibraryPrivate *libPrivate)
|
||||||
|
{
|
||||||
|
#ifdef __COVERAGESCANNER__
|
||||||
|
/*
|
||||||
|
__COVERAGESCANNER__ is defined when Qt has been instrumented for code
|
||||||
|
coverage by TestCocoon.
|
||||||
|
Here is the code to save the execution data.
|
||||||
|
See comments about initialization in QLibraryPrivate::load().
|
||||||
|
*/
|
||||||
|
if (libPrivate->pHnd) {
|
||||||
|
__coveragescanner_save();
|
||||||
|
__coveragescanner_clear();
|
||||||
|
__coveragescanner_unregister_library(libPrivate->fileName.toLocal8Bit());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(libPrivate);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
typedef QMap<QString, QLibraryPrivate*> LibraryMap;
|
typedef QMap<QString, QLibraryPrivate*> LibraryMap;
|
||||||
|
|
||||||
struct LibraryData {
|
struct LibraryData {
|
||||||
@ -465,6 +519,8 @@ bool QLibraryPrivate::load()
|
|||||||
lib->loadedLibs += this;
|
lib->loadedLibs += this;
|
||||||
libraryRefCount.ref();
|
libraryRefCount.ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
installCoverageTool(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -494,6 +550,8 @@ bool QLibraryPrivate::unload()
|
|||||||
|
|
||||||
void QLibraryPrivate::release()
|
void QLibraryPrivate::release()
|
||||||
{
|
{
|
||||||
|
releaseCoverageTool(this);
|
||||||
|
|
||||||
QMutexLocker locker(qt_library_mutex());
|
QMutexLocker locker(qt_library_mutex());
|
||||||
if (!libraryRefCount.deref())
|
if (!libraryRefCount.deref())
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -13,6 +13,14 @@ unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore
|
|||||||
|
|
||||||
load(qt_module_config)
|
load(qt_module_config)
|
||||||
|
|
||||||
|
# Code coverage with TestCocoon
|
||||||
|
# The following is required as extra compilers use $$QMAKE_CXX instead of $(CXX).
|
||||||
|
# Without this, testcocoon.prf is read only after $$QMAKE_CXX is used by the
|
||||||
|
# extra compilers.
|
||||||
|
testcocoon {
|
||||||
|
load(testcocoon)
|
||||||
|
}
|
||||||
|
|
||||||
HEADERS += $$QT_SOURCE_TREE/src/gui/qtguiversion.h
|
HEADERS += $$QT_SOURCE_TREE/src/gui/qtguiversion.h
|
||||||
|
|
||||||
include(accessible/accessible.pri)
|
include(accessible/accessible.pri)
|
||||||
|
@ -857,6 +857,35 @@ QT_BEGIN_NAMESPACE
|
|||||||
QTouchEventSequence is called (ie when the object returned runs out of scope).
|
QTouchEventSequence is called (ie when the object returned runs out of scope).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void installCoverageTool(const char * appname, const char * testname)
|
||||||
|
{
|
||||||
|
#ifdef __COVERAGESCANNER__
|
||||||
|
// Install Coverage Tool
|
||||||
|
__coveragescanner_install(appname);
|
||||||
|
__coveragescanner_testname(testname);
|
||||||
|
__coveragescanner_clear();
|
||||||
|
#else
|
||||||
|
Q_UNUSED(appname);
|
||||||
|
Q_UNUSED(testname);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveCoverageTool(const char * appname, bool testfailed)
|
||||||
|
{
|
||||||
|
#ifdef __COVERAGESCANNER__
|
||||||
|
// install again to make sure the filename is correct.
|
||||||
|
// without this, a plugin or similar may have changed the filename.
|
||||||
|
__coveragescanner_install(appname);
|
||||||
|
__coveragescanner_teststate(testfailed ? "FAILED" : "PASSED");
|
||||||
|
__coveragescanner_save();
|
||||||
|
__coveragescanner_testname("");
|
||||||
|
__coveragescanner_clear();
|
||||||
|
#else
|
||||||
|
Q_UNUSED(appname);
|
||||||
|
Q_UNUSED(testfailed);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
namespace QTest
|
namespace QTest
|
||||||
{
|
{
|
||||||
static QObject *currentTestObject = 0;
|
static QObject *currentTestObject = 0;
|
||||||
@ -1904,6 +1933,8 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
|
|||||||
const QMetaObject *metaObject = testObject->metaObject();
|
const QMetaObject *metaObject = testObject->metaObject();
|
||||||
QTEST_ASSERT(metaObject);
|
QTEST_ASSERT(metaObject);
|
||||||
|
|
||||||
|
installCoverageTool(argv[0], metaObject->className());
|
||||||
|
|
||||||
QTestResult::setCurrentTestObject(metaObject->className());
|
QTestResult::setCurrentTestObject(metaObject->className());
|
||||||
qtest_qParseArgs(argc, argv, false);
|
qtest_qParseArgs(argc, argv, false);
|
||||||
#ifdef QTESTLIB_USE_VALGRIND
|
#ifdef QTESTLIB_USE_VALGRIND
|
||||||
@ -1954,6 +1985,8 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
saveCoverageTool(argv[0], QTestResult::failCount());
|
||||||
|
|
||||||
#ifdef QTESTLIB_USE_VALGRIND
|
#ifdef QTESTLIB_USE_VALGRIND
|
||||||
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess)
|
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess)
|
||||||
return callgrindChildExitCode;
|
return callgrindChildExitCode;
|
||||||
|
@ -44,6 +44,14 @@ contains(DEFINES,QT_EVAL):include($$QT_SOURCE_TREE/src/corelib/eval.pri)
|
|||||||
|
|
||||||
QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist
|
QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist
|
||||||
|
|
||||||
|
# Code coverage with TestCocoon
|
||||||
|
# The following is required as extra compilers use $$QMAKE_CXX instead of $(CXX).
|
||||||
|
# Without this, testcocoon.prf is read only after $$QMAKE_CXX is used by the
|
||||||
|
# extra compilers.
|
||||||
|
testcocoon {
|
||||||
|
load(testcocoon)
|
||||||
|
}
|
||||||
|
|
||||||
DEFINES += Q_INTERNAL_QAPP_SRC
|
DEFINES += Q_INTERNAL_QAPP_SRC
|
||||||
|
|
||||||
INCLUDEPATH += ../3rdparty/harfbuzz/src
|
INCLUDEPATH += ../3rdparty/harfbuzz/src
|
||||||
|
@ -3,5 +3,6 @@ TEMPLATE = subdirs
|
|||||||
SUBDIRS = auto
|
SUBDIRS = auto
|
||||||
|
|
||||||
# benchmarks in debug mode is rarely sensible
|
# benchmarks in debug mode is rarely sensible
|
||||||
contains(QT_CONFIG,release):SUBDIRS += benchmarks
|
# benchmarks are not sensible for code coverage (here with tool testcocoon)
|
||||||
|
!testcocoon:contains(QT_CONFIG,release):SUBDIRS += benchmarks
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user