1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include <QPointer>
32#ifndef QT_NO_WIDGETS
33#include <QWidget>
34#endif
35
36class tst_QPointer : public QObject
37{
38 Q_OBJECT
39public:
40 inline tst_QPointer *me() const
41 { return const_cast<tst_QPointer *>(this); }
42
43private slots:
44 void constructors();
45 void destructor();
46 void assignment_operators();
47 void equality_operators();
48 void swap();
49 void isNull();
50 void dereference_operators();
51 void disconnect();
52 void castDuringDestruction();
53 void threadSafety();
54
55 void qvariantCast();
56 void constPointer();
57 void constQPointer();
58};
59
60void tst_QPointer::constructors()
61{
62 QPointer<QObject> p1;
63 QPointer<QObject> p2(this);
64 QPointer<QObject> p3(p2);
65 QCOMPARE(p1, QPointer<QObject>(0));
66 QCOMPARE(p2, QPointer<QObject>(this));
67 QCOMPARE(p3, QPointer<QObject>(this));
68}
69
70void tst_QPointer::destructor()
71{
72 // Make two QPointer's to the same object
73 QObject *object = new QObject;
74 QPointer<QObject> p1 = object;
75 QPointer<QObject> p2 = object;
76 // Check that they point to the correct object
77 QCOMPARE(p1, QPointer<QObject>(object));
78 QCOMPARE(p2, QPointer<QObject>(object));
79 QCOMPARE(p1, p2);
80 // Destroy the guarded object
81 delete object;
82 // Check that both pointers were zeroed
83 QCOMPARE(p1, QPointer<QObject>(0));
84 QCOMPARE(p2, QPointer<QObject>(0));
85 QCOMPARE(p1, p2);
86}
87
88void tst_QPointer::assignment_operators()
89{
90 QPointer<QObject> p1;
91 QPointer<QObject> p2;
92
93 // Test assignment with a QObject-derived object pointer
94 p1 = this;
95 p2 = p1;
96 QCOMPARE(p1, QPointer<QObject>(this));
97 QCOMPARE(p2, QPointer<QObject>(this));
98 QCOMPARE(p1, QPointer<QObject>(p2));
99
100 // Test assignment with a null pointer
101 p1 = 0;
102 p2 = p1;
103 QCOMPARE(p1, QPointer<QObject>(0));
104 QCOMPARE(p2, QPointer<QObject>(0));
105 QCOMPARE(p1, QPointer<QObject>(p2));
106
107 // Test assignment with a real QObject pointer
108 QObject *object = new QObject;
109
110 p1 = object;
111 p2 = p1;
112 QCOMPARE(p1, QPointer<QObject>(object));
113 QCOMPARE(p2, QPointer<QObject>(object));
114 QCOMPARE(p1, QPointer<QObject>(p2));
115
116 // Test assignment with the same pointer that's already guarded
117 p1 = object;
118 p2 = p1;
119 QCOMPARE(p1, QPointer<QObject>(object));
120 QCOMPARE(p2, QPointer<QObject>(object));
121 QCOMPARE(p1, QPointer<QObject>(p2));
122
123 // Cleanup
124 delete object;
125}
126
127void tst_QPointer::equality_operators()
128{
129 QPointer<QObject> p1;
130 QPointer<QObject> p2;
131
132 QVERIFY(p1 == p2);
133
134 QObject *object = 0;
135#ifndef QT_NO_WIDGETS
136 QWidget *widget = 0;
137#endif
138
139 p1 = object;
140 QVERIFY(p1 == p2);
141 QVERIFY(p1 == object);
142 p2 = object;
143 QVERIFY(p2 == p1);
144 QVERIFY(p2 == object);
145
146 p1 = this;
147 QVERIFY(p1 != p2);
148 p2 = p1;
149 QVERIFY(p1 == p2);
150
151 // compare to zero
152 p1 = 0;
153 QVERIFY(p1 == 0);
154 QVERIFY(0 == p1);
155 QVERIFY(p2 != 0);
156 QVERIFY(0 != p2);
157 QVERIFY(p1 == object);
158 QVERIFY(object == p1);
159 QVERIFY(p2 != object);
160 QVERIFY(object != p2);
161#ifndef QT_NO_WIDGETS
162 QVERIFY(p1 == widget);
163 QVERIFY(widget == p1);
164 QVERIFY(p2 != widget);
165 QVERIFY(widget != p2);
166#endif
167}
168
169void tst_QPointer::swap()
170{
171 QPointer<QObject> c1, c2;
172 {
173 QObject o;
174 c1 = &o;
175 QVERIFY(c2.isNull());
176 QCOMPARE(c1.data(), &o);
177 c1.swap(other&: c2);
178 QVERIFY(c1.isNull());
179 QCOMPARE(c2.data(), &o);
180 }
181 QVERIFY(c1.isNull());
182 QVERIFY(c2.isNull());
183}
184
185void tst_QPointer::isNull()
186{
187 QPointer<QObject> p1;
188 QVERIFY(p1.isNull());
189 p1 = this;
190 QVERIFY(!p1.isNull());
191 p1 = 0;
192 QVERIFY(p1.isNull());
193}
194
195void tst_QPointer::dereference_operators()
196{
197 QPointer<tst_QPointer> p1 = this;
198 QPointer<tst_QPointer> p2;
199
200 // operator->() -- only makes sense if not null
201 QObject *object = p1->me();
202 QCOMPARE(object, this);
203
204 // operator*() -- only makes sense if not null
205 QObject &ref = *p1;
206 QCOMPARE(&ref, this);
207
208 // operator T*()
209 QCOMPARE(static_cast<QObject *>(p1), this);
210 QCOMPARE(static_cast<QObject *>(p2), static_cast<QObject *>(0));
211
212 // data()
213 QCOMPARE(p1.data(), this);
214 QCOMPARE(p2.data(), static_cast<QObject *>(0));
215}
216
217void tst_QPointer::disconnect()
218{
219 // Verify that pointer remains guarded when all signals are disconencted.
220 QPointer<QObject> p1 = new QObject;
221 QVERIFY(!p1.isNull());
222 p1->disconnect();
223 QVERIFY(!p1.isNull());
224 delete static_cast<QObject *>(p1);
225 QVERIFY(p1.isNull());
226}
227
228class ChildObject : public QObject
229{
230 QPointer<QObject> guardedPointer;
231
232public:
233 ChildObject(QObject *parent)
234 : QObject(parent), guardedPointer(parent)
235 { }
236 ~ChildObject();
237};
238
239ChildObject::~ChildObject()
240{
241 QCOMPARE(static_cast<QObject *>(guardedPointer), static_cast<QObject *>(0));
242 QCOMPARE(qobject_cast<QObject *>(guardedPointer), static_cast<QObject *>(0));
243}
244
245#ifndef QT_NO_WIDGETS
246class ChildWidget : public QWidget
247{
248 QPointer<QWidget> guardedPointer;
249
250public:
251 ChildWidget(QWidget *parent)
252 : QWidget(parent), guardedPointer(parent)
253 { }
254 ~ChildWidget();
255};
256
257ChildWidget::~ChildWidget()
258{
259 QCOMPARE(static_cast<QWidget *>(guardedPointer), parentWidget());
260 QCOMPARE(qobject_cast<QWidget *>(guardedPointer), parentWidget());
261}
262#endif
263
264class DerivedChild;
265
266class DerivedParent : public QObject
267{
268 Q_OBJECT
269
270 DerivedChild *derivedChild;
271
272public:
273 DerivedParent();
274 ~DerivedParent();
275};
276
277class DerivedChild : public QObject
278{
279 Q_OBJECT
280
281 DerivedParent *parentPointer;
282 QPointer<DerivedParent> guardedParentPointer;
283
284public:
285 DerivedChild(DerivedParent *parent)
286 : QObject(parent), parentPointer(parent), guardedParentPointer(parent)
287 { }
288 ~DerivedChild();
289};
290
291DerivedParent::DerivedParent()
292 : QObject()
293{
294 derivedChild = new DerivedChild(this);
295}
296
297DerivedParent::~DerivedParent()
298{
299 delete derivedChild;
300}
301
302DerivedChild::~DerivedChild()
303{
304 QCOMPARE(static_cast<DerivedParent *>(guardedParentPointer), parentPointer);
305 QCOMPARE(qobject_cast<DerivedParent *>(guardedParentPointer), parentPointer);
306}
307
308void tst_QPointer::castDuringDestruction()
309{
310 {
311 QObject *parentObject = new QObject();
312 (void) new ChildObject(parentObject);
313 delete parentObject;
314 }
315
316#ifndef QT_NO_WIDGETS
317 {
318 QWidget *parentWidget = new QWidget();
319 (void) new ChildWidget(parentWidget);
320 delete parentWidget;
321 }
322#endif
323
324 {
325 delete new DerivedParent();
326 }
327}
328
329class TestRunnable : public QObject, public QRunnable {
330 void run() {
331 QPointer<QObject> obj1 = new QObject;
332 QPointer<QObject> obj2 = new QObject;
333 obj1->moveToThread(thread: thread()); // this is the owner thread
334 obj1->deleteLater(); // the delete will happen in the owner thread
335 obj2->moveToThread(thread: thread()); // this is the owner thread
336 obj2->deleteLater(); // the delete will happen in the owner thread
337 }
338};
339
340void tst_QPointer::threadSafety()
341{
342
343 QThread owner;
344 owner.start();
345
346 QThreadPool pool;
347 for (int i = 0; i < 300; i++) {
348 QPointer<TestRunnable> task = new TestRunnable;
349 task->setAutoDelete(true);
350 task->moveToThread(thread: &owner);
351 pool.start(runnable: task);
352 }
353 pool.waitForDone();
354
355 owner.quit();
356 owner.wait();
357}
358
359void tst_QPointer::qvariantCast()
360{
361 QFile file;
362 QPointer<QFile> tracking = &file;
363 tracking->setObjectName("A test name");
364 QVariant v = QVariant::fromValue(value: tracking);
365
366 {
367 QPointer<QObject> other = qPointerFromVariant<QObject>(variant: v);
368 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
369 }
370 {
371 QPointer<QIODevice> other = qPointerFromVariant<QIODevice>(variant: v);
372 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
373 }
374 {
375 QPointer<QFile> other = qPointerFromVariant<QFile>(variant: v);
376 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
377 }
378 {
379 QPointer<QThread> other = qPointerFromVariant<QThread>(variant: v);
380 QVERIFY(!other);
381 }
382 {
383 QPointer<QFile> toBeDeleted = new QFile;
384 QVariant deletedVariant = QVariant::fromValue(value: toBeDeleted);
385 delete toBeDeleted;
386 QPointer<QObject> deleted = qPointerFromVariant<QObject>(variant: deletedVariant);
387 QVERIFY(!deleted);
388 }
389
390 // Intentionally does not compile.
391// QPointer<int> sop = qPointerFromVariant<int>(v);
392}
393
394void tst_QPointer::constPointer()
395{
396 // Compile-time test that QPointer<const T> works.
397 QPointer<const QFile> fp = new QFile;
398 delete fp.data();
399}
400
401void tst_QPointer::constQPointer()
402{
403 // Check that const QPointers work. It's a bit weird to mark a pointer
404 // const if its value can change, but the shallow-const principle in C/C++
405 // allows this, and people use it, so document it with a test.
406 //
407 // It's unlikely that this test will fail in and out of itself, but it
408 // presents the use-case to static and dynamic checkers that can raise
409 // a warning (hopefully) should this become an issue.
410 QObject *o = new QObject(this);
411 const QPointer<QObject> p = o;
412 delete o;
413 QVERIFY(!p);
414}
415
416
417QTEST_MAIN(tst_QPointer)
418#include "tst_qpointer.moc"
419

source code of qtbase/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp