24 virtual ~ITrackable () =
default;
26 virtual QObject* GetQObject () = 0;
27 virtual int GetValue ()
const = 0;
36 explicit TrackableObject (
int value = 0)
41 QObject* GetQObject ()
override
46 int GetValue ()
const override
52 class ExternallyBacked
56 explicit ExternallyBacked (QObject *anchor)
61 QObject* Anchor ()
const
67 QObject* AnchorOf (ExternallyBacked *backed)
69 return backed->Anchor ();
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");
80 void TrackingPointerTest::testTracksLiveObject ()
82 TrackableObject obj { 42 };
83 ITrackable *
const iface = &obj;
85 const TrackingPointer<ITrackable> ptr { iface };
87 QVERIFY (
static_cast<bool> (ptr));
88 QCOMPARE (ptr.UnsafeGet (), iface);
89 QCOMPARE (ptr->GetValue (), 42);
90 QCOMPARE ((*ptr).GetValue (), 42);
93 void TrackingPointerTest::testDetectsDestruction ()
95 auto obj = std::make_unique<TrackableObject> (5);
96 const TrackingPointer<ITrackable> ptr { obj.get () };
105 void TrackingPointerTest::testDeadAccessThrows ()
107 auto obj = std::make_unique<TrackableObject> ();
108 const TrackingPointer<ITrackable> ptr { obj.get () };
112 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, ptr->GetValue ());
113 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, (*ptr).GetValue ());
116 void TrackingPointerTest::testNullIsInvalid ()
118 const TrackingPointer<ITrackable> defaulted;
119 QVERIFY (!defaulted);
120 QVERIFY (!defaulted.UnsafeGet ());
122 ITrackable *
const nullIface =
nullptr;
123 const TrackingPointer<ITrackable> fromNull { nullIface };
125 QVERIFY (!fromNull.UnsafeGet ());
127 QVERIFY_THROWS_EXCEPTION (BadTrackingPointerAccess, fromNull->GetValue ());
130 void TrackingPointerTest::testCopyPropagatesTracking ()
132 auto obj = std::make_unique<TrackableObject> (7);
134 TrackingPointer<ITrackable> copy;
138 const TrackingPointer<ITrackable> original { obj.get () };
143 QCOMPARE (copy->GetValue (), 7);
149 void TrackingPointerTest::testEqualityIsIdentity ()
151 TrackableObject first { 1 };
152 TrackableObject second { 2 };
154 const TrackingPointer<ITrackable> a { &first };
155 const TrackingPointer<ITrackable> b { &first };
156 const TrackingPointer<ITrackable> c { &second };
161 ITrackable *
const firstIface = &first;
162 QVERIFY (a == firstIface);
164 const TrackingPointer<ITrackable> empty;
165 QVERIFY (empty ==
nullptr);
166 QVERIFY (a !=
nullptr);
169 void TrackingPointerTest::testCustomGetter ()
171 auto anchor = std::make_unique<QObject> ();
172 ExternallyBacked backed { anchor.get () };
174 const TrackingPointer<ExternallyBacked, &ExternallyBacked::Anchor> viaMember { &backed };
176 QCOMPARE (viaMember.UnsafeGet (), &backed);
178 const TrackingPointer<ExternallyBacked, &AnchorOf> viaFreeFunc { &backed };
179 QVERIFY (viaFreeFunc);
182 QVERIFY (!viaMember);
183 QVERIFY (!viaFreeFunc);