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