/**************************************************************************** ** ** Copyright (C) 2009 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/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 swap(); void forwardDeclaration1(); void forwardDeclaration2(); void memoryManagement(); void downCast(); 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 threadStressTest_data(); void threadStressTest(); 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::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 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()); // is 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); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: ptr = qobject_cast<OtherObject *>(baseptr); QVERIFY(ptr == data); // again: ptr = qobject_cast<QSharedPointer<OtherObject> >(baseptr); QVERIFY(ptr == data); #endif } 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); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: ptr = qobject_cast<const OtherObject *>(baseptr); QVERIFY(ptr == data); // again: ptr = qobject_cast<QSharedPointer<const OtherObject> >(baseptr); QVERIFY(ptr == data); #endif } 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()); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: otherptr = qobject_cast<OtherObject *>(weakptr); QVERIFY(otherptr.isNull()); // again: otherptr = qobject_cast<QSharedPointer<OtherObject> >(weakptr); QVERIFY(otherptr.isNull()); #endif } 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); } } 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);"; #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION QTest::newRow("const-dropping-object-cast2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(new QObject);\n" "qobject_cast<QCoreApplication *>(baseptr);"; #endif // 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;"; #if QT_VERSION >= 0x040600 // 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);"; #endif // 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.setDebugMode(true); test.setQtModules(QTest::QExternalTest::QtCore); test.setExtraProgramSources(QStringList() << SRCDIR "forwarddeclared.cpp"); test.setProgramHeader( "#define QT_SHAREDPOINTER_TRACK_POINTERS\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"); } } QTEST_MAIN(tst_QSharedPointer) #include "tst_qsharedpointer.moc"