From 4e014ace452af8f1e22b95ba22d112fc2419ec6d Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 23 Jun 2011 10:48:33 +0200 Subject: 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 Reviewed-by: Rohan McGovern --- src/corelib/plugin/qlibrary.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ src/gui/gui.pro | 8 ++++++ src/testlib/qtestcase.cpp | 33 +++++++++++++++++++++++ src/widgets/widgets.pro | 8 ++++++ 4 files changed, 107 insertions(+) (limited to 'src') diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 9eeb783b60..6a40b5b818 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -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) +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 LibraryMap; struct LibraryData { @@ -465,6 +519,8 @@ bool QLibraryPrivate::load() lib->loadedLibs += this; libraryRefCount.ref(); } + + installCoverageTool(this); } return ret; @@ -494,6 +550,8 @@ bool QLibraryPrivate::unload() void QLibraryPrivate::release() { + releaseCoverageTool(this); + QMutexLocker locker(qt_library_mutex()); if (!libraryRefCount.deref()) delete this; diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 40888ade41..db045930a3 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -13,6 +13,14 @@ unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore 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 include(accessible/accessible.pri) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 4e0205ccbc..f01c588e6d 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -857,6 +857,35 @@ QT_BEGIN_NAMESPACE 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 { static QObject *currentTestObject = 0; @@ -1904,6 +1933,8 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) const QMetaObject *metaObject = testObject->metaObject(); QTEST_ASSERT(metaObject); + installCoverageTool(argv[0], metaObject->className()); + QTestResult::setCurrentTestObject(metaObject->className()); qtest_qParseArgs(argc, argv, false); #ifdef QTESTLIB_USE_VALGRIND @@ -1954,6 +1985,8 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) } #endif + saveCoverageTool(argv[0], QTestResult::failCount()); + #ifdef QTESTLIB_USE_VALGRIND if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) return callgrindChildExitCode; diff --git a/src/widgets/widgets.pro b/src/widgets/widgets.pro index d0425cac25..8f6a9713f6 100644 --- a/src/widgets/widgets.pro +++ b/src/widgets/widgets.pro @@ -44,6 +44,14 @@ contains(DEFINES,QT_EVAL):include($$QT_SOURCE_TREE/src/corelib/eval.pri) 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 INCLUDEPATH += ../3rdparty/harfbuzz/src -- cgit v1.2.3