Fix crash when auto-sizing a wxDataViewCtrl column.
[wxWidgets.git] / tests / weakref / weakref.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/weakref/weakref.cpp
3 // Purpose: wxWeakRef<T> unit test
4 // Author: Arne Steinarson
5 // Created: 2008-01-10
6 // Copyright: (c) 2007 Arne Steinarson
7 ///////////////////////////////////////////////////////////////////////////////
8
9 // ----------------------------------------------------------------------------
10 // headers
11 // ----------------------------------------------------------------------------
12
13 #include "testprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif // WX_PRECOMP
22
23 #include "wx/event.h"
24 #include "wx/weakref.h"
25
26 // A statically trackable derived wxObject
27 class wxObjectTrackable : public wxObject, public wxTrackable
28 {
29 public:
30 // Test member access
31 void TestFunc(){ }
32
33 // Make sure this does not clash with wxTrackableBase method
34 int GetFirst() { return 0; }
35 };
36
37 // --------------------------------------------------------------------------
38 // test class
39 // --------------------------------------------------------------------------
40
41 class WeakRefTestCase : public CppUnit::TestCase
42 {
43 public:
44 WeakRefTestCase() {}
45
46 private:
47 CPPUNIT_TEST_SUITE( WeakRefTestCase );
48 CPPUNIT_TEST( DeclareTest );
49 CPPUNIT_TEST( AssignTest );
50 CPPUNIT_TEST( AssignWeakRefTest );
51 CPPUNIT_TEST( MultiAssignTest );
52 CPPUNIT_TEST( CleanupTest );
53 CPPUNIT_TEST( DeleteTest );
54 #ifdef HAVE_DYNAMIC_CAST
55 CPPUNIT_TEST( DynamicRefTest );
56 #endif
57 CPPUNIT_TEST_SUITE_END();
58
59 void DeclareTest();
60 void AssignTest();
61 void AssignWeakRefTest();
62 void MultiAssignTest();
63 void CleanupTest();
64 void DeleteTest();
65 #ifdef HAVE_DYNAMIC_CAST
66 void DynamicRefTest();
67 #endif
68
69 DECLARE_NO_COPY_CLASS(WeakRefTestCase)
70 };
71
72 // register in the unnamed registry so that these tests are run by default
73 CPPUNIT_TEST_SUITE_REGISTRATION( WeakRefTestCase );
74
75 // also include in its own registry so that these tests can be run alone
76 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WeakRefTestCase, "WeakRefTestCase" );
77
78
79 // Test weak reference to an incomplete type, this should work if the type is
80 // fully defined before it is used (but currently doesn't, see #11916)
81 struct ForwardDeclaredClass;
82 wxWeakRef<ForwardDeclaredClass> g_incompleteWeakRef;
83
84 struct ForwardDeclaredClass : wxEvtHandler { };
85
86 void WeakRefTestCase::DeclareTest()
87 {
88 {
89 // Not initializing or initializing with NULL should work too
90 //
91 // FIXME-VC6: but it doesn't with VC6, see comment in wx/weakref.h
92 #ifndef __VISUALC6__
93 wxWeakRef<wxEvtHandler> wroDef;
94 wxWeakRef<wxEvtHandler> wro0(NULL);
95 #endif // __VISUALC6__
96
97 wxObject o; // Should not work
98 wxEvtHandler eh;
99 wxObjectTrackable ot;
100
101 // Test declare when T is wxObject
102 // wxWeakRef<wxObject> wro1(&o); // Gives compile time failure
103 wxWeakRef<wxEvtHandler> wro2(&eh);
104 wxWeakRef<wxObjectTrackable> wro3(&ot);
105
106 CPPUNIT_ASSERT( wro2.get() == &eh );
107 CPPUNIT_ASSERT( wro3.get() == &ot );
108
109 // Test accessing wxObject members
110 CPPUNIT_ASSERT( !wro2->GetRefData() );
111 CPPUNIT_ASSERT( !wro3->GetRefData() );
112
113
114 wxWeakRef<wxEvtHandler> wreh(&eh);
115 wxWeakRef<wxObjectTrackable> wrot(&ot);
116
117 CPPUNIT_ASSERT( wreh.get() == &eh );
118 CPPUNIT_ASSERT( wrot.get() == &ot );
119 }
120
121 // This test requires a working dynamic_cast<>
122 #ifndef wxNO_RTTI
123 {
124 ForwardDeclaredClass fdc;
125 g_incompleteWeakRef = &fdc;
126 CPPUNIT_ASSERT( g_incompleteWeakRef );
127 }
128
129 CPPUNIT_ASSERT( !g_incompleteWeakRef );
130 #endif // RTTI enabled
131 }
132
133 void WeakRefTestCase::AssignTest()
134 {
135 wxWeakRef<wxEvtHandler> wro1;
136 wxWeakRef<wxObjectTrackable> wro2;
137
138 { // Scope for object destruction
139 wxEvtHandler eh;
140 wxObjectTrackable ot;
141
142 wro1 = &eh;
143 wro2 = &ot;
144
145 CPPUNIT_ASSERT( wro1.get() == &eh );
146 CPPUNIT_ASSERT( wro2.get() == &ot );
147 }
148
149 // Should be reset now
150 CPPUNIT_ASSERT( !wro1 );
151 CPPUNIT_ASSERT( !wro2 );
152
153 // Explicitly resetting should work too
154 //
155 // FIXME-VC6: as above, it doesn't work with VC6, see wx/weakref.h
156 #ifndef __VISUALC6__
157 wxEvtHandler eh;
158 wxObjectTrackable ot;
159
160 wro1 = &eh;
161 wro2 = &ot;
162
163 wro1 = NULL;
164 wro2 = NULL;
165
166 CPPUNIT_ASSERT( !wro1 );
167 CPPUNIT_ASSERT( !wro2 );
168 #endif // __VISUALC6__
169 }
170
171 void WeakRefTestCase::AssignWeakRefTest()
172 {
173 // Test declare when T is wxObject
174 wxWeakRef<wxEvtHandler> wro1;
175 wxWeakRef<wxObjectTrackable> wro2;
176
177 { // Scope for object destruction
178 wxEvtHandler eh;
179 wxObjectTrackable ot;
180 wxWeakRef<wxEvtHandler> wro3;
181 wxWeakRef<wxObjectTrackable> wro4;
182
183 wro1 = &eh;
184 wro2 = &ot;
185 wro3 = wro1;
186 wro4 = wro2;
187
188 CPPUNIT_ASSERT( wro1.get() == &eh );
189 CPPUNIT_ASSERT( wro2.get() == &ot );
190 CPPUNIT_ASSERT( wro3.get() == &eh );
191 CPPUNIT_ASSERT( wro4.get() == &ot );
192
193 wro4.Release();
194 CPPUNIT_ASSERT( !wro4.get() );
195 }
196
197 // Should be reset now
198 CPPUNIT_ASSERT( !wro1 );
199 CPPUNIT_ASSERT( !wro2 );
200 }
201
202 void WeakRefTestCase::MultiAssignTest()
203 {
204 // Object is tracked by several refs
205 wxEvtHandler *peh = new wxEvtHandler;
206
207 // Test declare when T is wxObject
208 wxWeakRef<wxEvtHandler> wro1(peh);
209 wxWeakRef<wxEvtHandler> wro2(peh);
210
211 wxObjectTrackable *pot = new wxObjectTrackable;
212 wxWeakRef<wxObjectTrackable> wro3 = pot;
213 wxWeakRef<wxObjectTrackable> wro4 = pot;
214
215 CPPUNIT_ASSERT( wro1.get() == peh );
216 CPPUNIT_ASSERT( wro2.get() == peh );
217 CPPUNIT_ASSERT( wro3.get() == pot );
218 CPPUNIT_ASSERT( wro4.get() == pot );
219
220 delete peh;
221 delete pot;
222
223 // Should be reset now
224 CPPUNIT_ASSERT( !wro1 );
225 CPPUNIT_ASSERT( !wro2 );
226 CPPUNIT_ASSERT( !wro3 );
227 CPPUNIT_ASSERT( !wro4 );
228 }
229
230 void WeakRefTestCase::CleanupTest()
231 {
232 // Make sure that trackable objects have no left over tracker nodes after use.
233 // This time the references goes out of scope before the objects.
234 wxEvtHandler eh;
235 wxObjectTrackable ots;
236 wxObjectTrackable otd;
237
238 { // Scope for object destruction
239 wxWeakRef<wxEvtHandler> wro1;
240 wxWeakRef<wxEvtHandler> wro2;
241 wxWeakRef<wxObjectTrackable> wro3;
242 wxWeakRef<wxObjectTrackable> wro4;
243
244 wro1 = &eh;
245 wro2 = &eh; // Has two tracker nodes now
246 wro3 = &ots;
247 wro4 = &otd;
248
249 // Access members of reffed object
250 wro3->TestFunc();
251
252 CPPUNIT_ASSERT( eh.GetFirst()==&wro2 );
253 CPPUNIT_ASSERT( ots.wxTrackable::GetFirst()==&wro3 );
254 CPPUNIT_ASSERT( otd.wxTrackable::GetFirst()==&wro4 );
255 }
256
257 // Should be reset now
258 CPPUNIT_ASSERT( !eh.GetFirst() );
259 CPPUNIT_ASSERT( !ots.wxTrackable::GetFirst() );
260 CPPUNIT_ASSERT( !otd.wxTrackable::GetFirst() );
261 }
262
263 void WeakRefTestCase::DeleteTest()
264 {
265 // Object is tracked by several refs
266 wxEvtHandler *peh = new wxEvtHandler;
267
268 // Declared derived type of object and test deleting it
269 wxEvtHandlerRef wre(peh);
270 wxWeakRef<wxEvtHandler> wro(peh);
271
272 CPPUNIT_ASSERT( wre.get() == peh );
273 CPPUNIT_ASSERT( wro.get() == peh );
274
275 delete wre.get();
276
277 CPPUNIT_ASSERT( !wre );
278 CPPUNIT_ASSERT( !wro );
279 }
280
281 #ifdef HAVE_DYNAMIC_CAST
282
283 void WeakRefTestCase::DynamicRefTest()
284 {
285 wxWeakRefDynamic<wxEvtHandler> wro1;
286 wxWeakRefDynamic<wxObjectTrackable> wro2;
287 wxWeakRefDynamic<wxObjectTrackable> wro3;
288
289 { // Scope for object destruction
290 {
291 wxEvtHandler eh;
292 wro1 = &eh;
293 }
294
295 CPPUNIT_ASSERT( !wro1 );
296
297 wxObjectTrackable otd1;
298 wxObjectTrackable otd2;
299 wro2 = &otd1;
300 wro3 = &otd2;
301
302 CPPUNIT_ASSERT( wro2.get() == &otd1 );
303 CPPUNIT_ASSERT( wro3.get() == &otd2 );
304
305 wro3 = wro2;
306 CPPUNIT_ASSERT( wro2.get() == &otd1 );
307 CPPUNIT_ASSERT( wro3.get() == &otd1 );
308 }
309
310 // Should be reset now
311 CPPUNIT_ASSERT( !wro2 );
312 CPPUNIT_ASSERT( !wro3 );
313 }
314
315 #endif // HAVE_DYNAMIC_CAST