| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtTest/QtTest> |
| #include <QtCore/QScopedPointer> |
| |
| /*! |
| \class tst_QScopedPointer |
| \internal |
| \since 4.6 |
| \brief Tests class QScopedPointer. |
| |
| */ |
| class tst_QScopedPointer : public QObject |
| { |
| Q_OBJECT |
| |
| private Q_SLOTS: |
| void defaultConstructor(); |
| void dataOnDefaultConstructed(); |
| void useSubClassInConstructor(); |
| void dataOnValue(); |
| void dataSignature(); |
| void reset(); |
| void dereferenceOperator(); |
| void dereferenceOperatorSignature(); |
| void pointerOperator(); |
| void pointerOperatorSignature(); |
| void negationOperator(); |
| void negationOperatorSignature(); |
| void operatorBool(); |
| void operatorBoolSignature(); |
| void isNull(); |
| void isNullSignature(); |
| void objectSize(); |
| void comparison(); |
| void array(); |
| // TODO instanciate on const object |
| }; |
| |
| void tst_QScopedPointer::defaultConstructor() |
| { |
| /* Check that the members, one, is correctly initialized. */ |
| QScopedPointer<int> p; |
| QCOMPARE(p.data(), static_cast<int *>(0)); |
| QCOMPARE(p.get(), static_cast<int *>(0)); |
| } |
| |
| void tst_QScopedPointer::dataOnDefaultConstructed() |
| { |
| QScopedPointer<int> p; |
| |
| QCOMPARE(p.data(), static_cast<int *>(0)); |
| QCOMPARE(p.get(), static_cast<int *>(0)); |
| } |
| |
| class MyClass |
| { |
| }; |
| |
| class MySubClass : public MyClass |
| { |
| }; |
| |
| void tst_QScopedPointer::useSubClassInConstructor() |
| { |
| /* Use a syntax which users typically would do. */ |
| QScopedPointer<MyClass> p(new MySubClass()); |
| } |
| |
| void tst_QScopedPointer::dataOnValue() |
| { |
| int *const rawPointer = new int(5); |
| QScopedPointer<int> p(rawPointer); |
| |
| QCOMPARE(p.data(), rawPointer); |
| } |
| |
| void tst_QScopedPointer::dataSignature() |
| { |
| const QScopedPointer<int> p; |
| /* data() should be const. */ |
| p.data(); |
| } |
| |
| void tst_QScopedPointer::reset() |
| { |
| /* Call reset() on a default constructed value. */ |
| { |
| QScopedPointer<int> p; |
| p.reset(); |
| QCOMPARE(p.data(), static_cast<int *>(0)); |
| QCOMPARE(p.get(), static_cast<int *>(0)); |
| } |
| |
| /* Call reset() on an active value. */ |
| { |
| QScopedPointer<int> p(new int(3)); |
| p.reset(); |
| QCOMPARE(p.data(), static_cast<int *>(0)); |
| QCOMPARE(p.get(), static_cast<int *>(0)); |
| } |
| |
| /* Call reset() with a value, on an active value. */ |
| { |
| QScopedPointer<int> p(new int(3)); |
| |
| int *const value = new int(9); |
| p.reset(value); |
| QCOMPARE(*p.data(), 9); |
| QCOMPARE(*p.get(), 9); |
| } |
| |
| /* Call reset() with a value, on default constructed value. */ |
| { |
| QScopedPointer<int> p; |
| |
| int *const value = new int(9); |
| p.reset(value); |
| QCOMPARE(*p.data(), 9); |
| QCOMPARE(*p.get(), 9); |
| } |
| } |
| |
| class AbstractClass |
| { |
| public: |
| virtual ~AbstractClass() |
| { |
| } |
| |
| virtual int member() const = 0; |
| }; |
| |
| class SubClass : public AbstractClass |
| { |
| public: |
| virtual int member() const |
| { |
| return 5; |
| } |
| }; |
| |
| void tst_QScopedPointer::dereferenceOperator() |
| { |
| /* Dereference a basic value. */ |
| { |
| QScopedPointer<int> p(new int(5)); |
| |
| const int value2 = *p; |
| QCOMPARE(value2, 5); |
| } |
| |
| /* Dereference a pointer to an abstract class. This verifies |
| * that the operator returns a reference, when compiling |
| * with MSVC 2005. */ |
| { |
| QScopedPointer<AbstractClass> p(new SubClass()); |
| |
| QCOMPARE((*p).member(), 5); |
| } |
| } |
| |
| void tst_QScopedPointer::dereferenceOperatorSignature() |
| { |
| /* The operator should be const. */ |
| { |
| const QScopedPointer<int> p(new int(5)); |
| *p; |
| } |
| |
| /* A reference should be returned, not a value. */ |
| { |
| const QScopedPointer<int> p(new int(5)); |
| Q_UNUSED(static_cast<int &>(*p)); |
| } |
| |
| /* Instantiated on a const object, the returned object is a const reference. */ |
| { |
| const QScopedPointer<const int> p(new int(5)); |
| Q_UNUSED(static_cast<const int &>(*p)); |
| } |
| } |
| |
| class AnyForm |
| { |
| public: |
| int value; |
| }; |
| |
| void tst_QScopedPointer::pointerOperator() |
| { |
| QScopedPointer<AnyForm> p(new AnyForm()); |
| p->value = 5; |
| |
| QCOMPARE(p->value, 5); |
| } |
| |
| void tst_QScopedPointer::pointerOperatorSignature() |
| { |
| /* The operator should be const. */ |
| const QScopedPointer<AnyForm> p(new AnyForm); |
| p->value = 5; |
| |
| QVERIFY(p->value); |
| } |
| |
| void tst_QScopedPointer::negationOperator() |
| { |
| /* Invoke on default constructed value. */ |
| { |
| QScopedPointer<int> p; |
| QVERIFY(!p); |
| } |
| |
| /* Invoke on a value. */ |
| { |
| QScopedPointer<int> p(new int(2)); |
| QCOMPARE(!p, false); |
| } |
| } |
| |
| void tst_QScopedPointer::negationOperatorSignature() |
| { |
| /* The signature should be const. */ |
| const QScopedPointer<int> p; |
| !p; |
| |
| /* The return value should be bool. */ |
| static_cast<bool>(!p); |
| } |
| |
| void tst_QScopedPointer::operatorBool() |
| { |
| /* Invoke on default constructed value. */ |
| { |
| QScopedPointer<int> p; |
| QCOMPARE(bool(p), false); |
| } |
| |
| /* Invoke on active value. */ |
| { |
| QScopedPointer<int> p(new int(3)); |
| QVERIFY(p); |
| } |
| } |
| |
| void tst_QScopedPointer::operatorBoolSignature() |
| { |
| /* The signature should be const and return bool. */ |
| const QScopedPointer<int> p; |
| |
| (void)static_cast<bool>(p); |
| } |
| |
| void tst_QScopedPointer::isNull() |
| { |
| /* Invoke on default constructed value. */ |
| { |
| QScopedPointer<int> p; |
| QVERIFY(p.isNull()); |
| QVERIFY(p == nullptr); |
| QVERIFY(nullptr == p); |
| } |
| |
| /* Invoke on a set value. */ |
| { |
| QScopedPointer<int> p(new int(69)); |
| QVERIFY(!p.isNull()); |
| QVERIFY(p != nullptr); |
| QVERIFY(nullptr != p); |
| } |
| } |
| |
| void tst_QScopedPointer::isNullSignature() |
| { |
| const QScopedPointer<int> p(new int(69)); |
| |
| /* The signature should be const and return bool. */ |
| static_cast<bool>(p.isNull()); |
| } |
| |
| void tst_QScopedPointer::objectSize() |
| { |
| /* The size of QScopedPointer should be the same as one pointer. */ |
| QCOMPARE(sizeof(QScopedPointer<int>), sizeof(void *)); |
| } |
| |
| struct RefCounted |
| { |
| RefCounted() |
| : ref(0) |
| { |
| instanceCount.ref(); |
| } |
| |
| RefCounted(RefCounted const &) |
| : ref(0) |
| { |
| instanceCount.ref(); |
| } |
| |
| ~RefCounted() |
| { |
| QVERIFY( ref.loadRelaxed() == 0 ); |
| instanceCount.deref(); |
| } |
| |
| RefCounted &operator=(RefCounted const &) |
| { |
| return *this; |
| } |
| |
| QAtomicInt ref; |
| |
| static QAtomicInt instanceCount; |
| }; |
| |
| QAtomicInt RefCounted::instanceCount = 0; |
| |
| template <class A1, class A2, class B> |
| void scopedPointerComparisonTest(const A1 &a1, const A2 &a2, const B &b) |
| { |
| // test equality on equal pointers |
| QVERIFY(a1 == a2); |
| QVERIFY(a2 == a1); |
| |
| // test inequality on equal pointers |
| QVERIFY(!(a1 != a2)); |
| QVERIFY(!(a2 != a1)); |
| |
| // test equality on unequal pointers |
| QVERIFY(!(a1 == b)); |
| QVERIFY(!(a2 == b)); |
| QVERIFY(!(b == a1)); |
| QVERIFY(!(b == a2)); |
| |
| // test inequality on unequal pointers |
| QVERIFY(b != a1); |
| QVERIFY(b != a2); |
| QVERIFY(a1 != b); |
| QVERIFY(a2 != b); |
| } |
| |
| void tst_QScopedPointer::comparison() |
| { |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); |
| |
| { |
| RefCounted *a = new RefCounted; |
| RefCounted *b = new RefCounted; |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); |
| |
| QScopedPointer<RefCounted> pa1(a); |
| QScopedPointer<RefCounted> pa2(a); |
| QScopedPointer<RefCounted> pb(b); |
| |
| scopedPointerComparisonTest(pa1, pa1, pb); |
| scopedPointerComparisonTest(pa2, pa2, pb); |
| scopedPointerComparisonTest(pa1, pa2, pb); |
| |
| pa2.take(); |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); |
| } |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); |
| |
| { |
| RefCounted *a = new RefCounted[42]; |
| RefCounted *b = new RefCounted[43]; |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 ); |
| |
| QScopedArrayPointer<RefCounted> pa1(a); |
| QScopedArrayPointer<RefCounted> pa2(a); |
| QScopedArrayPointer<RefCounted> pb(b); |
| |
| scopedPointerComparisonTest(pa1, pa2, pb); |
| |
| pa2.take(); |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 ); |
| } |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); |
| |
| { |
| // QScopedSharedPointer is an internal helper class -- it is unsupported! |
| |
| RefCounted *a = new RefCounted; |
| RefCounted *b = new RefCounted; |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); |
| |
| QSharedDataPointer<RefCounted> pa1(a); |
| QSharedDataPointer<RefCounted> pa2(a); |
| QSharedDataPointer<RefCounted> pb(b); |
| |
| QCOMPARE( a->ref.loadRelaxed(), 2 ); |
| QCOMPARE( b->ref.loadRelaxed(), 1 ); |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); |
| |
| scopedPointerComparisonTest(pa1, pa2, pb); |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); |
| } |
| |
| QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); |
| } |
| |
| void tst_QScopedPointer::array() |
| { |
| int instCount = RefCounted::instanceCount.loadRelaxed(); |
| { |
| QScopedArrayPointer<RefCounted> array; |
| array.reset(new RefCounted[42]); |
| QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed()); |
| } |
| QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); |
| { |
| QScopedArrayPointer<RefCounted> array(new RefCounted[42]); |
| QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed()); |
| array.reset(new RefCounted[28]); |
| QCOMPARE(instCount + 28, RefCounted::instanceCount.loadRelaxed()); |
| array.reset(0); |
| QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); |
| } |
| QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); |
| } |
| |
| |
| QTEST_MAIN(tst_QScopedPointer) |
| #include "tst_qscopedpointer.moc" |