summaryrefslogtreecommitdiffstats
path: root/tests/auto/qsharedpointer
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/qsharedpointer
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/qsharedpointer')
-rw-r--r--tests/auto/qsharedpointer/.gitignore1
-rw-r--r--tests/auto/qsharedpointer/externaltests.cpp743
-rw-r--r--tests/auto/qsharedpointer/externaltests.h133
-rw-r--r--tests/auto/qsharedpointer/externaltests.pri8
-rw-r--r--tests/auto/qsharedpointer/forwarddeclaration.cpp52
-rw-r--r--tests/auto/qsharedpointer/forwarddeclared.cpp53
-rw-r--r--tests/auto/qsharedpointer/forwarddeclared.h54
-rw-r--r--tests/auto/qsharedpointer/qsharedpointer.pro15
-rw-r--r--tests/auto/qsharedpointer/tst_qsharedpointer.cpp1921
-rw-r--r--tests/auto/qsharedpointer/wrapper.cpp60
-rw-r--r--tests/auto/qsharedpointer/wrapper.h58
11 files changed, 3098 insertions, 0 deletions
diff --git a/tests/auto/qsharedpointer/.gitignore b/tests/auto/qsharedpointer/.gitignore
new file mode 100644
index 0000000000..3cd9f1a085
--- /dev/null
+++ b/tests/auto/qsharedpointer/.gitignore
@@ -0,0 +1 @@
+tst_qsharedpointer
diff --git a/tests/auto/qsharedpointer/externaltests.cpp b/tests/auto/qsharedpointer/externaltests.cpp
new file mode 100644
index 0000000000..1ba03dced6
--- /dev/null
+++ b/tests/auto/qsharedpointer/externaltests.cpp
@@ -0,0 +1,743 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "externaltests.h"
+
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QProcess>
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QDateTime>
+
+#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 <fcntl.h>
+# include <unistd.h>
+#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<QByteArray> 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<QByteArray> QExternalTest::qmakeSettings() const
+ {
+ return d->qmakeLines;
+ }
+
+ void QExternalTest::setQmakeSettings(const QList<QByteArray> &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()
+ {
+ Q_ASSERT(!temporaryDir.isEmpty());
+ 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 <QtCore/QtCore>\n";
+ if (qtModules & QExternalTest::QtGui)
+ sourceCode += "#include <QtGui/QtGui>\n";
+ if (qtModules & QExternalTest::QtNetwork)
+ sourceCode += "#include <QtNetwork/QtNetwork>\n";
+ if (qtModules & QExternalTest::QtXml)
+ sourceCode += "#include <QtXml/QtXml>\n";
+ if (qtModules & QExternalTest::QtXmlPatterns)
+ sourceCode += "#include <QtXmlPatterns/QtXmlPatterns>\n";
+ if (qtModules & QExternalTest::QtOpenGL)
+ sourceCode += "#include <QtOpenGL/QtOpenGL>\n";
+ if (qtModules & QExternalTest::QtSql)
+ sourceCode += "#include <QtSql/QtSql>\n";
+ if (qtModules & QExternalTest::Qt3Support)
+ sourceCode += "#include <Qt3Support/Qt3Support>\n";
+ if (qtModules & QExternalTest::QtSvg)
+ sourceCode += "#include <QtSvg/QtSvg>\n";
+ if (qtModules & QExternalTest::QtScript)
+ sourceCode += "#include <QtScript/QtScript>\n";
+ if (qtModules & QExternalTest::QtTest)
+ sourceCode += "#include <QtTest/QtTest>\n";
+ if (qtModules & QExternalTest::QtDBus)
+ sourceCode += "#include <QtDBus/QtDBus>\n";
+ if (qtModules & QExternalTest::QtWebKit)
+ sourceCode += "#include <QtWebKit/QtWebKit>\n";
+ if (qtModules & QExternalTest::Phonon)
+ sourceCode += "#include <Phonon/Phonon>\n";
+ sourceCode +=
+ "#include <stdlib.h>\n"
+ "#include <stddef.h>\n";
+
+ sourceCode +=
+ "\n"
+ "void q_external_test_user_code()\n"
+ "{\n"
+ "#include \"user_code.cpp\"\n"
+ "}\n"
+ "\n"
+ "#ifdef Q_OS_WIN\n"
+ "#include <windows.h>\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()
+ {
+ Q_ASSERT(!temporaryDir.isEmpty());
+
+ 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::Qt3Support)
+ projectFile.write("QT += qt3support\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()
+ {
+ Q_ASSERT(!temporaryDir.isEmpty());
+ 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)
+ {
+ Q_ASSERT(!temporaryDir.isEmpty());
+
+ 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/qsharedpointer/externaltests.h b/tests/auto/qsharedpointer/externaltests.h
new file mode 100644
index 0000000000..ca20cb0c30
--- /dev/null
+++ b/tests/auto/qsharedpointer/externaltests.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QTEST_EXTERNAL_TESTS_H
+#define QTEST_EXTERNAL_TESTS_H
+
+#include <QList>
+#include <QByteArray>
+#include <QStringList>
+
+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,
+ Qt3Support = 0x0080,
+ QtSvg = 0x0100,
+ QtScript = 0x0200,
+ QtTest = 0x0400,
+ QtDBus = 0x0800,
+ QtWebKit = 0x1000,
+ Phonon = 0x2000 // odd man out
+ };
+ Q_DECLARE_FLAGS(QtModules, QtModule)
+
+ enum ApplicationType {
+ AutoApplication,
+ Applicationless,
+ QCoreApplication,
+ QApplicationTty,
+ QApplicationGuiClient,
+ QApplicationGuiServer
+ };
+
+ QList<QByteArray> qmakeSettings() const;
+ void setQmakeSettings(const QList<QByteArray> &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/qsharedpointer/externaltests.pri b/tests/auto/qsharedpointer/externaltests.pri
new file mode 100644
index 0000000000..c8a36765ea
--- /dev/null
+++ b/tests/auto/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/qsharedpointer/forwarddeclaration.cpp b/tests/auto/qsharedpointer/forwarddeclaration.cpp
new file mode 100644
index 0000000000..a522eefc49
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define QT_SHAREDPOINTER_TRACK_POINTERS
+#include "qsharedpointer.h"
+
+class ForwardDeclared;
+ForwardDeclared *forwardPointer();
+
+void externalForwardDeclaration()
+{
+ struct Wrapper { QSharedPointer<ForwardDeclared> pointer; };
+}
+
diff --git a/tests/auto/qsharedpointer/forwarddeclared.cpp b/tests/auto/qsharedpointer/forwarddeclared.cpp
new file mode 100644
index 0000000000..3e29974553
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "forwarddeclared.h"
+
+ForwardDeclared *forwardPointer()
+{
+ return new ForwardDeclared;
+}
+
+int forwardDeclaredDestructorRunCount;
+ForwardDeclared::~ForwardDeclared()
+{
+ ++forwardDeclaredDestructorRunCount;
+}
diff --git a/tests/auto/qsharedpointer/forwarddeclared.h b/tests/auto/qsharedpointer/forwarddeclared.h
new file mode 100644
index 0000000000..908b63bc1c
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qsharedpointer/qsharedpointer.pro b/tests/auto/qsharedpointer/qsharedpointer.pro
new file mode 100644
index 0000000000..014006e782
--- /dev/null
+++ b/tests/auto/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/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp
new file mode 100644
index 0000000000..bb04621b67
--- /dev/null
+++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp
@@ -0,0 +1,1921 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define QT_SHAREDPOINTER_TRACK_POINTERS
+#include "qsharedpointer.h"
+#include <QtTest/QtTest>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QThread>
+#include <QtCore/QVector>
+
+#include "externaltests.h"
+#include "wrapper.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+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 <typename Base>
+class RefCountHack: public Base
+{
+public:
+ using Base::d;
+};
+template<typename Base> static inline
+QtSharedPointer::ExternalRefCountData *refCountData(const Base &b)
+{ return static_cast<const RefCountHack<Base> *>(&b)->d; }
+
+class Data
+{
+public:
+ static int destructorCounter;
+ static int generationCounter;
+ int generation;
+
+ Data() : generation(++generationCounter)
+ { }
+
+ virtual ~Data()
+ {
+ Q_ASSERT_X(generation > 0, "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<bool>("isNull");
+ QTest::newRow("null") << true;
+ QTest::newRow("non-null") << false;
+}
+
+void tst_QSharedPointer::basics()
+{
+ {
+ QSharedPointer<Data> ptr;
+ QWeakPointer<Data> 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<Data> 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<Data> 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<Data> 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<Data> 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<Data> 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<Data> 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<char> p1;
+ QSharedPointer<char> p2(new char);
+ qptrdiff diff = p2.data() - p1.data();
+ Q_ASSERT(p1.data() != p2.data());
+ Q_ASSERT(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<int> 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<ForwardDeclared> pointer; };
+
+ forwardDeclaredDestructorRunCount = 0;
+ {
+ Wrapper w;
+ w.pointer = QSharedPointer<ForwardDeclared>(forwardPointer());
+ QVERIFY(!w.pointer.isNull());
+ }
+ QCOMPARE(forwardDeclaredDestructorRunCount, 1);
+#endif
+}
+
+#include "forwarddeclared.h"
+
+void tst_QSharedPointer::forwardDeclaration2()
+{
+ forwardDeclaredDestructorRunCount = 0;
+ {
+ struct Wrapper { QSharedPointer<ForwardDeclared> pointer; };
+ Wrapper w1, w2;
+ w1.pointer = QSharedPointer<ForwardDeclared>(forwardPointer());
+ QVERIFY(!w1.pointer.isNull());
+ }
+ QCOMPARE(forwardDeclaredDestructorRunCount, 1);
+}
+
+void tst_QSharedPointer::memoryManagement()
+{
+ int generation = Data::generationCounter + 1;
+ int destructorCounter = Data::destructorCounter;
+
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(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<Data> 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<Data> 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<Data> 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<Data> weak = ptr;
+ ptr = QSharedPointer<Data>();
+
+ // 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<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(ptr);
+ QSharedPointer<Data> 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<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QSharedPointer<Data> baseptr = ptr;
+ }
+
+ int destructorCount;
+ destructorCount = DerivedData::derivedDestructorCounter;
+ {
+ QSharedPointer<Data> baseptr;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ baseptr = ptr;
+ QVERIFY(baseptr == ptr);
+ }
+ }
+ QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
+
+ destructorCount = DerivedData::derivedDestructorCounter;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QWeakPointer<Data> baseptr = ptr;
+ QVERIFY(baseptr == ptr);
+
+ ptr = QSharedPointer<DerivedData>();
+ QVERIFY(baseptr.isNull());
+ }
+ QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
+
+ destructorCount = DerivedData::derivedDestructorCounter;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QWeakPointer<DerivedData> weakptr(ptr);
+
+ QSharedPointer<Data> baseptr = weakptr;
+ QVERIFY(baseptr == ptr);
+ QWeakPointer<Data> baseweakptr = weakptr;
+ QVERIFY(baseweakptr == ptr);
+ }
+ QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
+}
+
+void functionDataByValue(QSharedPointer<Data> p) { Q_UNUSED(p); };
+void functionDataByRef(const QSharedPointer<Data> &p) { Q_UNUSED(p); };
+void tst_QSharedPointer::functionCallDownCast()
+{
+ QSharedPointer<DerivedData> p(new DerivedData());
+ functionDataByValue(p);
+ functionDataByRef(p);
+}
+
+void tst_QSharedPointer::upCast()
+{
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = qSharedPointerCast<DerivedData>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QWeakPointer<DerivedData> derivedptr = qWeakPointerCast<DerivedData>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<DerivedData> derivedptr = qSharedPointerCast<DerivedData>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = baseptr.staticCast<DerivedData>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(static_cast<Data *>(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<QObject> weak;
+ weak = QWeakPointer<QObject>();
+ QVERIFY(weak.isNull());
+ QVERIFY(!weak.data());
+ }
+
+ {
+ QObject *obj = new QObject;
+ QWeakPointer<QObject> 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<QObject> 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<QObject> 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<QObject> 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<QObject> weak(obj);
+
+ {
+ QWeakPointer<QObject> 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<QObject> weak(obj);
+
+ {
+ QWeakPointer<QObject> 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<QObject> weak(&obj);
+
+ QSharedPointer<QObject> 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<QObject> shared(new QObject);
+ QWeakPointer<QObject> weak = shared.data();
+ QVERIFY(!weak.isNull());
+
+ // delete:
+ shared.clear();
+ QVERIFY(weak.isNull());
+}
+
+void tst_QSharedPointer::objectCast()
+{
+ {
+ OtherObject *data = new OtherObject;
+ QSharedPointer<QObject> baseptr = QSharedPointer<QObject>(data);
+ QVERIFY(baseptr == data);
+ QVERIFY(data == baseptr);
+
+ // perform object cast
+ QSharedPointer<OtherObject> ptr = qSharedPointerObjectCast<OtherObject>(baseptr);
+ QVERIFY(!ptr.isNull());
+ QCOMPARE(ptr.data(), data);
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = baseptr.objectCast<OtherObject>();
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = qobject_cast<OtherObject *>(baseptr);
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = qobject_cast<QSharedPointer<OtherObject> >(baseptr);
+ QVERIFY(ptr == data);
+ }
+ check();
+
+ {
+ const OtherObject *data = new OtherObject;
+ QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(data);
+ QVERIFY(baseptr == data);
+ QVERIFY(data == baseptr);
+
+ // perform object cast
+ QSharedPointer<const OtherObject> ptr = qSharedPointerObjectCast<const OtherObject>(baseptr);
+ QVERIFY(!ptr.isNull());
+ QCOMPARE(ptr.data(), data);
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = baseptr.objectCast<const OtherObject>();
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = qobject_cast<const OtherObject *>(baseptr);
+ QVERIFY(ptr == data);
+
+ // again:
+ ptr = qobject_cast<QSharedPointer<const OtherObject> >(baseptr);
+ QVERIFY(ptr == data);
+ }
+ check();
+
+ {
+ OtherObject *data = new OtherObject;
+ QPointer<OtherObject> qptr = data;
+ QSharedPointer<OtherObject> ptr = QSharedPointer<OtherObject>(data);
+ QWeakPointer<QObject> weakptr = ptr;
+
+ {
+ // perform object cast
+ QSharedPointer<OtherObject> otherptr = qSharedPointerObjectCast<OtherObject>(weakptr);
+ QVERIFY(otherptr == ptr);
+
+ // again:
+ otherptr = qobject_cast<OtherObject *>(weakptr);
+ QVERIFY(otherptr == ptr);
+
+ // again:
+ otherptr = qobject_cast<QSharedPointer<OtherObject> >(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<OtherObject> otherptr = qSharedPointerObjectCast<OtherObject>(weakptr);
+ QVERIFY(otherptr.isNull());
+
+ // again:
+ otherptr = qobject_cast<OtherObject *>(weakptr);
+ QVERIFY(otherptr.isNull());
+
+ // again:
+ otherptr = qobject_cast<QSharedPointer<OtherObject> >(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<quintptr *>(&aData) == *reinterpret_cast<quintptr *>(&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<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData);
+ QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(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;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
+
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
+ QSharedPointer<DiffPtrDerivedData> ptr = qSharedPointerCast<DiffPtrDerivedData>(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;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
+
+ QSharedPointer<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData);
+ QSharedPointer<Data> 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;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
+
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
+ QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(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;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
+
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
+ QSharedPointer<Data> 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<Data> baseptr = QSharedPointer<Data>(aData);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(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<Data> baseptr = QSharedPointer<Data>(aData);
+
+ {
+ QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QSharedPointer<DiffPtrDerivedData> derivedptr = baseptr.dynamicCast<DiffPtrDerivedData>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ Stuffing *nakedptr = dynamic_cast<Stuffing *>(baseptr.data());
+ QVERIFY(nakedptr);
+
+ QSharedPointer<Stuffing> otherbaseptr = qSharedPointerDynamicCast<Stuffing>(baseptr);
+ QVERIFY(!otherbaseptr.isNull());
+ QVERIFY(otherbaseptr == nakedptr);
+ QCOMPARE(otherbaseptr.data(), nakedptr);
+ QCOMPARE(static_cast<DiffPtrDerivedData*>(otherbaseptr.data()), aData);
+ }
+}
+
+void tst_QSharedPointer::dynamicCastVirtualBase()
+{
+ VirtualDerived *aData = new VirtualDerived;
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
+
+ {
+ QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QSharedPointer<VirtualDerived> derivedptr = baseptr.dynamicCast<VirtualDerived>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+}
+
+void tst_QSharedPointer::dynamicCastFailure()
+{
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(new Data);
+ QVERIFY(dynamic_cast<DerivedData *>(baseptr.data()) == 0);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(baseptr);
+ QVERIFY(derivedptr.isNull());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+
+ {
+ QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>();
+ QVERIFY(derivedptr.isNull());
+ }
+ QCOMPARE(int(refCountData(baseptr)->weakref), 1);
+ QCOMPARE(int(refCountData(baseptr)->strongref), 1);
+}
+#endif
+
+void tst_QSharedPointer::constCorrectness()
+{
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data);
+ QSharedPointer<const Data> cptr(ptr);
+ QSharedPointer<volatile Data> vptr(ptr);
+ cptr = ptr;
+ vptr = ptr;
+
+ ptr = qSharedPointerConstCast<Data>(cptr);
+ ptr = qSharedPointerConstCast<Data>(vptr);
+ ptr = cptr.constCast<Data>();
+ ptr = vptr.constCast<Data>();
+
+#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<const volatile Data> cvptr(ptr);
+ QSharedPointer<const volatile Data> cvptr2(cptr);
+ QSharedPointer<const volatile Data> cvptr3(vptr);
+ cvptr = ptr;
+ cvptr2 = cptr;
+ cvptr3 = vptr;
+ ptr = qSharedPointerConstCast<Data>(cvptr);
+ ptr = cvptr.constCast<Data>();
+#endif
+ }
+ check();
+
+ {
+ Data *aData = new Data;
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(aData);
+ const QSharedPointer<Data> cptr = ptr;
+
+ ptr = cptr;
+ QSharedPointer<Data> other = qSharedPointerCast<Data>(cptr);
+
+#ifndef QT_NO_DYNAMIC_CAST
+ other = qSharedPointerDynamicCast<Data>(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 <typename T>
+struct CustomDeleter
+{
+ CustomDeleter() { ++refcount; }
+ CustomDeleter(const CustomDeleter &) { ++refcount; }
+ ~CustomDeleter() { --refcount; }
+ inline void operator()(T *ptr)
+ {
+ delete ptr;
+ ++callCount;
+ }
+ static int callCount;
+};
+template<typename T> int CustomDeleter<T>::callCount = 0;
+
+void tst_QSharedPointer::customDeleter()
+{
+ {
+ QSharedPointer<Data> ptr(new Data, &Data::doDelete);
+ QSharedPointer<Data> ptr2(new Data, &Data::alsoDelete);
+ QSharedPointer<Data> ptr3(new Data, &Data::virtualDelete);
+ }
+ check();
+ {
+ QSharedPointer<DerivedData> ptr(new DerivedData, &Data::doDelete);
+ QSharedPointer<DerivedData> ptr2(new DerivedData, &Data::alsoDelete);
+ QSharedPointer<DerivedData> ptr3(new DerivedData, &Data::virtualDelete);
+ }
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
+ ptr.data();
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
+ QCOMPARE(customDeleterFnCallCount, 0);
+ ptr.clear();
+ QCOMPARE(customDeleterFnCallCount, 1);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
+ QCOMPARE(customDeleterFnCallCount, 0);
+ ptr = QSharedPointer<Data>(new Data);
+ QCOMPARE(customDeleterFnCallCount, 1);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new DerivedData, customDeleterFn);
+ ptr.data();
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, customDeleterFn);
+ ptr.data();
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> other;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
+ other = ptr;
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ customDeleterFnCallCount = 0;
+ {
+ QSharedPointer<Data> other;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, customDeleterFn);
+ other = ptr;
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 0);
+ }
+ QCOMPARE(customDeleterFnCallCount, 1);
+ check();
+
+ refcount = 0;
+ CustomDeleter<Data> dataDeleter;
+ dataDeleter.callCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, dataDeleter);
+ ptr.data();
+ QCOMPARE(dataDeleter.callCount, 0);
+ }
+ QCOMPARE(dataDeleter.callCount, 1);
+ QCOMPARE(refcount, 1);
+ check();
+
+ dataDeleter.callCount = 0;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, dataDeleter);
+ QSharedPointer<Data> other = ptr;
+ other.clear();
+ QCOMPARE(dataDeleter.callCount, 0);
+ }
+ QCOMPARE(dataDeleter.callCount, 1);
+ QCOMPARE(refcount, 1);
+ check();
+
+ dataDeleter.callCount = 0;
+ {
+ QSharedPointer<Data> other;
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<Data>(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<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, dataDeleter);
+ ptr.data();
+ QCOMPARE(dataDeleter.callCount, 0);
+ }
+ QCOMPARE(dataDeleter.callCount, 1);
+ QCOMPARE(refcount, 1);
+ check();
+
+ CustomDeleter<DerivedData> derivedDataDeleter;
+ derivedDataDeleter.callCount = 0;
+ dataDeleter.callCount = 0;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(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<Data> other;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(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<Data> other;
+ {
+ QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(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<Data> ptr = QSharedPointer<Data>::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<Data> ptr = QSharedPointer<Data>::create();
+ QWeakPointer<Data> 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<Data> ptr = QSharedPointer<DerivedData>::create();
+ QCOMPARE(ptr->classLevel(), 2);
+ QCOMPARE(ptr.staticCast<DerivedData>()->moreData, 0);
+ ptr.clear();
+
+ QCOMPARE(Data::destructorCounter, 1);
+ QCOMPARE(DerivedData::derivedDestructorCounter, 1);
+ }
+ check();
+
+ {
+ QSharedPointer<Data> ptr = QSharedPointer<DiffPtrDerivedData>::create();
+ QCOMPARE(ptr->classLevel(), 3);
+ QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[7]+0, 16-7);
+ QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[3]+0, 16-3);
+ QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[0]+0, 16);
+ }
+ check();
+
+ {
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>::create();
+ QCOMPARE(ptr->classLevel(), 4);
+ QCOMPARE(ptr->moreData, 0xc0ffee);
+
+ QSharedPointer<Data> baseptr = ptr;
+ QCOMPARE(baseptr->classLevel(), 4);
+ }
+ check();
+}
+
+void tst_QSharedPointer::creatingQObject()
+{
+ {
+ QSharedPointer<QObject> ptr = QSharedPointer<QObject>::create();
+ QCOMPARE(ptr->metaObject(), &QObject::staticMetaObject);
+
+ QPointer<QObject> qptr = ptr.data();
+ ptr.clear();
+
+ QVERIFY(qptr.isNull());
+ }
+ check();
+
+ {
+ QSharedPointer<QObject> ptr = QSharedPointer<OtherObject>::create();
+ QCOMPARE(ptr->metaObject(), &OtherObject::staticMetaObject);
+ }
+ check();
+}
+
+void tst_QSharedPointer::mixTrackingPointerCode()
+{
+ {
+ // pointer created with tracking
+ // deleted in code without tracking
+ QSharedPointer<int> ptr = QSharedPointer<int>(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<ThreadData> ptr;
+};
+
+class WeakThread: public QThread
+{
+protected:
+ void run()
+ {
+ usleep(rand() % 2000);
+ QSharedPointer<ThreadData> ptr = weak;
+ if (ptr)
+ ptr->ref();
+ ptr.clear();
+ }
+public:
+ QWeakPointer<ThreadData> weak;
+};
+
+void tst_QSharedPointer::threadStressTest_data()
+{
+ QTest::addColumn<int>("strongThreadCount");
+ QTest::addColumn<int>("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<QThread*> allThreads(6 * qMax(strongThreadCount, weakThreadCount) + 3, 0);
+ QSharedPointer<ThreadData> base = QSharedPointer<ThreadData>(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<typename Container, bool Ordered>
+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) {
+ Q_ASSERT(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<QMap<QSharedPointer<int>, int>, true>();
+}
+
+void tst_QSharedPointer::hash()
+{
+ hashAndMapTest<QHash<QSharedPointer<int>, int>, false>();
+}
+
+void tst_QSharedPointer::validConstructs()
+{
+ {
+ Data *aData = new Data;
+ QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);
+
+ ptr1 = ptr1; // valid
+
+ QSharedPointer<Data> ptr2(ptr1);
+
+ ptr1 = ptr2;
+ ptr2 = ptr1;
+
+ ptr1 = QSharedPointer<Data>();
+ ptr1 = ptr2;
+ }
+}
+
+typedef bool (QTest::QExternalTest:: * TestFunction)(const QByteArray &body);
+Q_DECLARE_METATYPE(TestFunction)
+void tst_QSharedPointer::invalidConstructs_data()
+{
+ QTest::addColumn<TestFunction>("testFunction");
+ QTest::addColumn<QString>("code");
+ QTest::newRow("sanity-checking") << &QTest::QExternalTest::tryCompile << "";
+
+ // QSharedPointer<void> is not allowed
+ QTest::newRow("void") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer<void> ptr;";
+
+ // implicit initialization
+ QTest::newRow("implicit-initialization1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr = new Data;";
+ QTest::newRow("implicit-initialization2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr;"
+ "ptr = new Data;";
+ QTest::newRow("implicit-initialization3")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QWeakPointer<Data> ptr = new Data;";
+ QTest::newRow("implicit-initialization4")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QWeakPointer<Data> ptr;"
+ "ptr = new Data;";
+
+ // use of forward-declared class
+ QTest::newRow("forward-declaration")
+ << &QTest::QExternalTest::tryRun
+ << "forwardDeclaredDestructorRunCount = 0;\n"
+ "{ QSharedPointer<ForwardDeclared> ptr = QSharedPointer<ForwardDeclared>(forwardPointer()); }\n"
+ "exit(forwardDeclaredDestructorRunCount);";
+ QTest::newRow("creating-forward-declaration")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<ForwardDeclared>::create();";
+
+ // upcast without cast operator:
+ QTest::newRow("upcast1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);\n"
+ "QSharedPointer<DerivedData> ptr(baseptr);";
+ QTest::newRow("upcast2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);\n"
+ "QSharedPointer<DerivedData> ptr;\n"
+ "ptr = baseptr;";
+
+ // dropping of const
+ QTest::newRow("const-dropping1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
+ "QSharedPointer<Data> ptr(baseptr);";
+ QTest::newRow("const-dropping2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
+ "QSharedPointer<Data> ptr;"
+ "ptr = baseptr;";
+ QTest::newRow("const-dropping-static-cast")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
+ "qSharedPointerCast<DerivedData>(baseptr);";
+#ifndef QTEST_NO_RTTI
+ QTest::newRow("const-dropping-dynamic-cast")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
+ "qSharedPointerDynamicCast<DerivedData>(baseptr);";
+#endif
+ QTest::newRow("const-dropping-object-cast1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(new QObject);\n"
+ "qSharedPointerObjectCast<QCoreApplication>(baseptr);";
+ QTest::newRow("const-dropping-object-cast2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(new QObject);\n"
+ "qobject_cast<QCoreApplication *>(baseptr);";
+
+ // arithmethics through automatic cast operators
+ QTest::newRow("arithmethic1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<int> a;"
+ "QSharedPointer<Data> b;\n"
+ "if (a == b) return;";
+ QTest::newRow("arithmethic2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<int> a;"
+ "QSharedPointer<Data> 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<Data> ptr1 = QSharedPointer<Data>(aData);\n"
+ "QSharedPointer<Data> ptr2 = QSharedPointer<Data>(aData);\n";
+
+ // re-creation:
+ QTest::newRow("re-creation")
+ << &QTest::QExternalTest::tryRunFail
+ << "Data *aData = new Data;\n"
+ "QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);"
+ "ptr1 = QSharedPointer<Data>(aData);";
+
+ // any type of cast for unrelated types:
+ // (we have no reinterpret_cast)
+ QTest::newRow("invalid-cast1")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr1;\n"
+ "QSharedPointer<int> ptr2 = qSharedPointerCast<int>(ptr1);";
+#ifndef QTEST_NO_RTTI
+ QTest::newRow("invalid-cast2")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr1;\n"
+ "QSharedPointer<int> ptr2 = qSharedPointerDynamicCast<int>(ptr1);";
+#endif
+ QTest::newRow("invalid-cast3")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr1;\n"
+ "QSharedPointer<int> ptr2 = qSharedPointerConstCast<int>(ptr1);";
+ QTest::newRow("invalid-cast4")
+ << &QTest::QExternalTest::tryCompileFail
+ << "QSharedPointer<Data> ptr1;\n"
+ "QSharedPointer<int> ptr2 = qSharedPointerObjectCast<int>(ptr1);";
+
+ QTest::newRow("weak-pointer-from-regular-pointer")
+ << &QTest::QExternalTest::tryCompileFail
+ << "Data *ptr = 0;\n"
+ "QWeakPointer<Data> weakptr(ptr);\n";
+
+ QTest::newRow("shared-pointer-from-unmanaged-qobject")
+ << &QTest::QExternalTest::tryRunFail
+ << "QObject *ptr = new QObject;\n"
+ "QWeakPointer<QObject> weak = ptr;\n" // this makes the object unmanaged
+ "QSharedPointer<QObject> shared(ptr);\n";
+
+ QTest::newRow("shared-pointer-implicit-from-uninitialized")
+ << &QTest::QExternalTest::tryCompileFail
+ << "Data *ptr = 0;\n"
+ "QSharedPointer<Data> 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 <QtCore/qsharedpointer.h>\n"
+ "#include <QtCore/qcoreapplication.h>\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<Data> baseptr; QSharedPointer<DerivedData> 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<IB> getB() = 0;
+ };
+
+ struct B: public IB
+ {
+ IA *m_a;
+ B(IA *a_a) :m_a(a_a)
+ { }
+ ~B()
+ {
+ QSharedPointer<IB> b = m_a->getB();
+ }
+ };
+
+ struct A: public IA
+ {
+ QSharedPointer<IB> b;
+
+ virtual QSharedPointer<IB> getB()
+ {
+ return b;
+ }
+
+ A()
+ {
+ b = QSharedPointer<IB>(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/qsharedpointer/wrapper.cpp b/tests/auto/qsharedpointer/wrapper.cpp
new file mode 100644
index 0000000000..4e14448ef5
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+# undef QT_SHAREDPOINTER_TRACK_POINTERS
+#endif
+#include <QtCore/qsharedpointer.h>
+#include "wrapper.h"
+
+Wrapper::Wrapper(const QSharedPointer<int> &value)
+ : ptr(value)
+{
+}
+
+Wrapper::~Wrapper()
+{
+}
+
+Wrapper Wrapper::create()
+{
+ return Wrapper(QSharedPointer<int>(new int(-47)));
+}
diff --git a/tests/auto/qsharedpointer/wrapper.h b/tests/auto/qsharedpointer/wrapper.h
new file mode 100644
index 0000000000..4202e35c22
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef WRAPPER_H
+#define WRAPPER_H
+
+QT_BEGIN_NAMESPACE
+template <class T> class QSharedPointer;
+QT_END_NAMESPACE
+
+class Wrapper
+{
+public:
+ QSharedPointer<int> ptr;
+ Wrapper(const QSharedPointer<int> &);
+ ~Wrapper();
+
+ static Wrapper create();
+};
+
+#endif // WRAPPER_H