/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** 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 either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ #define QT_SHAREDPOINTER_TRACK_POINTERS #include "qsharedpointer.h" #include "externaltests.h" #include class tst_QSharedPointer: public QObject { Q_OBJECT private slots: void basics_data(); void basics(); void forwardDeclaration1(); void forwardDeclaration2(); void memoryManagement(); void downCast(); void upCast(); void objectCast(); void differentPointers(); void virtualBaseDifferentPointers(); #ifndef QTEST_NO_RTTI void dynamicCast(); void dynamicCastDifferentPointers(); void dynamicCastVirtualBase(); void dynamicCastFailure(); #endif void customDeleter(); void constCorrectness(); void validConstructs(); void invalidConstructs_data(); void invalidConstructs(); }; 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; } }; int Data::generationCounter = 0; int Data::destructorCounter = 0; void tst_QSharedPointer::basics_data() { QTest::addColumn("isNull"); QTest::newRow("null") << true; QTest::newRow("non-null") << false; } void tst_QSharedPointer::basics() { { QSharedPointer ptr; QWeakPointer weakref; QCOMPARE(sizeof(ptr), 2*sizeof(void*)); QCOMPARE(sizeof(weakref), 2*sizeof(void*)); } QFETCH(bool, isNull); Data *aData = 0; if (!isNull) aData = new Data; Data *otherData = new Data; QSharedPointer ptr(aData); { // basic self tests QCOMPARE(ptr.isNull(), isNull); QCOMPARE(bool(ptr), !isNull); QCOMPARE(!ptr, isNull); QCOMPARE(ptr.data(), aData); QCOMPARE(ptr.operator->(), aData); Data &dataReference = *ptr; QCOMPARE(&dataReference, aData); QVERIFY(ptr == aData); QVERIFY(!(ptr != aData)); QVERIFY(aData == ptr); QVERIFY(!(aData != ptr)); QVERIFY(ptr != otherData); QVERIFY(otherData != ptr); QVERIFY(! (ptr == otherData)); QVERIFY(! (otherData == ptr)); } QVERIFY(!ptr.d || ptr.d->weakref == 1); QVERIFY(!ptr.d || ptr.d->strongref == 1); { // create another object: QSharedPointer otherCopy(otherData); QVERIFY(ptr != otherCopy); QVERIFY(otherCopy != ptr); QVERIFY(! (ptr == otherCopy)); QVERIFY(! (otherCopy == ptr)); // otherData is deleted here } QVERIFY(!ptr.d || ptr.d->weakref == 1); QVERIFY(!ptr.d || ptr.d->strongref == 1); { // create a copy: QSharedPointer copy(ptr); QVERIFY(copy == ptr); QVERIFY(ptr == copy); QVERIFY(! (copy != ptr)); QVERIFY(! (ptr != copy)); QCOMPARE(copy, ptr); QCOMPARE(ptr, copy); QCOMPARE(copy.isNull(), isNull); QCOMPARE(copy.data(), aData); QVERIFY(copy == aData); } QVERIFY(!ptr.d || ptr.d->weakref == 1); QVERIFY(!ptr.d || ptr.d->strongref == 1); { // create a weak reference: QWeakPointer weak(ptr); QCOMPARE(weak.isNull(), isNull); QCOMPARE(!weak, isNull); QCOMPARE(bool(weak), !isNull); QVERIFY(ptr == weak); QVERIFY(weak == ptr); QVERIFY(! (ptr != weak)); QVERIFY(! (weak != ptr)); // create another reference: QWeakPointer weak2(weak); QCOMPARE(weak2.isNull(), isNull); QCOMPARE(!weak2, isNull); QCOMPARE(bool(weak2), !isNull); QVERIFY(weak2 == weak); QVERIFY(weak == weak2); QVERIFY(! (weak2 != weak)); QVERIFY(! (weak != weak2)); // create a strong reference back: QSharedPointer strong(weak); QVERIFY(strong == weak); QVERIFY(strong == ptr); QCOMPARE(strong.data(), aData); } QVERIFY(!ptr.d || ptr.d->weakref == 1); QVERIFY(!ptr.d || ptr.d->strongref == 1); // aData is deleted here } class ForwardDeclared; ForwardDeclared *forwardPointer(); void externalForwardDeclaration(); extern int forwardDeclaredDestructorRunCount; void tst_QSharedPointer::forwardDeclaration1() { externalForwardDeclaration(); struct Wrapper { QSharedPointer pointer; }; forwardDeclaredDestructorRunCount = 0; { Wrapper w; w.pointer = QSharedPointer(forwardPointer()); QVERIFY(!w.pointer.isNull()); } QCOMPARE(forwardDeclaredDestructorRunCount, 1); } #include "forwarddeclared.h" void tst_QSharedPointer::forwardDeclaration2() { forwardDeclaredDestructorRunCount = 0; { struct Wrapper { QSharedPointer pointer; }; Wrapper w1, w2; w1.pointer = QSharedPointer(forwardPointer()); QVERIFY(!w1.pointer.isNull()); } QCOMPARE(forwardDeclaredDestructorRunCount, 1); } void tst_QSharedPointer::memoryManagement() { int generation = Data::generationCounter + 1; int destructorCounter = Data::destructorCounter; QSharedPointer ptr = QSharedPointer(new Data); QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); ptr = ptr; QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); { QSharedPointer copy = ptr; QCOMPARE(ptr->generation, generation); QCOMPARE(copy->generation, generation); // copy goes out of scope, ptr continues } QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); { QWeakPointer weak = ptr; weak = ptr; QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); weak = weak; QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); QSharedPointer strong = weak; QCOMPARE(ptr->generation, generation); QCOMPARE(strong->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); // both weak and strong go out of scope } QCOMPARE(ptr->generation, generation); QCOMPARE(Data::destructorCounter, destructorCounter); QCOMPARE(Data::generationCounter, generation); QWeakPointer weak = ptr; ptr = QSharedPointer(); // destructor must have been called QCOMPARE(Data::destructorCounter, destructorCounter + 1); QVERIFY(ptr.isNull()); QVERIFY(weak.isNull()); // if we create a strong pointer from the weak, it must still be null ptr = weak; QVERIFY(ptr.isNull()); QVERIFY(ptr == 0); QCOMPARE(ptr.data(), (Data*)0); } class DerivedData: public Data { public: static int derivedDestructorCounter; int moreData; DerivedData() : moreData(0) { } ~DerivedData() { ++derivedDestructorCounter; } virtual void virtualDelete() { delete this; } }; int DerivedData::derivedDestructorCounter = 0; class Stuffing { public: char buffer[16]; virtual ~Stuffing() { } }; class DiffPtrDerivedData: public Stuffing, public Data { }; class VirtualDerived: virtual public Data { }; void tst_QSharedPointer::downCast() { { QSharedPointer ptr = QSharedPointer(new DerivedData); QSharedPointer baseptr = qSharedPointerCast(ptr); QSharedPointer other; QVERIFY(ptr == baseptr); QVERIFY(baseptr == ptr); QVERIFY(! (ptr != baseptr)); QVERIFY(! (baseptr != ptr)); QVERIFY(ptr != other); QVERIFY(other != ptr); QVERIFY(! (ptr == other)); QVERIFY(! (other == ptr)); } { QSharedPointer ptr = QSharedPointer(new DerivedData); QSharedPointer baseptr = ptr; } int destructorCount; destructorCount = DerivedData::derivedDestructorCounter; { QSharedPointer baseptr; { QSharedPointer ptr = QSharedPointer(new DerivedData); baseptr = ptr; QVERIFY(baseptr == ptr); } } QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); destructorCount = DerivedData::derivedDestructorCounter; { QSharedPointer ptr = QSharedPointer(new DerivedData); QWeakPointer baseptr = ptr; QVERIFY(baseptr == ptr); ptr = QSharedPointer(); QVERIFY(baseptr.isNull()); } QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); destructorCount = DerivedData::derivedDestructorCounter; { QSharedPointer ptr = QSharedPointer(new DerivedData); QWeakPointer weakptr(ptr); QSharedPointer baseptr = weakptr; QVERIFY(baseptr == ptr); QWeakPointer baseweakptr = weakptr; QVERIFY(baseweakptr == ptr); } QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1); } void tst_QSharedPointer::upCast() { QSharedPointer baseptr = QSharedPointer(new DerivedData); { QSharedPointer derivedptr = qSharedPointerCast(baseptr); QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QWeakPointer derivedptr = qWeakPointerCast(baseptr); QVERIFY(baseptr == derivedptr); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QWeakPointer weakptr = baseptr; QSharedPointer derivedptr = qSharedPointerCast(weakptr); QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QSharedPointer derivedptr = baseptr.staticCast(); QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); } class OtherObject: public QObject { Q_OBJECT }; void tst_QSharedPointer::objectCast() { { OtherObject *data = new OtherObject; QSharedPointer baseptr = QSharedPointer(data); QVERIFY(baseptr == data); QVERIFY(data == baseptr); // perform object cast QSharedPointer ptr = qSharedPointerObjectCast(baseptr); QVERIFY(!ptr.isNull()); QCOMPARE(ptr.data(), data); QVERIFY(ptr == data); // again: ptr = baseptr.objectCast(); QVERIFY(ptr == data); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: ptr = qobject_cast(baseptr); QVERIFY(ptr == data); // again: ptr = qobject_cast >(baseptr); QVERIFY(ptr == data); #endif } { const OtherObject *data = new OtherObject; QSharedPointer baseptr = QSharedPointer(data); QVERIFY(baseptr == data); QVERIFY(data == baseptr); // perform object cast QSharedPointer ptr = qSharedPointerObjectCast(baseptr); QVERIFY(!ptr.isNull()); QCOMPARE(ptr.data(), data); QVERIFY(ptr == data); // again: ptr = baseptr.objectCast(); QVERIFY(ptr == data); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: ptr = qobject_cast(baseptr); QVERIFY(ptr == data); // again: ptr = qobject_cast >(baseptr); QVERIFY(ptr == data); #endif } { OtherObject *data = new OtherObject; QPointer qptr = data; QSharedPointer ptr = QSharedPointer(data); QWeakPointer weakptr = ptr; { // perform object cast QSharedPointer otherptr = qSharedPointerObjectCast(weakptr); QVERIFY(otherptr == ptr); // again: otherptr = qobject_cast(weakptr); QVERIFY(otherptr == ptr); // again: otherptr = qobject_cast >(weakptr); QVERIFY(otherptr == ptr); } // drop the reference: ptr.clear(); QVERIFY(ptr.isNull()); QVERIFY(qptr.isNull()); QVERIFY(weakptr.toStrongRef().isNull()); // verify that the object casts fail without crash QSharedPointer otherptr = qSharedPointerObjectCast(weakptr); QVERIFY(otherptr.isNull()); #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION // again: otherptr = qobject_cast(weakptr); QVERIFY(otherptr.isNull()); // again: otherptr = qobject_cast >(weakptr); QVERIFY(otherptr.isNull()); #endif } } void tst_QSharedPointer::differentPointers() { { DiffPtrDerivedData *aData = new DiffPtrDerivedData; Data *aBase = aData; Q_ASSERT(aData == aBase); Q_ASSERT(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); QSharedPointer ptr = QSharedPointer(aData); QSharedPointer baseptr = qSharedPointerCast(ptr); QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } { DiffPtrDerivedData *aData = new DiffPtrDerivedData; Data *aBase = aData; Q_ASSERT(aData == aBase); Q_ASSERT(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); QSharedPointer baseptr = QSharedPointer(aData); QSharedPointer ptr = qSharedPointerCast(baseptr); QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(baseptr == aData); } { DiffPtrDerivedData *aData = new DiffPtrDerivedData; Data *aBase = aData; Q_ASSERT(aData == aBase); Q_ASSERT(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); QSharedPointer ptr = QSharedPointer(aData); QSharedPointer baseptr = ptr; QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } } void tst_QSharedPointer::virtualBaseDifferentPointers() { { VirtualDerived *aData = new VirtualDerived; Data *aBase = aData; Q_ASSERT(aData == aBase); Q_ASSERT(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); QSharedPointer ptr = QSharedPointer(aData); QSharedPointer baseptr = qSharedPointerCast(ptr); QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } { VirtualDerived *aData = new VirtualDerived; Data *aBase = aData; Q_ASSERT(aData == aBase); Q_ASSERT(*reinterpret_cast(&aData) != *reinterpret_cast(&aBase)); QSharedPointer ptr = QSharedPointer(aData); QSharedPointer baseptr = ptr; QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } } #ifndef QTEST_NO_RTTI void tst_QSharedPointer::dynamicCast() { DerivedData *aData = new DerivedData; QSharedPointer baseptr = QSharedPointer(aData); { QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QWeakPointer weakptr = baseptr; QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QSharedPointer derivedptr = baseptr.dynamicCast(); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); } void tst_QSharedPointer::dynamicCastDifferentPointers() { // DiffPtrDerivedData derives from both Data and Stuffing DiffPtrDerivedData *aData = new DiffPtrDerivedData; QSharedPointer baseptr = QSharedPointer(aData); { QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QWeakPointer weakptr = baseptr; QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QSharedPointer derivedptr = baseptr.dynamicCast(); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { Stuffing *nakedptr = dynamic_cast(baseptr.data()); QVERIFY(nakedptr); QSharedPointer otherbaseptr = qSharedPointerDynamicCast(baseptr); QVERIFY(!otherbaseptr.isNull()); QVERIFY(otherbaseptr == nakedptr); QCOMPARE(otherbaseptr.data(), nakedptr); QCOMPARE(static_cast(otherbaseptr.data()), aData); } } void tst_QSharedPointer::dynamicCastVirtualBase() { VirtualDerived *aData = new VirtualDerived; QSharedPointer baseptr = QSharedPointer(aData); { QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QWeakPointer weakptr = baseptr; QSharedPointer derivedptr = qSharedPointerDynamicCast(weakptr); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QSharedPointer derivedptr = baseptr.dynamicCast(); QVERIFY(baseptr == derivedptr); QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); } void tst_QSharedPointer::dynamicCastFailure() { QSharedPointer baseptr = QSharedPointer(new Data); QVERIFY(dynamic_cast(baseptr.data()) == 0); { QSharedPointer derivedptr = qSharedPointerDynamicCast(baseptr); QVERIFY(derivedptr.isNull()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); { QSharedPointer derivedptr = baseptr.dynamicCast(); QVERIFY(derivedptr.isNull()); } QCOMPARE(int(baseptr.d->weakref), 1); QCOMPARE(int(baseptr.d->strongref), 1); } #endif void tst_QSharedPointer::constCorrectness() { { QSharedPointer ptr = QSharedPointer(new Data); QSharedPointer cptr(ptr); QSharedPointer vptr(ptr); cptr = ptr; vptr = ptr; ptr = qSharedPointerConstCast(cptr); ptr = qSharedPointerConstCast(vptr); ptr = cptr.constCast(); ptr = vptr.constCast(); #if !defined(Q_CC_HPACC) && !defined(QT_ARCH_PARISC) // the aCC series 3 compiler we have on the PA-RISC // machine crashes compiling this code QSharedPointer cvptr(ptr); QSharedPointer cvptr2(cptr); QSharedPointer cvptr3(vptr); cvptr = ptr; cvptr2 = cptr; cvptr3 = vptr; ptr = qSharedPointerConstCast(cvptr); ptr = cvptr.constCast(); #endif } { Data *aData = new Data; QSharedPointer ptr = QSharedPointer(aData); const QSharedPointer cptr = ptr; ptr = cptr; QSharedPointer other = qSharedPointerCast(cptr); other = qSharedPointerDynamicCast(cptr); QCOMPARE(cptr.data(), aData); QCOMPARE(cptr.operator->(), aData); } } static int customDeleterFnCallCount; void customDeleterFn(Data *ptr) { ++customDeleterFnCallCount; delete ptr; } template struct CustomDeleter { inline void operator()(T *ptr) { delete ptr; ++callCount; } static int callCount; }; template int CustomDeleter::callCount = 0; void tst_QSharedPointer::customDeleter() { { QSharedPointer ptr(new Data, &Data::doDelete); QSharedPointer ptr2(new Data, &Data::alsoDelete); QSharedPointer ptr3(new Data, &Data::virtualDelete); } { QSharedPointer ptr(new DerivedData, &Data::doDelete); QSharedPointer ptr2(new DerivedData, &Data::alsoDelete); QSharedPointer ptr3(new DerivedData, &Data::virtualDelete); } customDeleterFnCallCount = 0; { QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); ptr.data(); QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); QCOMPARE(customDeleterFnCallCount, 0); ptr.clear(); QCOMPARE(customDeleterFnCallCount, 1); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); QCOMPARE(customDeleterFnCallCount, 0); ptr = QSharedPointer(new Data); QCOMPARE(customDeleterFnCallCount, 1); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); ptr.data(); QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); ptr.data(); QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer other; { QSharedPointer ptr = QSharedPointer(new Data, customDeleterFn); other = ptr; QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 1); customDeleterFnCallCount = 0; { QSharedPointer other; { QSharedPointer ptr = QSharedPointer(new DerivedData, customDeleterFn); other = ptr; QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 0); } QCOMPARE(customDeleterFnCallCount, 1); CustomDeleter dataDeleter; dataDeleter.callCount = 0; { QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); ptr.data(); QCOMPARE(dataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 1); dataDeleter.callCount = 0; { QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); QSharedPointer other = ptr; other.clear(); QCOMPARE(dataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 1); dataDeleter.callCount = 0; { QSharedPointer other; { QSharedPointer ptr = QSharedPointer(new Data, dataDeleter); other = ptr; QCOMPARE(dataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 1); dataDeleter.callCount = 0; { QSharedPointer ptr = QSharedPointer(new DerivedData, dataDeleter); ptr.data(); QCOMPARE(dataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 1); CustomDeleter derivedDataDeleter; derivedDataDeleter.callCount = 0; dataDeleter.callCount = 0; { QSharedPointer ptr = QSharedPointer(new DerivedData, derivedDataDeleter); ptr.data(); QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 1); derivedDataDeleter.callCount = 0; dataDeleter.callCount = 0; { QSharedPointer other; { QSharedPointer ptr = QSharedPointer(new DerivedData, dataDeleter); other = ptr; QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 1); QCOMPARE(derivedDataDeleter.callCount, 0); derivedDataDeleter.callCount = 0; dataDeleter.callCount = 0; { QSharedPointer other; { QSharedPointer ptr = QSharedPointer(new DerivedData, derivedDataDeleter); other = ptr; QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 0); } QCOMPARE(dataDeleter.callCount, 0); QCOMPARE(derivedDataDeleter.callCount, 1); } void tst_QSharedPointer::validConstructs() { { Data *aData = new Data; QSharedPointer ptr1 = QSharedPointer(aData); ptr1 = ptr1; // valid QSharedPointer ptr2(ptr1); ptr1 = ptr2; ptr2 = ptr1; ptr1 = QSharedPointer(); ptr1 = ptr2; } } typedef bool (QTest::QExternalTest:: * TestFunction)(const QByteArray &body); Q_DECLARE_METATYPE(TestFunction) void tst_QSharedPointer::invalidConstructs_data() { QTest::addColumn("testFunction"); QTest::addColumn("code"); QTest::newRow("sanity-checking") << &QTest::QExternalTest::tryCompile << ""; // QSharedPointer is not allowed QTest::newRow("void") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr;"; // implicit initialization QTest::newRow("implicit-initialization1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr = new Data;"; QTest::newRow("implicit-initialization2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr;" "ptr = new Data;"; QTest::newRow("implicit-initialization3") << &QTest::QExternalTest::tryCompileFail << "QWeakPointer ptr = new Data;"; QTest::newRow("implicit-initialization4") << &QTest::QExternalTest::tryCompileFail << "QWeakPointer ptr;" "ptr = new Data;"; // use of forward-declared class QTest::newRow("forward-declaration") << &QTest::QExternalTest::tryRun << "forwardDeclaredDestructorRunCount = 0;\n" "{ QSharedPointer ptr = QSharedPointer(forwardPointer()); }\n" "exit(forwardDeclaredDestructorRunCount);"; // upcast without cast operator: QTest::newRow("upcast1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new DerivedData);\n" "QSharedPointer ptr(baseptr);"; QTest::newRow("upcast2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new DerivedData);\n" "QSharedPointer ptr;\n" "ptr = baseptr;"; // dropping of const QTest::newRow("const-dropping1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new Data);\n" "QSharedPointer ptr(baseptr);"; QTest::newRow("const-dropping2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new Data);\n" "QSharedPointer ptr;" "ptr = baseptr;"; QTest::newRow("const-dropping-static-cast") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new Data);\n" "qSharedPointerCast(baseptr);"; #ifndef QTEST_NO_RTTI QTest::newRow("const-dropping-dynamic-cast") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new Data);\n" "qSharedPointerDynamicCast(baseptr);"; #endif QTest::newRow("const-dropping-object-cast") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new QObject);\n" "qSharedPointerObjectCast(baseptr);"; // arithmethics through automatic cast operators QTest::newRow("arithmethic1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer a;" "QSharedPointer b;\n" "if (a == b) return;"; QTest::newRow("arithmethic2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer a;" "QSharedPointer b;\n" "if (a + b) return;"; // two objects with the same pointer QTest::newRow("same-pointer") << &QTest::QExternalTest::tryRunFail << "Data *aData = new Data;\n" "QSharedPointer ptr1 = QSharedPointer(aData);\n" "QSharedPointer ptr2 = QSharedPointer(aData);\n"; // re-creation: QTest::newRow("re-creation") << &QTest::QExternalTest::tryRunFail << "Data *aData = new Data;\n" "QSharedPointer ptr1 = QSharedPointer(aData);" "ptr1 = QSharedPointer(aData);"; // any type of cast for unrelated types: // (we have no reinterpret_cast) QTest::newRow("invalid-cast1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr1;\n" "QSharedPointer ptr2 = qSharedPointerCast(ptr1);"; #ifndef QTEST_NO_RTTI QTest::newRow("invalid-cast2") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr1;\n" "QSharedPointer ptr2 = qSharedPointerDynamicCast(ptr1);"; #endif QTest::newRow("invalid-cast3") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr1;\n" "QSharedPointer ptr2 = qSharedPointerConstCast(ptr1);"; QTest::newRow("invalid-cast4") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr1;\n" "QSharedPointer ptr2 = qSharedPointerObjectCast(ptr1);"; } 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 \n" "#include \n" "\n" "struct Data { int i; };\n" "struct DerivedData: public Data { int j; };\n" "\n" "extern int forwardDeclaredDestructorRunCount;\n" "struct ForwardDeclared;\n" "ForwardDeclared *forwardPointer();\n" ); QFETCH(QString, code); static bool sane = true; if (code.isEmpty()) { static const char snippet[] = "QSharedPointer baseptr; QSharedPointer ptr;"; if (!test.tryCompile("") || !test.tryRun("") || !test.tryRunFail("exit(1);") || !test.tryCompile(snippet) || !test.tryLink(snippet) || !test.tryRun(snippet)) { sane = false; qWarning("Sanity checking failed\nCode:\n%s\n", qPrintable(test.errorReport())); } } if (!sane) QFAIL("External testing failed sanity checking, cannot proceed"); QFETCH(TestFunction, testFunction); QByteArray body = code.toLatin1(); bool result = (test.*testFunction)(body); if (qgetenv("QTEST_EXTERNAL_DEBUG").toInt() > 0) { qDebug("External test output:"); 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"