From 5c27f0a2fb772279fb3e4d60f7c879f5cecb3352 Mon Sep 17 00:00:00 2001 From: Holger Ihrig Date: Fri, 26 Aug 2011 15:03:33 +0200 Subject: Moving relevant tests to corelib/tools Task-number: QTBUG-21066 Change-Id: I650f8f7826b9feea7c1484f06e03e10c68ec2b65 Reviewed-on: http://codereview.qt.nokia.com/3712 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/corelib/tools/qsharedpointer/.gitignore | 1 + .../corelib/tools/qsharedpointer/externaltests.cpp | 745 ++++++++ .../corelib/tools/qsharedpointer/externaltests.h | 132 ++ .../corelib/tools/qsharedpointer/externaltests.pri | 8 + .../tools/qsharedpointer/forwarddeclaration.cpp | 52 + .../tools/qsharedpointer/forwarddeclared.cpp | 53 + .../corelib/tools/qsharedpointer/forwarddeclared.h | 54 + .../tools/qsharedpointer/qsharedpointer.pro | 15 + .../tools/qsharedpointer/tst_qsharedpointer.cpp | 1922 ++++++++++++++++++++ .../auto/corelib/tools/qsharedpointer/wrapper.cpp | 60 + tests/auto/corelib/tools/qsharedpointer/wrapper.h | 58 + 11 files changed, 3100 insertions(+) create mode 100644 tests/auto/corelib/tools/qsharedpointer/.gitignore create mode 100644 tests/auto/corelib/tools/qsharedpointer/externaltests.cpp create mode 100644 tests/auto/corelib/tools/qsharedpointer/externaltests.h create mode 100644 tests/auto/corelib/tools/qsharedpointer/externaltests.pri create mode 100644 tests/auto/corelib/tools/qsharedpointer/forwarddeclaration.cpp create mode 100644 tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp create mode 100644 tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h create mode 100644 tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro create mode 100644 tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp create mode 100644 tests/auto/corelib/tools/qsharedpointer/wrapper.cpp create mode 100644 tests/auto/corelib/tools/qsharedpointer/wrapper.h (limited to 'tests/auto/corelib/tools/qsharedpointer') diff --git a/tests/auto/corelib/tools/qsharedpointer/.gitignore b/tests/auto/corelib/tools/qsharedpointer/.gitignore new file mode 100644 index 0000000000..3cd9f1a085 --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/.gitignore @@ -0,0 +1 @@ +tst_qsharedpointer diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp new file mode 100644 index 0000000000..1bfa1c10a0 --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp @@ -0,0 +1,745 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "externaltests.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_SYMBIAN +#define DEFAULT_MAKESPEC "X:/STLsupport/mkspecs/symbian-abld/" +#endif + +#ifndef DEFAULT_MAKESPEC +# error DEFAULT_MAKESPEC not defined +#endif + +#ifdef Q_OS_UNIX +# include +# include +#endif + +static QString makespec() +{ + static const char default_makespec[] = DEFAULT_MAKESPEC; + const char *p; + for (p = default_makespec + sizeof(default_makespec) - 1; p >= default_makespec; --p) + if (*p == '/' || *p == '\\') + break; + + return QString::fromLatin1(p + 1); +} + +static bool removeRecursive(const QString &pathname) +{ + QFileInfo fi(pathname); + if (!fi.exists()) + return true; + + if (fi.isFile()) + return QFile::remove(pathname); + + if (!fi.isDir()) { + // not a file or directory. How do I remove it? + return false; + } + + // not empty -- we must empty it first + QDirIterator di(pathname, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot); + while (di.hasNext()) { + di.next(); + if (!di.fileInfo().exists() && !di.fileInfo().isSymLink()) + continue; + bool ok; + if (di.fileInfo().isFile() || di.fileInfo().isSymLink()) + ok = QFile::remove(di.filePath()); + else + ok = removeRecursive(di.filePath()); + if (!ok) { + return false; + } + } + + QDir dir(pathname); + QString dirname = dir.dirName(); + dir.cdUp(); + return dir.rmdir(dirname); +} + +QT_BEGIN_NAMESPACE +namespace QTest { + class QExternalProcess: public QProcess + { + protected: +#ifdef Q_OS_UNIX + void setupChildProcess() + { + // run in user code + QProcess::setupChildProcess(); + + if (processChannelMode() == ForwardedChannels) { + // reopen /dev/tty into stdin + int fd = ::open("/dev/tty", O_RDONLY); + if (fd == -1) + return; + ::dup2(fd, 0); + ::close(fd); + } + } +#endif + }; + + class QExternalTestPrivate + { + public: + QExternalTestPrivate() + : qtModules(QExternalTest::QtCore | QExternalTest::QtGui | QExternalTest::QtTest), + appType(QExternalTest::AutoApplication), + exitCode(-1) + { + } + ~QExternalTestPrivate() + { + clear(); + } + + enum Target { Compile, Link, Run }; + + QList qmakeLines; + QStringList extraProgramSources; + QByteArray programHeader; + QExternalTest::QtModules qtModules; + QExternalTest::ApplicationType appType; + + QString temporaryDir; + QByteArray sourceCode; + QByteArray std_out; + QByteArray std_err; + int exitCode; + QExternalTest::Stage failedStage; + + void clear(); + bool tryCompile(const QByteArray &body); + bool tryLink(const QByteArray &body); + bool tryRun(const QByteArray &body); + + private: + void removeTemporaryDirectory(); + bool createTemporaryDirectory(); + bool prepareSourceCode(const QByteArray &body); + bool createProjectFile(); + bool runQmake(); + bool runMake(Target target); + bool commonSetup(const QByteArray &body); + }; + + QExternalTest::QExternalTest() + : d(new QExternalTestPrivate) + { + } + + QExternalTest::~QExternalTest() + { + delete d; + } + + QList QExternalTest::qmakeSettings() const + { + return d->qmakeLines; + } + + void QExternalTest::setQmakeSettings(const QList &settings) + { + d->qmakeLines = settings; + } + + QExternalTest::QtModules QExternalTest::qtModules() const + { + return d->qtModules; + } + + void QExternalTest::setQtModules(QtModules modules) + { + d->qtModules = modules; + } + + QExternalTest::ApplicationType QExternalTest::applicationType() const + { + return d->appType; + } + + void QExternalTest::setApplicationType(ApplicationType type) + { + d->appType = type; + } + + QStringList QExternalTest::extraProgramSources() const + { + return d->extraProgramSources; + } + + void QExternalTest::setExtraProgramSources(const QStringList &extra) + { + d->extraProgramSources = extra; + } + + QByteArray QExternalTest::programHeader() const + { + return d->programHeader; + } + + void QExternalTest::setProgramHeader(const QByteArray &header) + { + d->programHeader = header; + } + + bool QExternalTest::tryCompile(const QByteArray &body) + { + return d->tryCompile(body) && d->exitCode == 0; + } + + bool QExternalTest::tryLink(const QByteArray &body) + { + return d->tryLink(body) && d->exitCode == 0; + } + + bool QExternalTest::tryRun(const QByteArray &body) + { + return d->tryRun(body) && d->exitCode == 0; + } + + bool QExternalTest::tryCompileFail(const QByteArray &body) + { + return d->tryCompile(body) && d->exitCode != 0; + } + + bool QExternalTest::tryLinkFail(const QByteArray &body) + { + return d->tryLink(body) && d->exitCode != 0; + } + + bool QExternalTest::tryRunFail(const QByteArray &body) + { + return d->tryRun(body) && d->exitCode != 0; + } + + QExternalTest::Stage QExternalTest::failedStage() const + { + return d->failedStage; + } + + int QExternalTest::exitCode() const + { + return d->exitCode; + } + + QByteArray QExternalTest::fullProgramSource() const + { + return d->sourceCode; + } + + QByteArray QExternalTest::standardOutput() const + { + return d->std_out; + } + + QByteArray QExternalTest::standardError() const + { + return d->std_err; + } + + QString QExternalTest::errorReport() const + { + const char *stage = 0; + switch (d->failedStage) { + case FileStage: + stage = "creating files"; + break; + case QmakeStage: + stage = "executing qmake"; + break; + case CompilationStage: + stage = "during compilation"; + break; + case LinkStage: + stage = "during linking"; + break; + case RunStage: + stage = "executing program"; + break; + } + + QString report = QString::fromLatin1( + "External test failed %1 with exit code %4\n" + "==== standard error: ====\n" + "%2\n" + "==== standard output: ====\n" + "%3\n" + "==== ====\n"); + return report.arg(QString::fromLatin1(stage), + QString::fromLocal8Bit(d->std_err), + QString::fromLocal8Bit(d->std_out)) + .arg(d->exitCode); + } + + // actual execution code + void QExternalTestPrivate::clear() + { + if (!temporaryDir.isEmpty()) + removeTemporaryDirectory(); + + sourceCode.clear(); + std_out.clear(); + std_err.clear(); + exitCode = -1; + failedStage = QExternalTest::FileStage; + } + + void QExternalTestPrivate::removeTemporaryDirectory() + { + if (temporaryDir.isEmpty()) + qWarning() << "Temporary directory is expected to be non-empty"; + removeRecursive(temporaryDir); + temporaryDir.clear(); + } + + bool QExternalTestPrivate::prepareSourceCode(const QByteArray &body) + { + sourceCode.clear(); + sourceCode.reserve(8192); + + sourceCode += programHeader; + + // Add Qt header includes + if (qtModules & QExternalTest::QtCore) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtGui) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtNetwork) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtXml) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtXmlPatterns) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtOpenGL) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtSql) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtSvg) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtScript) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtTest) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtDBus) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::QtWebKit) + sourceCode += "#include \n"; + if (qtModules & QExternalTest::Phonon) + sourceCode += "#include \n"; + sourceCode += + "#include \n" + "#include \n"; + + sourceCode += + "\n" + "void q_external_test_user_code()\n" + "{\n" + "#include \"user_code.cpp\"\n" + "}\n" + "\n" + "#ifdef Q_OS_WIN\n" + "#include \n" + "static void q_test_setup()\n" + "{\n" + " SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n" + "}\n" + "#else\n" + "static void q_test_setup() { }\n" + "#endif\n" + "int main(int argc, char **argv)\n" + "{\n"; + + switch (appType) { + applicationless: + case QExternalTest::Applicationless: + sourceCode += + " (void)argc; (void)argv;\n"; + break; + + coreapplication: + case QExternalTest::QCoreApplication: + sourceCode += + " QCoreApplication app(argc, argv);\n"; + break; + + case QExternalTest::QApplicationTty: + sourceCode += + " QApplication app(argc, argv, QApplication::Tty);\n"; + break; + + guiapplication: + case QExternalTest::QApplicationGuiClient: + sourceCode += + " QApplication app(argc, argv, QApplication::GuiClient);\n"; + break; + + case QExternalTest::QApplicationGuiServer: + sourceCode += + " QApplication app(argc, argv, QApplication::GuiServer);\n"; + break; + + case QExternalTest::AutoApplication: + if (qtModules & QExternalTest::QtGui) + goto guiapplication; + if (qtModules == 0) + goto applicationless; + goto coreapplication; + } + + sourceCode += + " q_test_setup();\n" + " q_external_test_user_code();\n" + " return 0;\n" + "}\n"; + + QFile sourceFile(temporaryDir + QLatin1String("/project.cpp")); + if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + std_err = sourceFile.errorString().toLocal8Bit(); + return false; + } + + sourceFile.write(sourceCode); + sourceFile.close(); + + sourceFile.setFileName(temporaryDir + QLatin1String("/user_code.cpp")); + if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + std_err = sourceFile.errorString().toLocal8Bit(); + return false; + } + sourceFile.write(body); + + return true; + } + + bool QExternalTestPrivate::createTemporaryDirectory() + { + QDir temp = QDir::temp(); + QString subdir = QString::fromLatin1("qexternaltest-%1-%2-%3") + .arg(QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss"))) + .arg(quintptr(this), 0, 16) + .arg(qrand()); + if (!temp.mkdir(subdir)) + return false; + + if (!temp.cd(subdir)) + return false; + + temporaryDir = temp.absolutePath(); + return true; + } + + bool QExternalTestPrivate::createProjectFile() + { + if (temporaryDir.isEmpty()) + qWarning() << "Temporary directory is expected to be non-empty"; + + QFile projectFile(temporaryDir + QLatin1String("/project.pro")); + if (!projectFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + std_err = projectFile.errorString().toLocal8Bit(); + return false; + } + + projectFile.write( + "TEMPLATE = app\n" + "\n" + "TARGET = externaltest\n" + "CONFIG -= app_bundle\n" // for the Mac + "CONFIG -= debug_and_release\n" + "DESTDIR = .\n" + "OBJECTS_DIR = .\n" + "UI_DIR = .\n" + "MOC_DIR = .\n" + "RCC_DIR = .\n" + "HEADERS +=\n" + "SOURCES += project.cpp\n" + "QT -= core gui\n" + "INCLUDEPATH += . "); + projectFile.write(QFile::encodeName(QDir::currentPath())); + +#ifndef QT_NO_DEBUG + projectFile.write("\nCONFIG += debug\n"); +#else + projectFile.write("\nCONFIG += release\n"); +#endif + + QByteArray extraSources = QFile::encodeName(extraProgramSources.join(" ")); + if (!extraSources.isEmpty()) { + projectFile.write("SOURCES += "); + projectFile.write(extraSources); + projectFile.putChar('\n'); + } + + // Add Qt modules + if (qtModules & QExternalTest::QtCore) + projectFile.write("QT += core\n"); + if (qtModules & QExternalTest::QtGui) + projectFile.write("QT += gui\n"); + if (qtModules & QExternalTest::QtNetwork) + projectFile.write("QT += network\n"); + if (qtModules & QExternalTest::QtXml) + projectFile.write("QT += xml\n"); + if (qtModules & QExternalTest::QtXmlPatterns) + projectFile.write("QT += xmlpatterns\n"); + if (qtModules & QExternalTest::QtOpenGL) + projectFile.write("QT += opengl\n"); + if (qtModules & QExternalTest::QtSql) + projectFile.write("QT += sql\n"); + if (qtModules & QExternalTest::QtSvg) + projectFile.write("QT += svg\n"); + if (qtModules & QExternalTest::QtScript) + projectFile.write("QT += script\n"); + if (qtModules & QExternalTest::QtTest) + projectFile.write("QT += testlib\n"); + if (qtModules & QExternalTest::QtDBus) + projectFile.write("QT += dbus\n"); + if (qtModules & QExternalTest::QtWebKit) + projectFile.write("QT += webkit\n"); + if (qtModules & QExternalTest::Phonon) + projectFile.write("QT += phonon\n"); + + projectFile.write("\n### User-specified settings start ###\n"); + foreach (QByteArray line, qmakeLines) { + projectFile.write(line); + projectFile.write("\n"); + } + projectFile.write("\n### User-specified settings end ###\n"); + + // Use qmake to just compile: + projectFile.write( + "\n" + "test_compile.depends += $(OBJECTS)\n" + "QMAKE_EXTRA_TARGETS += test_compile\n"); + + // Use qmake to run the app too: + projectFile.write( + "\n" + "unix:test_run.commands = ./$(QMAKE_TARGET)\n" + "else:test_run.commands = $(QMAKE_TARGET)\n" + "embedded:test_run.commands += -qws\n" + "QMAKE_EXTRA_TARGETS += test_run\n"); + + // Use qmake to debug: + projectFile.write( + "\n" + "*-g++* {\n" + " unix:test_debug.commands = gdb --args ./$(QMAKE_TARGET)\n" + " else:test_debug.commands = gdb --args $(QMAKE_TARGET)\n" + " embedded:test_debug.commands += -qws\n" + " QMAKE_EXTRA_TARGETS += test_debug\n" + "}\n"); + + // Also use qmake to run the app with valgrind: + projectFile.write( + "\n" + "unix:test_valgrind.commands = valgrind ./$(QMAKE_TARGET)\n" + "else:test_valgrind.commands = valgrind $(QMAKE_TARGET)\n" + "embedded:test_valgrind.commands += -qws\n" + "QMAKE_EXTRA_TARGETS += test_valgrind\n"); + + return true; + } + + bool QExternalTestPrivate::runQmake() + { + if (temporaryDir.isEmpty()) + qWarning() << "Temporary directory is expected to be non-empty"; + + if (!createProjectFile()) + return false; + + failedStage = QExternalTest::QmakeStage; + QProcess qmake; + QStringList args; + args << QLatin1String("-makefile") + << QLatin1String("-spec") + << makespec() + << QLatin1String("project.pro"); + qmake.setWorkingDirectory(temporaryDir); + qmake.start(QLatin1String("qmake"), args); + + std_out += "### --- stdout from qmake --- ###\n"; + std_err += "### --- stderr from qmake --- ###\n"; + bool ok = qmake.waitForStarted(); + if (!ok) { + exitCode = 255; + std_err += "qmake: "; + std_err += qmake.errorString().toLocal8Bit(); + } else { + ok = qmake.waitForFinished(); + exitCode = qmake.exitCode(); + + std_out += qmake.readAllStandardOutput(); + std_err += qmake.readAllStandardError(); + } + + return ok && exitCode == 0; + } + + bool QExternalTestPrivate::runMake(Target target) + { + if (temporaryDir.isEmpty()) + qWarning() << "Temporary directory is expected to be non-empty"; + + QExternalProcess make; + make.setWorkingDirectory(temporaryDir); + + QStringList environment = QProcess::systemEnvironment(); + environment += QLatin1String("LC_ALL=C"); + make.setEnvironment(environment); + + QStringList args; + QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels; + if (target == Compile) { + args << QLatin1String("test_compile"); + } else if (target == Run) { + QByteArray run = qgetenv("QTEST_EXTERNAL_RUN"); + if (run == "valgrind") + args << QLatin1String("test_valgrind"); + else if (run == "debug") + args << QLatin1String("test_debug"); + else + args << QLatin1String("test_run"); + if (!run.isEmpty()) + channelMode = QProcess::ForwardedChannels; + } + + make.setProcessChannelMode(channelMode); + + static const char makes[] = + "nmake.exe\0" //for visual c++ + "mingw32-make.exe\0" //for mingw + "gmake\0" + "make\0"; + for (const char *p = makes; *p; p += strlen(p) + 1) { + make.start(QLatin1String(p), args); + if (make.waitForStarted()) + break; + } + + if (make.state() != QProcess::Running) { + exitCode = 255; + std_err += "make: "; + std_err += make.errorString().toLocal8Bit(); + return false; + } + + make.closeWriteChannel(); + bool ok = make.waitForFinished(channelMode == QProcess::ForwardedChannels ? -1 : 60000); + if (!ok) + make.terminate(); + exitCode = make.exitCode(); + std_out += make.readAllStandardOutput(); + std_err += make.readAllStandardError(); + + return ok; + } + + bool QExternalTestPrivate::commonSetup(const QByteArray &body) + { + clear(); + + if (!createTemporaryDirectory()) + return false; + if (!createProjectFile()) + return false; + if (!prepareSourceCode(body)) + return false; + if (!runQmake()) + return false; + return true; + } + + bool QExternalTestPrivate::tryCompile(const QByteArray &body) + { + if (!commonSetup(body)) + return false; + + // compile + failedStage = QExternalTest::CompilationStage; + std_out += "\n### --- stdout from make (compilation) --- ###\n"; + std_err += "\n### --- stderr from make (compilation) --- ###\n"; + return runMake(Compile); + } + + bool QExternalTestPrivate::tryLink(const QByteArray &body) + { + if (!tryCompile(body) || exitCode != 0) + return false; + + // link + failedStage = QExternalTest::LinkStage; + std_out += "\n### --- stdout from make (linking) --- ###\n"; + std_err += "\n### --- stderr from make (linking) --- ###\n"; + return runMake(Link); + } + + bool QExternalTestPrivate::tryRun(const QByteArray &body) + { + if (!tryLink(body) || exitCode != 0) + return false; + + // run + failedStage = QExternalTest::RunStage; + std_out += "\n### --- stdout from process --- ###\n"; + std_err += "\n### --- stderr from process --- ###\n"; + return runMake(Run); + } +} +QT_END_NAMESPACE diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.h b/tests/auto/corelib/tools/qsharedpointer/externaltests.h new file mode 100644 index 0000000000..e07ba31928 --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QTEST_EXTERNAL_TESTS_H +#define QTEST_EXTERNAL_TESTS_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace QTest { + class QExternalTestPrivate; + class QExternalTest + { + public: + QExternalTest(); + ~QExternalTest(); + + enum Stage { + FileStage, + QmakeStage, + CompilationStage, + LinkStage, + RunStage + }; + + enum QtModule { + QtCore = 0x0001, + QtGui = 0x0002, + QtNetwork = 0x0004, + QtXml = 0x0008, + QtXmlPatterns=0x0010, + QtOpenGL = 0x0020, + QtSql = 0x0040, + QtSvg = 0x0080, + QtScript = 0x0100, + QtTest = 0x0200, + QtDBus = 0x0400, + QtWebKit = 0x0800, + Phonon = 0x1000 // odd man out + }; + Q_DECLARE_FLAGS(QtModules, QtModule) + + enum ApplicationType { + AutoApplication, + Applicationless, + QCoreApplication, + QApplicationTty, + QApplicationGuiClient, + QApplicationGuiServer + }; + + QList qmakeSettings() const; + void setQmakeSettings(const QList &settings); + + QtModules qtModules() const; + void setQtModules(QtModules modules); + + ApplicationType applicationType() const; + void setApplicationType(ApplicationType type); + + QStringList extraProgramSources() const; + void setExtraProgramSources(const QStringList &list); + + QByteArray programHeader() const; + void setProgramHeader(const QByteArray &header); + + // execution: + bool tryCompile(const QByteArray &body); + bool tryLink(const QByteArray &body); + bool tryRun(const QByteArray &body); + bool tryCompileFail(const QByteArray &body); + bool tryLinkFail(const QByteArray &body); + bool tryRunFail(const QByteArray &body); + + Stage failedStage() const; + int exitCode() const; + QByteArray fullProgramSource() const; + QByteArray standardOutput() const; + QByteArray standardError() const; + + QString errorReport() const; + + private: + QExternalTestPrivate * const d; + }; + + Q_DECLARE_OPERATORS_FOR_FLAGS(QExternalTest::QtModules) +} +QT_END_NAMESPACE + +#endif diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.pri b/tests/auto/corelib/tools/qsharedpointer/externaltests.pri new file mode 100644 index 0000000000..c8a36765ea --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.pri @@ -0,0 +1,8 @@ +SOURCES += $$PWD/externaltests.cpp +HEADERS += $$PWD/externaltests.h +cleanedQMAKESPEC = $$replace(QMAKESPEC, \\\\, /) +!symbian:DEFINES += DEFAULT_MAKESPEC=\\\"$$cleanedQMAKESPEC\\\" + +embedded:DEFINES += QTEST_NO_RTTI QTEST_CROSS_COMPILED +wince*:DEFINES += QTEST_CROSS_COMPILED QTEST_NO_RTTI +symbian: DEFINES += QTEST_CROSS_COMPILED diff --git a/tests/auto/corelib/tools/qsharedpointer/forwarddeclaration.cpp b/tests/auto/corelib/tools/qsharedpointer/forwarddeclaration.cpp new file mode 100644 index 0000000000..f6ee9ad02a --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/forwarddeclaration.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define QT_SHAREDPOINTER_TRACK_POINTERS +#include "qsharedpointer.h" + +class ForwardDeclared; +ForwardDeclared *forwardPointer(); + +void externalForwardDeclaration() +{ + struct Wrapper { QSharedPointer pointer; }; +} + diff --git a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp new file mode 100644 index 0000000000..5ff8893b81 --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "forwarddeclared.h" + +ForwardDeclared *forwardPointer() +{ + return new ForwardDeclared; +} + +int forwardDeclaredDestructorRunCount; +ForwardDeclared::~ForwardDeclared() +{ + ++forwardDeclaredDestructorRunCount; +} diff --git a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h new file mode 100644 index 0000000000..6afc293dde --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORWARDDECLARED_H +#define FORWARDDECLARED_H + +extern int forwardDeclaredDestructorRunCount; +class ForwardDeclared +{ +public: + ~ForwardDeclared(); +}; + +ForwardDeclared *forwardPointer(); + +#endif // FORWARDDECLARED_H diff --git a/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro b/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro new file mode 100644 index 0000000000..014006e782 --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro @@ -0,0 +1,15 @@ +load(qttest_p4) + +SOURCES += tst_qsharedpointer.cpp \ + forwarddeclaration.cpp \ + forwarddeclared.cpp \ + wrapper.cpp + +HEADERS += forwarddeclared.h \ + wrapper.h + +QT = core +!symbian:DEFINES += SRCDIR=\\\"$$PWD/\\\" + +include(externaltests.pri) +CONFIG += parallel_test diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp new file mode 100644 index 0000000000..27d2d4d24a --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -0,0 +1,1922 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define QT_SHAREDPOINTER_TRACK_POINTERS +#include "qsharedpointer.h" +#include +#include +#include +#include +#include + +#include "externaltests.h" +#include "wrapper.h" + +#include +#include + +QT_BEGIN_NAMESPACE +namespace QtSharedPointer { + Q_CORE_EXPORT void internalSafetyCheckCleanCheck(); +} +QT_END_NAMESPACE + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +class tst_QSharedPointer: public QObject +{ + Q_OBJECT + +private slots: + void basics_data(); + void basics(); + void operators(); + void swap(); + void forwardDeclaration1(); + void forwardDeclaration2(); + void memoryManagement(); + void downCast(); + void functionCallDownCast(); + void upCast(); + void qobjectWeakManagement(); + void noSharedPointerFromWeakQObject(); + void weakQObjectFromSharedPointer(); + void objectCast(); + void differentPointers(); + void virtualBaseDifferentPointers(); +#ifndef QTEST_NO_RTTI + void dynamicCast(); + void dynamicCastDifferentPointers(); + void dynamicCastVirtualBase(); + void dynamicCastFailure(); +#endif + void constCorrectness(); + void customDeleter(); + void creating(); + void creatingQObject(); + void mixTrackingPointerCode(); + void reentrancyWhileDestructing(); + + void threadStressTest_data(); + void threadStressTest(); + void map(); + void hash(); + void validConstructs(); + void invalidConstructs_data(); + void invalidConstructs(); + +public slots: + void cleanup() { check(); } + +public: + inline void check() + { +#ifdef QT_BUILD_INTERNAL + QtSharedPointer::internalSafetyCheckCleanCheck(); +#endif + } +}; + +template +class RefCountHack: public Base +{ +public: + using Base::d; +}; +template static inline +QtSharedPointer::ExternalRefCountData *refCountData(const Base &b) +{ return static_cast *>(&b)->d; } + +class Data +{ +public: + static int destructorCounter; + static int generationCounter; + int generation; + + Data() : generation(++generationCounter) + { } + + virtual ~Data() + { + if (generation <= 0) + qFatal("tst_qsharedpointer: Double deletion!"); + generation = 0; + ++destructorCounter; + } + + void doDelete() + { + delete this; + } + + bool alsoDelete() + { + doDelete(); + return true; + } + + virtual void virtualDelete() + { + delete this; + } + + virtual int classLevel() { return 1; } +}; +int Data::generationCounter = 0; +int Data::destructorCounter = 0; + +void tst_QSharedPointer::basics_data() +{ + QTest::addColumn("isNull"); + QTest::newRow("null") << true; + QTest::newRow("non-null") << false; +} + +void tst_QSharedPointer::basics() +{ + { + QSharedPointer ptr; + QWeakPointer weakref; + + QCOMPARE(sizeof(ptr), 2*sizeof(void*)); + QCOMPARE(sizeof(weakref), 2*sizeof(void*)); + } + + QFETCH(bool, isNull); + Data *aData = 0; + if (!isNull) + aData = new Data; + Data *otherData = new Data; + QSharedPointer ptr(aData); + + { + // basic self tests + QCOMPARE(ptr.isNull(), isNull); + QCOMPARE(bool(ptr), !isNull); + QCOMPARE(!ptr, isNull); + + QCOMPARE(ptr.data(), aData); + QCOMPARE(ptr.operator->(), aData); + Data &dataReference = *ptr; + QCOMPARE(&dataReference, aData); + + QVERIFY(ptr == aData); + QVERIFY(!(ptr != aData)); + QVERIFY(aData == ptr); + QVERIFY(!(aData != ptr)); + + QVERIFY(ptr != otherData); + QVERIFY(otherData != ptr); + QVERIFY(! (ptr == otherData)); + QVERIFY(! (otherData == ptr)); + } + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref == 1); + + { + // create another object: + QSharedPointer otherCopy(otherData); + QVERIFY(ptr != otherCopy); + QVERIFY(otherCopy != ptr); + QVERIFY(! (ptr == otherCopy)); + QVERIFY(! (otherCopy == ptr)); + + // otherData is deleted here + } + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref == 1); + + { + // create a copy: + QSharedPointer copy(ptr); + QVERIFY(copy == ptr); + QVERIFY(ptr == copy); + QVERIFY(! (copy != ptr)); + QVERIFY(! (ptr != copy)); + QCOMPARE(copy, ptr); + QCOMPARE(ptr, copy); + + QCOMPARE(copy.isNull(), isNull); + QCOMPARE(copy.data(), aData); + QVERIFY(copy == aData); + } + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref == 1); + + { + // create a weak reference: + QWeakPointer weak(ptr); + QCOMPARE(weak.isNull(), isNull); + QCOMPARE(!weak, isNull); + QCOMPARE(bool(weak), !isNull); + + QVERIFY(ptr == weak); + QVERIFY(weak == ptr); + QVERIFY(! (ptr != weak)); + QVERIFY(! (weak != ptr)); + + // create another reference: + QWeakPointer weak2(weak); + QCOMPARE(weak2.isNull(), isNull); + QCOMPARE(!weak2, isNull); + QCOMPARE(bool(weak2), !isNull); + + QVERIFY(weak2 == weak); + QVERIFY(weak == weak2); + QVERIFY(! (weak2 != weak)); + QVERIFY(! (weak != weak2)); + + // create a strong reference back: + QSharedPointer strong(weak); + QVERIFY(strong == weak); + QVERIFY(strong == ptr); + QCOMPARE(strong.data(), aData); + } + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref == 1); + + // aData is deleted here +} + +void tst_QSharedPointer::operators() +{ + QSharedPointer p1; + QSharedPointer p2(new char); + qptrdiff diff = p2.data() - p1.data(); + QVERIFY(p1.data() != p2.data()); + QVERIFY(diff != 0); + + // operator- + QCOMPARE(p2 - p1.data(), diff); + QCOMPARE(p2.data() - p1, diff); + QCOMPARE(p2 - p1, diff); + QCOMPARE(p1 - p2, -diff); + QCOMPARE(p1 - p1, qptrdiff(0)); + QCOMPARE(p2 - p2, qptrdiff(0)); + + // operator< + QVERIFY(p1 < p2.data()); + QVERIFY(p1.data() < p2); + QVERIFY(p1 < p2); + QVERIFY(!(p2 < p1)); + QVERIFY(!(p2 < p2)); + QVERIFY(!(p1 < p1)); + + // qHash + QCOMPARE(qHash(p1), qHash(p1.data())); + QCOMPARE(qHash(p2), qHash(p2.data())); +} + +void tst_QSharedPointer::swap() +{ + QSharedPointer p1, p2(new int(42)), control = p2; + QVERIFY(p1 != control); + QVERIFY(p1.isNull()); + QVERIFY(p2 == control); + QVERIFY(!p2.isNull()); + QVERIFY(*p2 == 42); + + p1.swap(p2); + QVERIFY(p1 == control); + QVERIFY(!p1.isNull()); + QVERIFY(p2 != control); + QVERIFY(p2.isNull()); + QVERIFY(*p1 == 42); + + p1.swap(p2); + QVERIFY(p1 != control); + QVERIFY(p1.isNull()); + QVERIFY(p2 == control); + QVERIFY(!p2.isNull()); + QVERIFY(*p2 == 42); + + qSwap(p1, p2); + QVERIFY(p1 == control); + QVERIFY(!p1.isNull()); + QVERIFY(p2 != control); + QVERIFY(p2.isNull()); + QVERIFY(*p1 == 42); +} + +class ForwardDeclared; +ForwardDeclared *forwardPointer(); +void externalForwardDeclaration(); +extern int forwardDeclaredDestructorRunCount; + +void tst_QSharedPointer::forwardDeclaration1() +{ +#if defined(Q_CC_SUN) || defined(Q_CC_WINSCW) || defined(Q_CC_RVCT) + QSKIP("This type of forward declaration is not valid with this compiler", SkipAll); +#else + externalForwardDeclaration(); + + struct Wrapper { QSharedPointer pointer; }; + + forwardDeclaredDestructorRunCount = 0; + { + Wrapper w; + w.pointer = QSharedPointer(forwardPointer()); + QVERIFY(!w.pointer.isNull()); + } + QCOMPARE(forwardDeclaredDestructorRunCount, 1); +#endif +} + +#include "forwarddeclared.h" + +void tst_QSharedPointer::forwardDeclaration2() +{ + forwardDeclaredDestructorRunCount = 0; + { + struct Wrapper { QSharedPointer pointer; }; + Wrapper w1, w2; + w1.pointer = QSharedPointer(forwardPointer()); + QVERIFY(!w1.pointer.isNull()); + } + QCOMPARE(forwardDeclaredDestructorRunCount, 1); +} + +void tst_QSharedPointer::memoryManagement() +{ + int generation = Data::generationCounter + 1; + int destructorCounter = Data::destructorCounter; + + QSharedPointer ptr = QSharedPointer(new Data); + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + ptr = ptr; + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + { + QSharedPointer copy = ptr; + QCOMPARE(ptr->generation, generation); + QCOMPARE(copy->generation, generation); + + // copy goes out of scope, ptr continues + } + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + { + QWeakPointer weak = ptr; + weak = ptr; + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + weak = weak; + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + QSharedPointer strong = weak; + QCOMPARE(ptr->generation, generation); + QCOMPARE(strong->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + // both weak and strong go out of scope + } + QCOMPARE(ptr->generation, generation); + QCOMPARE(Data::destructorCounter, destructorCounter); + QCOMPARE(Data::generationCounter, generation); + + QWeakPointer weak = ptr; + ptr = QSharedPointer(); + + // destructor must have been called + QCOMPARE(Data::destructorCounter, destructorCounter + 1); + QVERIFY(ptr.isNull()); + QVERIFY(weak.isNull()); + + // if we create a strong pointer from the weak, it must still be null + ptr = weak; + QVERIFY(ptr.isNull()); + QVERIFY(ptr == 0); + QCOMPARE(ptr.data(), (Data*)0); +} + +class DerivedData: public Data +{ +public: + static int derivedDestructorCounter; + int moreData; + DerivedData() : moreData(0) { } + ~DerivedData() { ++derivedDestructorCounter; } + + virtual void virtualDelete() + { + delete this; + } + + virtual int classLevel() { return 2; } +}; +int DerivedData::derivedDestructorCounter = 0; + +class Stuffing +{ +public: + char buffer[16]; + Stuffing() { for (uint i = 0; i < sizeof buffer; ++i) buffer[i] = 16 - i; } + virtual ~Stuffing() { } +}; + +class DiffPtrDerivedData: public Stuffing, public Data +{ +public: + virtual int classLevel() { return 3; } +}; + +class VirtualDerived: virtual public Data +{ +public: + int moreData; + + VirtualDerived() : moreData(0xc0ffee) { } + virtual int classLevel() { return 4; } +}; + +void tst_QSharedPointer::downCast() +{ + { + QSharedPointer ptr = QSharedPointer(new DerivedData); + QSharedPointer baseptr = qSharedPointerCast(ptr); + QSharedPointer other; + + QVERIFY(ptr == baseptr); + QVERIFY(baseptr == ptr); + QVERIFY(! (ptr != baseptr)); + QVERIFY(! (baseptr != ptr)); + + QVERIFY(ptr != other); + QVERIFY(other != ptr); + QVERIFY(! (ptr == other)); + QVERIFY(! (other == ptr)); + } + + { + QSharedPointer ptr = QSharedPointer(new DerivedData); + QSharedPointer baseptr = ptr; + } + + int destructorCount; + destructorCount = DerivedData::derivedDestructorCounter; + { + QSharedPointer baseptr; + { + QSharedPointer ptr = QSharedPointer(new DerivedData); + baseptr = ptr; + QVERIFY(baseptr == ptr); + } + } + QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); + + destructorCount = DerivedData::derivedDestructorCounter; + { + QSharedPointer ptr = QSharedPointer(new DerivedData); + QWeakPointer baseptr = ptr; + QVERIFY(baseptr == ptr); + + ptr = QSharedPointer(); + QVERIFY(baseptr.isNull()); + } + QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); + + destructorCount = DerivedData::derivedDestructorCounter; + { + QSharedPointer ptr = QSharedPointer(new DerivedData); + QWeakPointer weakptr(ptr); + + QSharedPointer baseptr = weakptr; + QVERIFY(baseptr == ptr); + QWeakPointer baseweakptr = weakptr; + QVERIFY(baseweakptr == ptr); + } + QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); +} + +void functionDataByValue(QSharedPointer p) { Q_UNUSED(p); }; +void functionDataByRef(const QSharedPointer &p) { Q_UNUSED(p); }; +void tst_QSharedPointer::functionCallDownCast() +{ + QSharedPointer p(new DerivedData()); + functionDataByValue(p); + functionDataByRef(p); +} + +void tst_QSharedPointer::upCast() +{ + QSharedPointer baseptr = QSharedPointer(new DerivedData); + + { + QSharedPointer derivedptr = qSharedPointerCast(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QWeakPointer derivedptr = qWeakPointerCast(baseptr); + QVERIFY(baseptr == derivedptr); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QWeakPointer weakptr = baseptr; + QSharedPointer derivedptr = qSharedPointerCast(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QSharedPointer derivedptr = baseptr.staticCast(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); +} + +class OtherObject: public QObject +{ + Q_OBJECT +}; + +void tst_QSharedPointer::qobjectWeakManagement() +{ + { + QWeakPointer weak; + weak = QWeakPointer(); + QVERIFY(weak.isNull()); + QVERIFY(!weak.data()); + } + + { + QObject *obj = new QObject; + QWeakPointer weak(obj); + QVERIFY(!weak.isNull()); + QVERIFY(weak.data() == obj); + + // now delete + delete obj; + QVERIFY(weak.isNull()); + } + check(); + + { + // same, bit with operator= + QObject *obj = new QObject; + QWeakPointer weak; + weak = obj; + QVERIFY(!weak.isNull()); + QVERIFY(weak.data() == obj); + + // now delete + delete obj; + QVERIFY(weak.isNull()); + } + check(); + + { + // delete triggered by parent + QObject *obj, *parent; + parent = new QObject; + obj = new QObject(parent); + QWeakPointer weak(obj); + + // now delete the parent + delete parent; + QVERIFY(weak.isNull()); + } + check(); + + { + // same as above, but set the parent after QWeakPointer is created + QObject *obj, *parent; + obj = new QObject; + QWeakPointer weak(obj); + + parent = new QObject; + obj->setParent(parent); + + // now delete the parent + delete parent; + QVERIFY(weak.isNull()); + } + check(); + + { + // with two QWeakPointers + QObject *obj = new QObject; + QWeakPointer weak(obj); + + { + QWeakPointer weak2(obj); + QVERIFY(!weak2.isNull()); + QVERIFY(weak == weak2); + } + QVERIFY(!weak.isNull()); + + delete obj; + QVERIFY(weak.isNull()); + } + check(); + + { + // same, but delete the pointer while two QWeakPointers exist + QObject *obj = new QObject; + QWeakPointer weak(obj); + + { + QWeakPointer weak2(obj); + QVERIFY(!weak2.isNull()); + + delete obj; + QVERIFY(weak.isNull()); + QVERIFY(weak2.isNull()); + } + QVERIFY(weak.isNull()); + } + check(); +} + +void tst_QSharedPointer::noSharedPointerFromWeakQObject() +{ + // you're not allowed to create a QSharedPointer from an unmanaged QObject + QObject obj; + QWeakPointer weak(&obj); + + QSharedPointer strong = weak.toStrongRef(); + QVERIFY(strong.isNull()); + + // if something went wrong, we'll probably crash here +} + +void tst_QSharedPointer::weakQObjectFromSharedPointer() +{ + // this is the inverse of the above: you're allowed to create a QWeakPointer + // from a managed QObject + QSharedPointer shared(new QObject); + QWeakPointer weak = shared.data(); + QVERIFY(!weak.isNull()); + + // delete: + shared.clear(); + QVERIFY(weak.isNull()); +} + +void tst_QSharedPointer::objectCast() +{ + { + OtherObject *data = new OtherObject; + QSharedPointer baseptr = QSharedPointer(data); + QVERIFY(baseptr == data); + QVERIFY(data == baseptr); + + // perform object cast + QSharedPointer ptr = qSharedPointerObjectCast(baseptr); + QVERIFY(!ptr.isNull()); + QCOMPARE(ptr.data(), data); + QVERIFY(ptr == data); + + // again: + ptr = baseptr.objectCast(); + QVERIFY(ptr == data); + + // again: + ptr = qobject_cast(baseptr); + QVERIFY(ptr == data); + + // again: + ptr = qobject_cast >(baseptr); + QVERIFY(ptr == data); + } + check(); + + { + const OtherObject *data = new OtherObject; + QSharedPointer baseptr = QSharedPointer(data); + QVERIFY(baseptr == data); + QVERIFY(data == baseptr); + + // perform object cast + QSharedPointer ptr = qSharedPointerObjectCast(baseptr); + QVERIFY(!ptr.isNull()); + QCOMPARE(ptr.data(), data); + QVERIFY(ptr == data); + + // again: + ptr = baseptr.objectCast(); + QVERIFY(ptr == data); + + // again: + ptr = qobject_cast(baseptr); + QVERIFY(ptr == data); + + // again: + ptr = qobject_cast >(baseptr); + QVERIFY(ptr == data); + } + check(); + + { + OtherObject *data = new OtherObject; + QPointer qptr = data; + QSharedPointer ptr = QSharedPointer(data); + QWeakPointer weakptr = ptr; + + { + // perform object cast + QSharedPointer otherptr = qSharedPointerObjectCast(weakptr); + QVERIFY(otherptr == ptr); + + // again: + otherptr = qobject_cast(weakptr); + QVERIFY(otherptr == ptr); + + // again: + otherptr = qobject_cast >(weakptr); + QVERIFY(otherptr == ptr); + } + + // drop the reference: + ptr.clear(); + QVERIFY(ptr.isNull()); + QVERIFY(qptr.isNull()); + QVERIFY(weakptr.toStrongRef().isNull()); + + // verify that the object casts fail without crash + QSharedPointer otherptr = qSharedPointerObjectCast(weakptr); + QVERIFY(otherptr.isNull()); + + // again: + otherptr = qobject_cast(weakptr); + QVERIFY(otherptr.isNull()); + + // again: + otherptr = qobject_cast >(weakptr); + QVERIFY(otherptr.isNull()); + } + check(); +} + +void tst_QSharedPointer::differentPointers() +{ + { + DiffPtrDerivedData *aData = new DiffPtrDerivedData; + Data *aBase = aData; + + // ensure that this compiler isn't broken + if (*reinterpret_cast(&aData) == *reinterpret_cast(&aBase)) + qFatal("Something went very wrong -- we couldn't create two different pointers to the same object"); + if (aData != aBase) + QSKIP("Broken compiler", SkipAll); + if (aBase != aData) + QSKIP("Broken compiler", SkipAll); + + QSharedPointer ptr = QSharedPointer(aData); + QSharedPointer baseptr = qSharedPointerCast(ptr); + qDebug("naked: orig: %p; base: %p (%s) -- QSharedPointer: orig: %p; base %p (%s) -- result: %s", + aData, aBase, aData == aBase ? "equal" : "not equal", + ptr.data(), baseptr.data(), ptr.data() == baseptr.data() ? "equal" : "not equal", + baseptr.data() == aData ? "equal" : "not equal"); + + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(baseptr.data() == ptr.data()); + QVERIFY(ptr == baseptr); + QVERIFY(baseptr == ptr); + + QVERIFY(ptr.data() == aBase); + QVERIFY(aBase == ptr.data()); + QVERIFY(ptr.data() == aData); + QVERIFY(aData == ptr.data()); + + QVERIFY(ptr == aBase); + QVERIFY(aBase == ptr); + QVERIFY(ptr == aData); + QVERIFY(aData == ptr); + + QVERIFY(baseptr.data() == aBase); + QVERIFY(aBase == baseptr.data()); + QVERIFY(baseptr == aBase); + QVERIFY(aBase == baseptr); + + QVERIFY(baseptr.data() == aData); + QVERIFY(aData == baseptr.data()); + +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(baseptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(aData == baseptr); + } + check(); + + { + DiffPtrDerivedData *aData = new DiffPtrDerivedData; + Data *aBase = aData; + QVERIFY(aData == aBase); + QVERIFY(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); + + QSharedPointer baseptr = QSharedPointer(aData); + QSharedPointer ptr = qSharedPointerCast(baseptr); + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(baseptr == aData); + } + check(); + + { + DiffPtrDerivedData *aData = new DiffPtrDerivedData; + Data *aBase = aData; + QVERIFY(aData == aBase); + QVERIFY(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); + + QSharedPointer ptr = QSharedPointer(aData); + QSharedPointer baseptr = ptr; + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); + QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(baseptr == aData); + QVERIFY(baseptr == aBase); + } + check(); +} + +void tst_QSharedPointer::virtualBaseDifferentPointers() +{ + { + VirtualDerived *aData = new VirtualDerived; + Data *aBase = aData; + QVERIFY(aData == aBase); + QVERIFY(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); + + QSharedPointer ptr = QSharedPointer(aData); + QSharedPointer baseptr = qSharedPointerCast(ptr); + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); + QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(baseptr == aData); + QVERIFY(baseptr == aBase); + } + check(); + + { + VirtualDerived *aData = new VirtualDerived; + Data *aBase = aData; + QVERIFY(aData == aBase); + QVERIFY(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); + + QSharedPointer ptr = QSharedPointer(aData); + QSharedPointer baseptr = ptr; + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); + QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif + QVERIFY(baseptr == aData); + QVERIFY(baseptr == aBase); + } + check(); +} + +#ifndef QTEST_NO_RTTI +void tst_QSharedPointer::dynamicCast() +{ + DerivedData *aData = new DerivedData; + QSharedPointer baseptr = QSharedPointer(aData); + + { + QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QWeakPointer weakptr = baseptr; + QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QSharedPointer derivedptr = baseptr.dynamicCast(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); +} + +void tst_QSharedPointer::dynamicCastDifferentPointers() +{ + // DiffPtrDerivedData derives from both Data and Stuffing + DiffPtrDerivedData *aData = new DiffPtrDerivedData; + QSharedPointer baseptr = QSharedPointer(aData); + + { + QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QWeakPointer weakptr = baseptr; + QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QSharedPointer derivedptr = baseptr.dynamicCast(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + Stuffing *nakedptr = dynamic_cast(baseptr.data()); + QVERIFY(nakedptr); + + QSharedPointer otherbaseptr = qSharedPointerDynamicCast(baseptr); + QVERIFY(!otherbaseptr.isNull()); + QVERIFY(otherbaseptr == nakedptr); + QCOMPARE(otherbaseptr.data(), nakedptr); + QCOMPARE(static_cast(otherbaseptr.data()), aData); + } +} + +void tst_QSharedPointer::dynamicCastVirtualBase() +{ + VirtualDerived *aData = new VirtualDerived; + QSharedPointer baseptr = QSharedPointer(aData); + + { + QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QWeakPointer weakptr = baseptr; + QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QSharedPointer derivedptr = baseptr.dynamicCast(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); +} + +void tst_QSharedPointer::dynamicCastFailure() +{ + QSharedPointer baseptr = QSharedPointer(new Data); + QVERIFY(dynamic_cast(baseptr.data()) == 0); + + { + QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); + QVERIFY(derivedptr.isNull()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); + + { + QSharedPointer derivedptr = baseptr.dynamicCast(); + QVERIFY(derivedptr.isNull()); + } + QCOMPARE(int(refCountData(baseptr)->weakref), 1); + QCOMPARE(int(refCountData(baseptr)->strongref), 1); +} +#endif + +void tst_QSharedPointer::constCorrectness() +{ + { + QSharedPointer ptr = QSharedPointer(new Data); + QSharedPointer cptr(ptr); + QSharedPointer vptr(ptr); + cptr = ptr; + vptr = ptr; + + ptr = qSharedPointerConstCast(cptr); + ptr = qSharedPointerConstCast(vptr); + ptr = cptr.constCast(); + ptr = vptr.constCast(); + +#if !defined(Q_CC_HPACC) && !defined(QT_ARCH_PARISC) + // the aCC series 3 compiler we have on the PA-RISC + // machine crashes compiling this code + + QSharedPointer cvptr(ptr); + QSharedPointer cvptr2(cptr); + QSharedPointer cvptr3(vptr); + cvptr = ptr; + cvptr2 = cptr; + cvptr3 = vptr; + ptr = qSharedPointerConstCast(cvptr); + ptr = cvptr.constCast(); +#endif + } + check(); + + { + Data *aData = new Data; + QSharedPointer ptr = QSharedPointer(aData); + const QSharedPointer cptr = ptr; + + ptr = cptr; + QSharedPointer other = qSharedPointerCast(cptr); + +#ifndef QT_NO_DYNAMIC_CAST + other = qSharedPointerDynamicCast(cptr); +#endif + + QCOMPARE(cptr.data(), aData); + QCOMPARE(cptr.operator->(), aData); + } + check(); +} + +static int customDeleterFnCallCount; +void customDeleterFn(Data *ptr) +{ + ++customDeleterFnCallCount; + delete ptr; +} + +static int refcount; + +template +struct CustomDeleter +{ + CustomDeleter() { ++refcount; } + CustomDeleter(const CustomDeleter &) { ++refcount; } + ~CustomDeleter() { --refcount; } + inline void operator()(T *ptr) + { + delete ptr; + ++callCount; + } + static int callCount; +}; +template int CustomDeleter::callCount = 0; + +void tst_QSharedPointer::customDeleter() +{ + { + QSharedPointer ptr(new Data, &Data::doDelete); + QSharedPointer ptr2(new Data, &Data::alsoDelete); + QSharedPointer ptr3(new Data, &Data::virtualDelete); + } + check(); + { + QSharedPointer ptr(new DerivedData, &Data::doDelete); + QSharedPointer ptr2(new DerivedData, &Data::alsoDelete); + QSharedPointer ptr3(new DerivedData, &Data::virtualDelete); + } + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); + ptr.data(); + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); + QCOMPARE(customDeleterFnCallCount, 0); + ptr.clear(); + QCOMPARE(customDeleterFnCallCount, 1); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); + QCOMPARE(customDeleterFnCallCount, 0); + ptr = QSharedPointer(new Data); + QCOMPARE(customDeleterFnCallCount, 1); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); + ptr.data(); + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); + ptr.data(); + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer other; + { + QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); + other = ptr; + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + customDeleterFnCallCount = 0; + { + QSharedPointer other; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); + other = ptr; + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 0); + } + QCOMPARE(customDeleterFnCallCount, 1); + check(); + + refcount = 0; + CustomDeleter dataDeleter; + dataDeleter.callCount = 0; + { + QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); + ptr.data(); + QCOMPARE(dataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 1); + QCOMPARE(refcount, 1); + check(); + + dataDeleter.callCount = 0; + { + QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); + QSharedPointer other = ptr; + other.clear(); + QCOMPARE(dataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 1); + QCOMPARE(refcount, 1); + check(); + + dataDeleter.callCount = 0; + { + QSharedPointer other; + { + QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); + other = ptr; + QCOMPARE(dataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 1); + QCOMPARE(refcount, 1); + check(); + + dataDeleter.callCount = 0; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, dataDeleter); + ptr.data(); + QCOMPARE(dataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 1); + QCOMPARE(refcount, 1); + check(); + + CustomDeleter derivedDataDeleter; + derivedDataDeleter.callCount = 0; + dataDeleter.callCount = 0; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, derivedDataDeleter); + ptr.data(); + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 1); + QCOMPARE(refcount, 2); + check(); + + derivedDataDeleter.callCount = 0; + dataDeleter.callCount = 0; + { + QSharedPointer other; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, dataDeleter); + other = ptr; + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 1); + QCOMPARE(derivedDataDeleter.callCount, 0); + QCOMPARE(refcount, 2); + check(); + + derivedDataDeleter.callCount = 0; + dataDeleter.callCount = 0; + { + QSharedPointer other; + { + QSharedPointer ptr = QSharedPointer(new DerivedData, derivedDataDeleter); + other = ptr; + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 0); + } + QCOMPARE(dataDeleter.callCount, 0); + QCOMPARE(derivedDataDeleter.callCount, 1); + QCOMPARE(refcount, 2); + check(); +} + +void customQObjectDeleterFn(QObject *obj) +{ + ++customDeleterFnCallCount; + delete obj; +} + +void tst_QSharedPointer::creating() +{ + Data::generationCounter = Data::destructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QVERIFY(ptr.data()); + QCOMPARE(Data::generationCounter, 1); + QCOMPARE(ptr->generation, 1); + QCOMPARE(Data::destructorCounter, 0); + + QCOMPARE(ptr->classLevel(), 1); + + ptr.clear(); + QCOMPARE(Data::destructorCounter, 1); + } + check(); + + Data::generationCounter = Data::destructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QWeakPointer weakptr = ptr; + QtSharedPointer::ExternalRefCountData *d = refCountData(ptr); + + ptr.clear(); + QVERIFY(ptr.isNull()); + QCOMPARE(Data::destructorCounter, 1); + + // valgrind will complain here if something happened to the pointer + QVERIFY(d->weakref == 1); + QVERIFY(d->strongref == 0); + } + check(); + + Data::generationCounter = Data::destructorCounter = 0; + DerivedData::derivedDestructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 2); + QCOMPARE(ptr.staticCast()->moreData, 0); + ptr.clear(); + + QCOMPARE(Data::destructorCounter, 1); + QCOMPARE(DerivedData::derivedDestructorCounter, 1); + } + check(); + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 3); + QCOMPARE(ptr.staticCast()->buffer[7]+0, 16-7); + QCOMPARE(ptr.staticCast()->buffer[3]+0, 16-3); + QCOMPARE(ptr.staticCast()->buffer[0]+0, 16); + } + check(); + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 4); + QCOMPARE(ptr->moreData, 0xc0ffee); + + QSharedPointer baseptr = ptr; + QCOMPARE(baseptr->classLevel(), 4); + } + check(); +} + +void tst_QSharedPointer::creatingQObject() +{ + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->metaObject(), &QObject::staticMetaObject); + + QPointer qptr = ptr.data(); + ptr.clear(); + + QVERIFY(qptr.isNull()); + } + check(); + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->metaObject(), &OtherObject::staticMetaObject); + } + check(); +} + +void tst_QSharedPointer::mixTrackingPointerCode() +{ + { + // pointer created with tracking + // deleted in code without tracking + QSharedPointer ptr = QSharedPointer(new int(42)); + Wrapper w(ptr); + ptr.clear(); + } + check(); + + { + // pointer created without tracking + // deleted in code with tracking + Wrapper w = Wrapper::create(); + w.ptr.clear(); + } +} + +class ThreadData +{ + QAtomicInt * volatile ptr; +public: + ThreadData(QAtomicInt *p) : ptr(p) { } + ~ThreadData() { ++ptr; } + void ref() + { + // if we're called after the destructor, we'll crash + ptr->ref(); + } +}; + +class StrongThread: public QThread +{ +protected: + void run() + { + usleep(rand() % 2000); + ptr->ref(); + ptr.clear(); + } +public: + QSharedPointer ptr; +}; + +class WeakThread: public QThread +{ +protected: + void run() + { + usleep(rand() % 2000); + QSharedPointer ptr = weak; + if (ptr) + ptr->ref(); + ptr.clear(); + } +public: + QWeakPointer weak; +}; + +void tst_QSharedPointer::threadStressTest_data() +{ + QTest::addColumn("strongThreadCount"); + QTest::addColumn("weakThreadCount"); + + QTest::newRow("0+0") << 0 << 0; + QTest::newRow("1+0") << 1 << 0; + QTest::newRow("2+0") << 2 << 0; + QTest::newRow("10+0") << 10 << 0; + + QTest::newRow("0+1") << 0 << 1; + QTest::newRow("1+1") << 1 << 1; + + QTest::newRow("2+10") << 2 << 10; +#ifndef Q_OS_WINCE + // Windows CE cannot run this many threads + QTest::newRow("5+10") << 5 << 10; + QTest::newRow("5+30") << 5 << 30; + + QTest::newRow("100+100") << 100 << 100; +#endif +} + +void tst_QSharedPointer::threadStressTest() +{ + QFETCH(int, strongThreadCount); + QFETCH(int, weakThreadCount); + + int guard1[128]; + QAtomicInt counter; + int guard2[128]; + + memset(guard1, 0, sizeof guard1); + memset(guard2, 0, sizeof guard2); + + for (int r = 0; r < 5; ++r) { + QVector allThreads(6 * qMax(strongThreadCount, weakThreadCount) + 3, 0); + QSharedPointer base = QSharedPointer(new ThreadData(&counter)); + counter = 0; + + // set the pointers + for (int i = 0; i < strongThreadCount; ++i) { + StrongThread *t = new StrongThread; + t->ptr = base; + allThreads[2 * i] = t; + } + for (int i = 0; i < weakThreadCount; ++i) { + WeakThread *t = new WeakThread; + t->weak = base; + allThreads[6 * i + 3] = t; + } + + base.clear(); + +#ifdef Q_OS_WINCE + srand(QDateTime::currentDateTime().toTime_t()); +#else + srand(time(NULL)); +#endif + // start threads + for (int i = 0; i < allThreads.count(); ++i) + if (allThreads[i]) allThreads[i]->start(); + + // wait for them to finish + for (int i = 0; i < allThreads.count(); ++i) + if (allThreads[i]) allThreads[i]->wait(); + qDeleteAll(allThreads); + + // ensure the guards aren't touched + for (uint i = 0; i < sizeof guard1 / sizeof guard1[0]; ++i) + QVERIFY(!guard1[i]); + for (uint i = 0; i < sizeof guard2 / sizeof guard2[0]; ++i) + QVERIFY(!guard2[i]); + + // verify that the count is the right range + int minValue = strongThreadCount; + int maxValue = strongThreadCount + weakThreadCount; + QVERIFY(counter >= minValue); + QVERIFY(counter <= maxValue); + } +} + +template +void hashAndMapTest() +{ + typedef typename Container::key_type Key; + typedef typename Container::mapped_type Value; + + Container c; + QVERIFY(c.isEmpty()); + + Key k0; + c.insert(k0, Value(0)); + QVERIFY(!c.isEmpty()); + + typename Container::iterator it; + it = c.find(k0); + QVERIFY(it != c.end()); + it = c.find(Key()); + QVERIFY(it != c.end()); + it = c.find(Key(0)); + QVERIFY(it != c.end()); + + Key k1(new typename Key::value_type(42)); + it = c.find(k1); + QVERIFY(it == c.end()); + + c.insert(k1, Value(42)); + it = c.find(k1); + QVERIFY(it != c.end()); + QVERIFY(it != c.find(Key())); + + if (Ordered) { + QVERIFY(k0 < k1); + + it = c.begin(); + QCOMPARE(it.key(), k0); + QCOMPARE(it.value(), Value(0)); + + ++it; + QCOMPARE(it.key(), k1); + QCOMPARE(it.value(), Value(42)); + + ++it; + QVERIFY(it == c.end()); + } + + c.insertMulti(k1, Value(47)); + it = c.find(k1); + QVERIFY(it != c.end()); + QCOMPARE(it.key(), k1); + ++it; + QVERIFY(it != c.end()); + QCOMPARE(it.key(), k1); + ++it; + QVERIFY(it == c.end()); +} + +void tst_QSharedPointer::map() +{ + hashAndMapTest, int>, true>(); +} + +void tst_QSharedPointer::hash() +{ + hashAndMapTest, int>, false>(); +} + +void tst_QSharedPointer::validConstructs() +{ + { + Data *aData = new Data; + QSharedPointer ptr1 = QSharedPointer(aData); + + ptr1 = ptr1; // valid + + QSharedPointer ptr2(ptr1); + + ptr1 = ptr2; + ptr2 = ptr1; + + ptr1 = QSharedPointer(); + ptr1 = ptr2; + } +} + +typedef bool (QTest::QExternalTest:: * TestFunction)(const QByteArray &body); +Q_DECLARE_METATYPE(TestFunction) +void tst_QSharedPointer::invalidConstructs_data() +{ + QTest::addColumn("testFunction"); + QTest::addColumn("code"); + QTest::newRow("sanity-checking") << &QTest::QExternalTest::tryCompile << ""; + + // QSharedPointer is not allowed + QTest::newRow("void") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr;"; + + // implicit initialization + QTest::newRow("implicit-initialization1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr = new Data;"; + QTest::newRow("implicit-initialization2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr;" + "ptr = new Data;"; + QTest::newRow("implicit-initialization3") + << &QTest::QExternalTest::tryCompileFail + << "QWeakPointer ptr = new Data;"; + QTest::newRow("implicit-initialization4") + << &QTest::QExternalTest::tryCompileFail + << "QWeakPointer ptr;" + "ptr = new Data;"; + + // use of forward-declared class + QTest::newRow("forward-declaration") + << &QTest::QExternalTest::tryRun + << "forwardDeclaredDestructorRunCount = 0;\n" + "{ QSharedPointer ptr = QSharedPointer(forwardPointer()); }\n" + "exit(forwardDeclaredDestructorRunCount);"; + QTest::newRow("creating-forward-declaration") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer::create();"; + + // upcast without cast operator: + QTest::newRow("upcast1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new DerivedData);\n" + "QSharedPointer ptr(baseptr);"; + QTest::newRow("upcast2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new DerivedData);\n" + "QSharedPointer ptr;\n" + "ptr = baseptr;"; + + // dropping of const + QTest::newRow("const-dropping1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new Data);\n" + "QSharedPointer ptr(baseptr);"; + QTest::newRow("const-dropping2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new Data);\n" + "QSharedPointer ptr;" + "ptr = baseptr;"; + QTest::newRow("const-dropping-static-cast") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new Data);\n" + "qSharedPointerCast(baseptr);"; +#ifndef QTEST_NO_RTTI + QTest::newRow("const-dropping-dynamic-cast") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new Data);\n" + "qSharedPointerDynamicCast(baseptr);"; +#endif + QTest::newRow("const-dropping-object-cast1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new QObject);\n" + "qSharedPointerObjectCast(baseptr);"; + QTest::newRow("const-dropping-object-cast2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new QObject);\n" + "qobject_cast(baseptr);"; + + // arithmethics through automatic cast operators + QTest::newRow("arithmethic1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer a;" + "QSharedPointer b;\n" + "if (a == b) return;"; + QTest::newRow("arithmethic2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer a;" + "QSharedPointer b;\n" + "if (a + b) return;"; + + // two objects with the same pointer + QTest::newRow("same-pointer") + << &QTest::QExternalTest::tryRunFail + << "Data *aData = new Data;\n" + "QSharedPointer ptr1 = QSharedPointer(aData);\n" + "QSharedPointer ptr2 = QSharedPointer(aData);\n"; + + // re-creation: + QTest::newRow("re-creation") + << &QTest::QExternalTest::tryRunFail + << "Data *aData = new Data;\n" + "QSharedPointer ptr1 = QSharedPointer(aData);" + "ptr1 = QSharedPointer(aData);"; + + // any type of cast for unrelated types: + // (we have no reinterpret_cast) + QTest::newRow("invalid-cast1") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr1;\n" + "QSharedPointer ptr2 = qSharedPointerCast(ptr1);"; +#ifndef QTEST_NO_RTTI + QTest::newRow("invalid-cast2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr1;\n" + "QSharedPointer ptr2 = qSharedPointerDynamicCast(ptr1);"; +#endif + QTest::newRow("invalid-cast3") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr1;\n" + "QSharedPointer ptr2 = qSharedPointerConstCast(ptr1);"; + QTest::newRow("invalid-cast4") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer ptr1;\n" + "QSharedPointer ptr2 = qSharedPointerObjectCast(ptr1);"; + + QTest::newRow("weak-pointer-from-regular-pointer") + << &QTest::QExternalTest::tryCompileFail + << "Data *ptr = 0;\n" + "QWeakPointer weakptr(ptr);\n"; + + QTest::newRow("shared-pointer-from-unmanaged-qobject") + << &QTest::QExternalTest::tryRunFail + << "QObject *ptr = new QObject;\n" + "QWeakPointer weak = ptr;\n" // this makes the object unmanaged + "QSharedPointer shared(ptr);\n"; + + QTest::newRow("shared-pointer-implicit-from-uninitialized") + << &QTest::QExternalTest::tryCompileFail + << "Data *ptr = 0;\n" + "QSharedPointer weakptr = Qt::Uninitialized;\n"; +} + +void tst_QSharedPointer::invalidConstructs() +{ +#ifdef Q_CC_MINGW + QSKIP("The maintainer of QSharedPointer: 'We don't know what the problem is so skip the tests.'", SkipAll); +#endif +#ifdef QTEST_CROSS_COMPILED + QSKIP("This test does not work on cross compiled systems", SkipAll); +#endif + + QTest::QExternalTest test; + test.setQtModules(QTest::QExternalTest::QtCore); + test.setExtraProgramSources(QStringList() << SRCDIR "forwarddeclared.cpp"); + test.setProgramHeader( + "#define QT_SHAREDPOINTER_TRACK_POINTERS\n" + "#define QT_DEBUG\n" + "#include \n" + "#include \n" + "\n" + "struct Data { int i; };\n" + "struct DerivedData: public Data { int j; };\n" + "\n" + "extern int forwardDeclaredDestructorRunCount;\n" + "class ForwardDeclared;\n" + "ForwardDeclared *forwardPointer();\n" + ); + + QFETCH(QString, code); + static bool sane = true; + if (code.isEmpty()) { + static const char snippet[] = "QSharedPointer baseptr; QSharedPointer ptr;"; + if (!test.tryCompile("") + || !test.tryRun("") + || !test.tryRunFail("exit(1);") + || !test.tryCompile(snippet) + || !test.tryLink(snippet) + || !test.tryRun(snippet)) { + sane = false; + qWarning("Sanity checking failed\nCode:\n%s\n", + qPrintable(test.errorReport())); + } + } + if (!sane) + QFAIL("External testing failed sanity checking, cannot proceed"); + + QFETCH(TestFunction, testFunction); + + QByteArray body = code.toLatin1(); + + bool result = (test.*testFunction)(body); + if (qgetenv("QTEST_EXTERNAL_DEBUG").toInt() > 0) { + qDebug("External test output:"); +#ifdef Q_CC_MSVC + // MSVC prints errors to stdout + printf("%s\n", test.standardOutput().constData()); +#endif + printf("%s\n", test.standardError().constData()); + } + if (!result) { + qWarning("External code testing failed\nCode:\n%s\n", body.constData()); + QFAIL("Fail"); + } +} + +namespace QTBUG11730 { + struct IB + { + virtual ~IB() {} + }; + + struct IA + { + virtual QSharedPointer getB() = 0; + }; + + struct B: public IB + { + IA *m_a; + B(IA *a_a) :m_a(a_a) + { } + ~B() + { + QSharedPointer b = m_a->getB(); + } + }; + + struct A: public IA + { + QSharedPointer b; + + virtual QSharedPointer getB() + { + return b; + } + + A() + { + b = QSharedPointer(new B(this)); + } + + ~A() + { + b.clear(); + } + }; +} + +void tst_QSharedPointer::reentrancyWhileDestructing() +{ + // this bug is about recursing back into QSharedPointer::clear() + // from inside it + // that is, the destructor of the object being deleted recurses + // into the same QSharedPointer object. + // First reported as QTBUG-11730 + QTBUG11730::A obj; +} + + +QTEST_MAIN(tst_QSharedPointer) + +#include "tst_qsharedpointer.moc" diff --git a/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp b/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp new file mode 100644 index 0000000000..018fc1c97b --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef QT_SHAREDPOINTER_TRACK_POINTERS +# undef QT_SHAREDPOINTER_TRACK_POINTERS +#endif +#include +#include "wrapper.h" + +Wrapper::Wrapper(const QSharedPointer &value) + : ptr(value) +{ +} + +Wrapper::~Wrapper() +{ +} + +Wrapper Wrapper::create() +{ + return Wrapper(QSharedPointer(new int(-47))); +} diff --git a/tests/auto/corelib/tools/qsharedpointer/wrapper.h b/tests/auto/corelib/tools/qsharedpointer/wrapper.h new file mode 100644 index 0000000000..b25510f76d --- /dev/null +++ b/tests/auto/corelib/tools/qsharedpointer/wrapper.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef WRAPPER_H +#define WRAPPER_H + +QT_BEGIN_NAMESPACE +template class QSharedPointer; +QT_END_NAMESPACE + +class Wrapper +{ +public: + QSharedPointer ptr; + Wrapper(const QSharedPointer &); + ~Wrapper(); + + static Wrapper create(); +}; + +#endif // WRAPPER_H -- cgit v1.2.3