VAL=no
;;
#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,"`
VAL=yes
;;
UNKNOWN_OPT=yes
fi
;;
+ testcocoon)
+ if [ "$VAL" = "yes" ]; then
+ QTCONFIG_CONFIG="$QTCONFIG_CONFIG testcocoon"
+ fi
+ ;;
exceptions|g++-exceptions)
if [ "$VAL" = "no" ]; then
CFG_EXCEPTIONS=no
-qtnamespace <name> Wraps all Qt library code in 'namespace <name> {...}'.
-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.
-I <string> ........ Add an explicit include path.
-L <string> ........ Add an explicit library path.
--- /dev/null
+#
+# 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)
#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;
struct LibraryData {
lib->loadedLibs += this;
libraryRefCount.ref();
}
+
+ installCoverageTool(this);
}
return ret;
void QLibraryPrivate::release()
{
+ releaseCoverageTool(this);
+
QMutexLocker locker(qt_library_mutex());
if (!libraryRefCount.deref())
delete this;
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)
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;
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
}
#endif
+ saveCoverageTool(argv[0], QTestResult::failCount());
+
#ifdef QTESTLIB_USE_VALGRIND
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess)
return callgrindChildExitCode;
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
SUBDIRS = auto
# 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
}