LeechCraft 0.6.70-18808-g3467692359
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
trackingpointertest.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
10#include <memory>
11#include <type_traits>
12#include <QtTest>
13#include "trackingpointer.h"
14
16
17namespace LC::Util
18{
19 namespace
20 {
21 class ITrackable
22 {
23 public:
24 virtual ~ITrackable () = default;
25
26 virtual QObject* GetQObject () = 0;
27 virtual int GetValue () const = 0;
28 };
29
30 class TrackableObject
31 : public QObject
32 , public ITrackable
33 {
34 int Value_;
35 public:
36 explicit TrackableObject (int value = 0)
37 : Value_ { value }
38 {
39 }
40
41 QObject* GetQObject () override
42 {
43 return this;
44 }
45
46 int GetValue () const override
47 {
48 return Value_;
49 }
50 };
51
52 class ExternallyBacked
53 {
54 QObject *Anchor_;
55 public:
56 explicit ExternallyBacked (QObject *anchor)
57 : Anchor_ { anchor }
58 {
59 }
60
61 QObject* Anchor () const
62 {
63 return Anchor_;
64 }
65 };
66
67 QObject* AnchorOf (ExternallyBacked *backed)
68 {
69 return backed->Anchor ();
70 }
71 }
72
73 static_assert (std::is_convertible_v<ITrackable*, TrackingPointer<ITrackable>>,
74 "a raw interface pointer should implicitly convert into a TrackingPointer");
75 static_assert (!std::is_convertible_v<TrackingPointer<ITrackable>, ITrackable*>,
76 "a TrackingPointer must not silently decay back to a raw pointer");
77 static_assert (!std::is_convertible_v<TrackingPointer<ITrackable>, bool>,
78 "operator bool must remain explicit");
79
80 void TrackingPointerTest::testTracksLiveObject ()
81 {
82 TrackableObject obj { 42 };
83 ITrackable * const iface = &obj;
84
85 const TrackingPointer<ITrackable> ptr { iface };
86
87 QVERIFY (static_cast<bool> (ptr));
88 QCOMPARE (ptr.UnsafeGet (), iface);
89 QCOMPARE (ptr->GetValue (), 42);
90 QCOMPARE ((*ptr).GetValue (), 42);
91 }
92
93 void TrackingPointerTest::testDetectsDestruction ()
94 {
95 auto obj = std::make_unique<TrackableObject> (5);
96 const TrackingPointer<ITrackable> ptr { obj.get () };
97
98 QVERIFY (ptr);
99
100 obj.reset ();
101
102 QVERIFY (!ptr);
103 }
104
105 void TrackingPointerTest::testDeadAccessThrows ()
106 {
107 auto obj = std::make_unique<TrackableObject> ();
108 const TrackingPointer<ITrackable> ptr { obj.get () };
109 obj.reset ();
110
111 QVERIFY (!ptr);
112 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, ptr->GetValue ());
113 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, (*ptr).GetValue ());
114 }
115
116 void TrackingPointerTest::testNullIsInvalid ()
117 {
118 const TrackingPointer<ITrackable> defaulted;
119 QVERIFY (!defaulted);
120 QVERIFY (!defaulted.UnsafeGet ());
121
122 ITrackable * const nullIface = nullptr;
123 const TrackingPointer<ITrackable> fromNull { nullIface };
124 QVERIFY (!fromNull);
125 QVERIFY (!fromNull.UnsafeGet ());
126
127 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, fromNull->GetValue ());
128 }
129
130 void TrackingPointerTest::testCopyPropagatesTracking ()
131 {
132 auto obj = std::make_unique<TrackableObject> (7);
133
134 TrackingPointer<ITrackable> copy;
135 QVERIFY (!copy);
136
137 {
138 const TrackingPointer<ITrackable> original { obj.get () };
139 copy = original;
140 }
141
142 QVERIFY (copy);
143 QCOMPARE (copy->GetValue (), 7);
144
145 obj.reset ();
146 QVERIFY (!copy);
147 }
148
149 void TrackingPointerTest::testEqualityIsIdentity ()
150 {
151 TrackableObject first { 1 };
152 TrackableObject second { 2 };
153
154 const TrackingPointer<ITrackable> a { &first };
155 const TrackingPointer<ITrackable> b { &first };
156 const TrackingPointer<ITrackable> c { &second };
157
158 QVERIFY (a == b);
159 QVERIFY (a != c);
160
161 ITrackable * const firstIface = &first;
162 QVERIFY (a == firstIface);
163
164 const TrackingPointer<ITrackable> empty;
165 QVERIFY (empty == nullptr);
166 QVERIFY (a != nullptr);
167 }
168
169 void TrackingPointerTest::testCustomGetter ()
170 {
171 auto anchor = std::make_unique<QObject> ();
172 ExternallyBacked backed { anchor.get () };
173
174 const TrackingPointer<ExternallyBacked, &ExternallyBacked::Anchor> viaMember { &backed };
175 QVERIFY (viaMember);
176 QCOMPARE (viaMember.UnsafeGet (), &backed);
177
178 const TrackingPointer<ExternallyBacked, &AnchorOf> viaFreeFunc { &backed };
179 QVERIFY (viaFreeFunc);
180
181 anchor.reset ();
182 QVERIFY (!viaMember);
183 QVERIFY (!viaFreeFunc);
184 }
185}