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#include <QtCore/QScopedPointer>
31
32/*!
33 \class tst_QScopedPointer
34 \internal
35 \since 4.6
36 \brief Tests class QScopedPointer.
37
38 */
39class tst_QScopedPointer : public QObject
40{
41 Q_OBJECT
42
43private Q_SLOTS:
44 void defaultConstructor();
45 void dataOnDefaultConstructed();
46 void useSubClassInConstructor();
47 void dataOnValue();
48 void dataSignature();
49 void reset();
50 void dereferenceOperator();
51 void dereferenceOperatorSignature();
52 void pointerOperator();
53 void pointerOperatorSignature();
54 void negationOperator();
55 void negationOperatorSignature();
56 void operatorBool();
57 void operatorBoolSignature();
58 void isNull();
59 void isNullSignature();
60 void objectSize();
61 void comparison();
62 void array();
63 // TODO instanciate on const object
64};
65
66void tst_QScopedPointer::defaultConstructor()
67{
68 /* Check that the members, one, is correctly initialized. */
69 QScopedPointer<int> p;
70 QCOMPARE(p.data(), static_cast<int *>(0));
71 QCOMPARE(p.get(), static_cast<int *>(0));
72}
73
74void tst_QScopedPointer::dataOnDefaultConstructed()
75{
76 QScopedPointer<int> p;
77
78 QCOMPARE(p.data(), static_cast<int *>(0));
79 QCOMPARE(p.get(), static_cast<int *>(0));
80}
81
82class MyClass
83{
84};
85
86class MySubClass : public MyClass
87{
88};
89
90void tst_QScopedPointer::useSubClassInConstructor()
91{
92 /* Use a syntax which users typically would do. */
93 QScopedPointer<MyClass> p(new MySubClass());
94}
95
96void tst_QScopedPointer::dataOnValue()
97{
98 int *const rawPointer = new int(5);
99 QScopedPointer<int> p(rawPointer);
100
101 QCOMPARE(p.data(), rawPointer);
102}
103
104void tst_QScopedPointer::dataSignature()
105{
106 const QScopedPointer<int> p;
107 /* data() should be const. */
108 p.data();
109}
110
111void tst_QScopedPointer::reset()
112{
113 /* Call reset() on a default constructed value. */
114 {
115 QScopedPointer<int> p;
116 p.reset();
117 QCOMPARE(p.data(), static_cast<int *>(0));
118 QCOMPARE(p.get(), static_cast<int *>(0));
119 }
120
121 /* Call reset() on an active value. */
122 {
123 QScopedPointer<int> p(new int(3));
124 p.reset();
125 QCOMPARE(p.data(), static_cast<int *>(0));
126 QCOMPARE(p.get(), static_cast<int *>(0));
127 }
128
129 /* Call reset() with a value, on an active value. */
130 {
131 QScopedPointer<int> p(new int(3));
132
133 int *const value = new int(9);
134 p.reset(other: value);
135 QCOMPARE(*p.data(), 9);
136 QCOMPARE(*p.get(), 9);
137 }
138
139 /* Call reset() with a value, on default constructed value. */
140 {
141 QScopedPointer<int> p;
142
143 int *const value = new int(9);
144 p.reset(other: value);
145 QCOMPARE(*p.data(), 9);
146 QCOMPARE(*p.get(), 9);
147 }
148}
149
150class AbstractClass
151{
152public:
153 virtual ~AbstractClass()
154 {
155 }
156
157 virtual int member() const = 0;
158};
159
160class SubClass : public AbstractClass
161{
162public:
163 virtual int member() const
164 {
165 return 5;
166 }
167};
168
169void tst_QScopedPointer::dereferenceOperator()
170{
171 /* Dereference a basic value. */
172 {
173 QScopedPointer<int> p(new int(5));
174
175 const int value2 = *p;
176 QCOMPARE(value2, 5);
177 }
178
179 /* Dereference a pointer to an abstract class. This verifies
180 * that the operator returns a reference, when compiling
181 * with MSVC 2005. */
182 {
183 QScopedPointer<AbstractClass> p(new SubClass());
184
185 QCOMPARE((*p).member(), 5);
186 }
187}
188
189void tst_QScopedPointer::dereferenceOperatorSignature()
190{
191 /* The operator should be const. */
192 {
193 const QScopedPointer<int> p(new int(5));
194 *p;
195 }
196
197 /* A reference should be returned, not a value. */
198 {
199 const QScopedPointer<int> p(new int(5));
200 Q_UNUSED(static_cast<int &>(*p));
201 }
202
203 /* Instantiated on a const object, the returned object is a const reference. */
204 {
205 const QScopedPointer<const int> p(new int(5));
206 Q_UNUSED(static_cast<const int &>(*p));
207 }
208}
209
210class AnyForm
211{
212public:
213 int value;
214};
215
216void tst_QScopedPointer::pointerOperator()
217{
218 QScopedPointer<AnyForm> p(new AnyForm());
219 p->value = 5;
220
221 QCOMPARE(p->value, 5);
222}
223
224void tst_QScopedPointer::pointerOperatorSignature()
225{
226 /* The operator should be const. */
227 const QScopedPointer<AnyForm> p(new AnyForm);
228 p->value = 5;
229
230 QVERIFY(p->value);
231}
232
233void tst_QScopedPointer::negationOperator()
234{
235 /* Invoke on default constructed value. */
236 {
237 QScopedPointer<int> p;
238 QVERIFY(!p);
239 }
240
241 /* Invoke on a value. */
242 {
243 QScopedPointer<int> p(new int(2));
244 QCOMPARE(!p, false);
245 }
246}
247
248void tst_QScopedPointer::negationOperatorSignature()
249{
250 /* The signature should be const. */
251 const QScopedPointer<int> p;
252 !p;
253
254 /* The return value should be bool. */
255 static_cast<bool>(!p);
256}
257
258void tst_QScopedPointer::operatorBool()
259{
260 /* Invoke on default constructed value. */
261 {
262 QScopedPointer<int> p;
263 QCOMPARE(bool(p), false);
264 }
265
266 /* Invoke on active value. */
267 {
268 QScopedPointer<int> p(new int(3));
269 QVERIFY(p);
270 }
271}
272
273void tst_QScopedPointer::operatorBoolSignature()
274{
275 /* The signature should be const and return bool. */
276 const QScopedPointer<int> p;
277
278 (void)static_cast<bool>(p);
279}
280
281void tst_QScopedPointer::isNull()
282{
283 /* Invoke on default constructed value. */
284 {
285 QScopedPointer<int> p;
286 QVERIFY(p.isNull());
287 QVERIFY(p == nullptr);
288 QVERIFY(nullptr == p);
289 }
290
291 /* Invoke on a set value. */
292 {
293 QScopedPointer<int> p(new int(69));
294 QVERIFY(!p.isNull());
295 QVERIFY(p != nullptr);
296 QVERIFY(nullptr != p);
297 }
298}
299
300void tst_QScopedPointer::isNullSignature()
301{
302 const QScopedPointer<int> p(new int(69));
303
304 /* The signature should be const and return bool. */
305 static_cast<bool>(p.isNull());
306}
307
308void tst_QScopedPointer::objectSize()
309{
310 /* The size of QScopedPointer should be the same as one pointer. */
311 QCOMPARE(sizeof(QScopedPointer<int>), sizeof(void *));
312}
313
314struct RefCounted
315{
316 RefCounted()
317 : ref(0)
318 {
319 instanceCount.ref();
320 }
321
322 RefCounted(RefCounted const &)
323 : ref(0)
324 {
325 instanceCount.ref();
326 }
327
328 ~RefCounted()
329 {
330 QVERIFY( ref.loadRelaxed() == 0 );
331 instanceCount.deref();
332 }
333
334 RefCounted &operator=(RefCounted const &)
335 {
336 return *this;
337 }
338
339 QAtomicInt ref;
340
341 static QAtomicInt instanceCount;
342};
343
344QAtomicInt RefCounted::instanceCount = 0;
345
346template <class A1, class A2, class B>
347void scopedPointerComparisonTest(const A1 &a1, const A2 &a2, const B &b)
348{
349 // test equality on equal pointers
350 QVERIFY(a1 == a2);
351 QVERIFY(a2 == a1);
352
353 // test inequality on equal pointers
354 QVERIFY(!(a1 != a2));
355 QVERIFY(!(a2 != a1));
356
357 // test equality on unequal pointers
358 QVERIFY(!(a1 == b));
359 QVERIFY(!(a2 == b));
360 QVERIFY(!(b == a1));
361 QVERIFY(!(b == a2));
362
363 // test inequality on unequal pointers
364 QVERIFY(b != a1);
365 QVERIFY(b != a2);
366 QVERIFY(a1 != b);
367 QVERIFY(a2 != b);
368}
369
370void tst_QScopedPointer::comparison()
371{
372 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
373
374 {
375 RefCounted *a = new RefCounted;
376 RefCounted *b = new RefCounted;
377
378 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
379
380 QScopedPointer<RefCounted> pa1(a);
381 QScopedPointer<RefCounted> pa2(a);
382 QScopedPointer<RefCounted> pb(b);
383
384 scopedPointerComparisonTest(a1: pa1, a2: pa1, b: pb);
385 scopedPointerComparisonTest(a1: pa2, a2: pa2, b: pb);
386 scopedPointerComparisonTest(a1: pa1, a2: pa2, b: pb);
387
388 pa2.take();
389
390 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
391 }
392
393 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
394
395 {
396 RefCounted *a = new RefCounted[42];
397 RefCounted *b = new RefCounted[43];
398
399 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
400
401 QScopedArrayPointer<RefCounted> pa1(a);
402 QScopedArrayPointer<RefCounted> pa2(a);
403 QScopedArrayPointer<RefCounted> pb(b);
404
405 scopedPointerComparisonTest(a1: pa1, a2: pa2, b: pb);
406
407 pa2.take();
408
409 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
410 }
411
412 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
413
414 {
415 // QScopedSharedPointer is an internal helper class -- it is unsupported!
416
417 RefCounted *a = new RefCounted;
418 RefCounted *b = new RefCounted;
419
420 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
421
422 QSharedDataPointer<RefCounted> pa1(a);
423 QSharedDataPointer<RefCounted> pa2(a);
424 QSharedDataPointer<RefCounted> pb(b);
425
426 QCOMPARE( a->ref.loadRelaxed(), 2 );
427 QCOMPARE( b->ref.loadRelaxed(), 1 );
428 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
429
430 scopedPointerComparisonTest(a1: pa1, a2: pa2, b: pb);
431
432 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
433 }
434
435 QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
436}
437
438void tst_QScopedPointer::array()
439{
440 int instCount = RefCounted::instanceCount.loadRelaxed();
441 {
442 QScopedArrayPointer<RefCounted> array;
443 array.reset(other: new RefCounted[42]);
444 QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed());
445 }
446 QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
447 {
448 QScopedArrayPointer<RefCounted> array(new RefCounted[42]);
449 QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed());
450 array.reset(other: new RefCounted[28]);
451 QCOMPARE(instCount + 28, RefCounted::instanceCount.loadRelaxed());
452 array.reset(other: 0);
453 QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
454 }
455 QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
456}
457
458
459QTEST_MAIN(tst_QScopedPointer)
460#include "tst_qscopedpointer.moc"
461

source code of qtbase/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp