|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 |
|
45 QT_USE_NAMESPACE |
|
46 |
|
47 #if defined(QT_NO_EXCEPTIONS) |
|
48 QTEST_NOOP_MAIN |
|
49 #else |
|
50 class tst_ExceptionSafety: public QObject |
|
51 { |
|
52 Q_OBJECT |
|
53 private slots: |
|
54 void exceptionInSlot(); |
|
55 void exceptionVector(); |
|
56 void exceptionHash(); |
|
57 void exceptionMap(); |
|
58 void exceptionList(); |
|
59 void exceptionLinkedList(); |
|
60 // void exceptionEventLoop(); |
|
61 // void exceptionSignalSlot(); |
|
62 }; |
|
63 |
|
64 class Emitter : public QObject |
|
65 { |
|
66 Q_OBJECT |
|
67 public: |
|
68 inline void emitTestSignal() { emit testSignal(); } |
|
69 signals: |
|
70 void testSignal(); |
|
71 }; |
|
72 |
|
73 class ExceptionThrower : public QObject |
|
74 { |
|
75 Q_OBJECT |
|
76 public slots: |
|
77 void thrower() { throw 5; } |
|
78 }; |
|
79 |
|
80 class Receiver : public QObject |
|
81 { |
|
82 Q_OBJECT |
|
83 public: |
|
84 Receiver() |
|
85 : received(0) {} |
|
86 int received; |
|
87 |
|
88 public slots: |
|
89 void receiver() { ++received; } |
|
90 }; |
|
91 |
|
92 enum ThrowType { ThrowNot = 0, ThrowAtCreate = 1, ThrowAtCopy = 2, ThrowLater = 3, ThrowAtComparison = 4 }; |
|
93 |
|
94 ThrowType throwType = ThrowNot; // global flag to indicate when an exception should be throw. Will be reset when the exception has been generated. |
|
95 |
|
96 int objCounter = 0; |
|
97 |
|
98 /*! Class that does not throw any exceptions. Used as baseclass for all the other ones. |
|
99 */ |
|
100 template <int T> |
|
101 class FlexibleThrower |
|
102 { |
|
103 public: |
|
104 FlexibleThrower() : _value(-1) { |
|
105 if( throwType == ThrowAtCreate ) { |
|
106 throwType = ThrowNot; |
|
107 throw ThrowAtCreate; |
|
108 } |
|
109 objCounter++; |
|
110 } |
|
111 |
|
112 FlexibleThrower( short value ) : _value(value) { |
|
113 if( throwType == ThrowAtCreate ) { |
|
114 throwType = ThrowNot; |
|
115 throw ThrowAtCreate; |
|
116 } |
|
117 objCounter++; |
|
118 } |
|
119 |
|
120 FlexibleThrower(FlexibleThrower const& other ) { |
|
121 // qDebug("cc"); |
|
122 |
|
123 if( throwType == ThrowAtCopy ) { |
|
124 throwType = ThrowNot; |
|
125 throw ThrowAtCopy; |
|
126 |
|
127 } else if( throwType == ThrowLater ) { |
|
128 throwType = ThrowAtCopy; |
|
129 } |
|
130 |
|
131 objCounter++; |
|
132 _value = other.value(); |
|
133 } |
|
134 |
|
135 ~FlexibleThrower() { objCounter--; } |
|
136 |
|
137 bool operator==(const FlexibleThrower<T> &t) const |
|
138 { |
|
139 // qDebug("vv == %d %d", value(), t.value()); |
|
140 if( throwType == ThrowAtComparison ) { |
|
141 throwType = ThrowNot; |
|
142 throw ThrowAtComparison; |
|
143 } |
|
144 return value()==t.value(); |
|
145 } |
|
146 |
|
147 bool operator<(const FlexibleThrower<T> &t) const |
|
148 { |
|
149 // qDebug("vv < %d %d", value(), t.value()); |
|
150 if( throwType == ThrowAtComparison ) { |
|
151 throwType = ThrowNot; |
|
152 throw ThrowAtComparison; |
|
153 } |
|
154 return value()<t.value(); |
|
155 } |
|
156 |
|
157 int value() const |
|
158 { return (int)_value; } |
|
159 |
|
160 short _value; |
|
161 char dummy[T]; |
|
162 }; |
|
163 |
|
164 uint qHash(const FlexibleThrower<2>& t) |
|
165 { |
|
166 // qDebug("ha"); |
|
167 if( throwType == ThrowAtComparison ) { |
|
168 throwType = ThrowNot; |
|
169 throw ThrowAtComparison; |
|
170 } |
|
171 return (uint)t.value(); |
|
172 } |
|
173 |
|
174 typedef FlexibleThrower<2> FlexibleThrowerSmall; |
|
175 typedef QMap<FlexibleThrowerSmall,FlexibleThrowerSmall> MyMap; |
|
176 typedef QHash<FlexibleThrowerSmall,FlexibleThrowerSmall> MyHash; |
|
177 |
|
178 // connect a signal to a slot that throws an exception |
|
179 // run this through valgrind to make sure it doesn't corrupt |
|
180 void tst_ExceptionSafety::exceptionInSlot() |
|
181 { |
|
182 Emitter emitter; |
|
183 ExceptionThrower thrower; |
|
184 |
|
185 connect(&emitter, SIGNAL(testSignal()), &thrower, SLOT(thrower())); |
|
186 |
|
187 try { |
|
188 emitter.emitTestSignal(); |
|
189 } catch (int i) { |
|
190 QCOMPARE(i, 5); |
|
191 } |
|
192 } |
|
193 |
|
194 void tst_ExceptionSafety::exceptionList() { |
|
195 |
|
196 { |
|
197 QList<FlexibleThrowerSmall> list; |
|
198 QList<FlexibleThrowerSmall> list2; |
|
199 QList<FlexibleThrowerSmall> list3; |
|
200 |
|
201 for( int i = 0; i<10; i++ ) |
|
202 list.append( FlexibleThrowerSmall(i) ); |
|
203 |
|
204 try { |
|
205 throwType = ThrowAtCopy; |
|
206 list.append( FlexibleThrowerSmall(10)); |
|
207 } catch (...) { |
|
208 } |
|
209 QCOMPARE( list.size(), 10 ); |
|
210 |
|
211 try { |
|
212 throwType = ThrowAtCopy; |
|
213 list.prepend( FlexibleThrowerSmall(10)); |
|
214 } catch (...) { |
|
215 } |
|
216 QCOMPARE( list.at(0).value(), 0 ); |
|
217 QCOMPARE( list.size(), 10 ); |
|
218 |
|
219 try { |
|
220 throwType = ThrowAtCopy; |
|
221 list.insert( 8, FlexibleThrowerSmall(10)); |
|
222 } catch (...) { |
|
223 } |
|
224 QCOMPARE( list.at(7).value(), 7 ); |
|
225 QCOMPARE( list.at(8).value(), 8 ); |
|
226 QCOMPARE( list.size(), 10 ); |
|
227 |
|
228 try { |
|
229 throwType = ThrowAtCopy; |
|
230 FlexibleThrowerSmall t = list.takeAt( 6 ); |
|
231 } catch (...) { |
|
232 } |
|
233 QCOMPARE( list.at(6).value(), 6 ); |
|
234 QCOMPARE( list.at(7).value(), 7 ); |
|
235 QCOMPARE( list.size(), 10 ); |
|
236 |
|
237 try { |
|
238 throwType = ThrowAtCopy; |
|
239 list3 = list; |
|
240 } catch (...) { |
|
241 } |
|
242 QCOMPARE( list.at(0).value(), 0 ); |
|
243 QCOMPARE( list.at(7).value(), 7 ); |
|
244 QCOMPARE( list.size(), 10 ); |
|
245 QCOMPARE( list3.at(0).value(), 0 ); |
|
246 QCOMPARE( list3.at(7).value(), 7 ); |
|
247 QCOMPARE( list3.size(), 10 ); |
|
248 |
|
249 try { |
|
250 throwType = ThrowAtCopy; |
|
251 list3.append( FlexibleThrowerSmall(11) ); |
|
252 } catch (...) { |
|
253 } |
|
254 QCOMPARE( list.at(0).value(), 0 ); |
|
255 QCOMPARE( list.at(7).value(), 7 ); |
|
256 QCOMPARE( list.size(), 10 ); |
|
257 QCOMPARE( list3.at(0).value(), 0 ); |
|
258 QCOMPARE( list3.at(7).value(), 7 ); |
|
259 QCOMPARE( list3.size(), 10 ); |
|
260 |
|
261 try { |
|
262 list2.clear(); |
|
263 list2.append( FlexibleThrowerSmall(11)); |
|
264 throwType = ThrowAtCopy; |
|
265 list3 = list+list2; |
|
266 } catch (...) { |
|
267 } |
|
268 QCOMPARE( list.at(0).value(), 0 ); |
|
269 QCOMPARE( list.at(7).value(), 7 ); |
|
270 QCOMPARE( list.size(), 10 ); |
|
271 |
|
272 // check that copy on write works atomar |
|
273 list2.clear(); |
|
274 list2.append( FlexibleThrowerSmall(11)); |
|
275 list3 = list+list2; |
|
276 try { |
|
277 throwType = ThrowAtCreate; |
|
278 list3[7]=FlexibleThrowerSmall(12); |
|
279 } catch (...) { |
|
280 } |
|
281 QCOMPARE( list.at(7).value(), 7 ); |
|
282 QCOMPARE( list.size(), 10 ); |
|
283 QCOMPARE( list3.at(7).value(), 7 ); |
|
284 QCOMPARE( list3.size(), 11 ); |
|
285 |
|
286 } |
|
287 QCOMPARE(objCounter, 0 ); // check that every object has been freed |
|
288 } |
|
289 |
|
290 void tst_ExceptionSafety::exceptionLinkedList() { |
|
291 |
|
292 { |
|
293 QLinkedList<FlexibleThrowerSmall> list; |
|
294 QLinkedList<FlexibleThrowerSmall> list2; |
|
295 QLinkedList<FlexibleThrowerSmall> list3; |
|
296 |
|
297 for( int i = 0; i<10; i++ ) |
|
298 list.append( FlexibleThrowerSmall(i) ); |
|
299 |
|
300 try { |
|
301 throwType = ThrowAtCopy; |
|
302 list.append( FlexibleThrowerSmall(10)); |
|
303 } catch (...) { |
|
304 } |
|
305 QCOMPARE( list.size(), 10 ); |
|
306 |
|
307 try { |
|
308 throwType = ThrowAtCopy; |
|
309 list.prepend( FlexibleThrowerSmall(10)); |
|
310 } catch (...) { |
|
311 } |
|
312 QCOMPARE( list.first().value(), 0 ); |
|
313 QCOMPARE( list.size(), 10 ); |
|
314 |
|
315 try { |
|
316 throwType = ThrowAtCopy; |
|
317 list3 = list; |
|
318 list3.append( FlexibleThrowerSmall(11) ); |
|
319 } catch (...) { |
|
320 } |
|
321 QCOMPARE( list.first().value(), 0 ); |
|
322 QCOMPARE( list.size(), 10 ); |
|
323 QCOMPARE( list3.size(), 10 ); |
|
324 } |
|
325 QCOMPARE(objCounter, 0 ); // check that every object has been freed |
|
326 } |
|
327 |
|
328 void tst_ExceptionSafety::exceptionVector() { |
|
329 |
|
330 { |
|
331 QVector<FlexibleThrowerSmall> vector; |
|
332 QVector<FlexibleThrowerSmall> vector2; |
|
333 QVector<FlexibleThrowerSmall> vector3; |
|
334 |
|
335 for (int i = 0; i<10; i++) |
|
336 vector.append( FlexibleThrowerSmall(i) ); |
|
337 |
|
338 try { |
|
339 throwType = ThrowAtCopy; |
|
340 vector.append( FlexibleThrowerSmall(10)); |
|
341 } catch (...) { |
|
342 } |
|
343 QCOMPARE( vector.size(), 10 ); |
|
344 |
|
345 try { |
|
346 throwType = ThrowAtCopy; |
|
347 vector.prepend( FlexibleThrowerSmall(10)); |
|
348 } catch (...) { |
|
349 } |
|
350 QCOMPARE( vector.at(0).value(), 0 ); |
|
351 QCOMPARE( vector.size(), 10 ); |
|
352 |
|
353 try { |
|
354 throwType = ThrowAtCopy; |
|
355 vector.insert( 8, FlexibleThrowerSmall(10)); |
|
356 } catch (...) { |
|
357 } |
|
358 QCOMPARE( vector.at(7).value(), 7 ); |
|
359 QCOMPARE( vector.at(8).value(), 8 ); |
|
360 QCOMPARE( vector.size(), 10 ); |
|
361 |
|
362 try { |
|
363 throwType = ThrowAtCopy; |
|
364 vector3 = vector; |
|
365 } catch (...) { |
|
366 } |
|
367 QCOMPARE( vector.at(0).value(), 0 ); |
|
368 QCOMPARE( vector.at(7).value(), 7 ); |
|
369 QCOMPARE( vector.size(), 10 ); |
|
370 QCOMPARE( vector3.at(0).value(), 0 ); |
|
371 QCOMPARE( vector3.at(7).value(), 7 ); |
|
372 QCOMPARE( vector3.size(), 10 ); |
|
373 |
|
374 try { |
|
375 throwType = ThrowAtCopy; |
|
376 vector3.append( FlexibleThrowerSmall(11) ); |
|
377 } catch (...) { |
|
378 } |
|
379 QCOMPARE( vector.at(0).value(), 0 ); |
|
380 QCOMPARE( vector.at(7).value(), 7 ); |
|
381 QCOMPARE( vector.size(), 10 ); |
|
382 QCOMPARE( vector3.at(0).value(), 0 ); |
|
383 QCOMPARE( vector3.at(7).value(), 7 ); |
|
384 |
|
385 try { |
|
386 vector2.clear(); |
|
387 vector2.append( FlexibleThrowerSmall(11)); |
|
388 throwType = ThrowAtCopy; |
|
389 vector3 = vector+vector2; |
|
390 } catch (...) { |
|
391 } |
|
392 QCOMPARE( vector.at(0).value(), 0 ); |
|
393 QCOMPARE( vector.at(7).value(), 7 ); |
|
394 QCOMPARE( vector.size(), 10 ); |
|
395 |
|
396 // check that copy on write works atomar |
|
397 vector2.clear(); |
|
398 vector2.append( FlexibleThrowerSmall(11)); |
|
399 vector3 = vector+vector2; |
|
400 try { |
|
401 throwType = ThrowAtCreate; |
|
402 vector3[7]=FlexibleThrowerSmall(12); |
|
403 } catch (...) { |
|
404 } |
|
405 QCOMPARE( vector.at(7).value(), 7 ); |
|
406 QCOMPARE( vector.size(), 10 ); |
|
407 QCOMPARE( vector3.at(7).value(), 7 ); |
|
408 QCOMPARE( vector3.size(), 11 ); |
|
409 |
|
410 try { |
|
411 throwType = ThrowAtCreate; |
|
412 vector.resize(15); |
|
413 } catch (...) { |
|
414 } |
|
415 QCOMPARE( vector.at(7).value(), 7 ); |
|
416 QCOMPARE( vector.size(), 10 ); |
|
417 |
|
418 try { |
|
419 throwType = ThrowAtCreate; |
|
420 vector.resize(15); |
|
421 } catch (...) { |
|
422 } |
|
423 QCOMPARE( vector.at(7).value(), 7 ); |
|
424 QCOMPARE( vector.size(), 10 ); |
|
425 |
|
426 try { |
|
427 throwType = ThrowLater; |
|
428 vector.fill(FlexibleThrowerSmall(1), 15); |
|
429 } catch (...) { |
|
430 } |
|
431 QCOMPARE( vector.at(0).value(), 0 ); |
|
432 QCOMPARE( vector.size(), 10 ); |
|
433 |
|
434 |
|
435 } |
|
436 QCOMPARE(objCounter, 0 ); // check that every object has been freed |
|
437 } |
|
438 |
|
439 |
|
440 void tst_ExceptionSafety::exceptionMap() { |
|
441 |
|
442 { |
|
443 MyMap map; |
|
444 MyMap map2; |
|
445 MyMap map3; |
|
446 |
|
447 throwType = ThrowNot; |
|
448 for (int i = 0; i<10; i++) |
|
449 map[ FlexibleThrowerSmall(i) ] = FlexibleThrowerSmall(i); |
|
450 |
|
451 return; // further test are deactivated until Map is fixed. |
|
452 |
|
453 for( int i = ThrowAtCopy; i<=ThrowAtComparison; i++ ) { |
|
454 try { |
|
455 throwType = (ThrowType)i; |
|
456 map[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); |
|
457 } catch(...) { |
|
458 } |
|
459 QCOMPARE( map.size(), 10 ); |
|
460 QCOMPARE( map[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); |
|
461 } |
|
462 |
|
463 map2 = map; |
|
464 try { |
|
465 throwType = ThrowLater; |
|
466 map2[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); |
|
467 } catch(...) { |
|
468 } |
|
469 /* qDebug("%d %d", map.size(), map2.size() ); |
|
470 for( int i=0; i<map.size(); i++ ) |
|
471 qDebug( "Value at %d: %d",i, map.value(FlexibleThrowerSmall(i), FlexibleThrowerSmall()).value() ); |
|
472 QCOMPARE( map.value(FlexibleThrowerSmall(1), FlexibleThrowerSmall()), FlexibleThrowerSmall(1) ); |
|
473 qDebug( "Value at %d: %d",1, map[FlexibleThrowerSmall(1)].value() ); |
|
474 qDebug("%d %d", map.size(), map2.size() ); |
|
475 */ |
|
476 QCOMPARE( map[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); |
|
477 QCOMPARE( map.size(), 10 ); |
|
478 QCOMPARE( map2[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); |
|
479 QCOMPARE( map2.size(), 10 ); |
|
480 |
|
481 } |
|
482 QCOMPARE(objCounter, 0 ); // check that every object has been freed |
|
483 } |
|
484 |
|
485 void tst_ExceptionSafety::exceptionHash() { |
|
486 |
|
487 { |
|
488 MyHash hash; |
|
489 MyHash hash2; |
|
490 MyHash hash3; |
|
491 |
|
492 for( int i = 0; i<10; i++ ) |
|
493 hash[ FlexibleThrowerSmall(i) ] = FlexibleThrowerSmall(i); |
|
494 |
|
495 for( int i = ThrowAtCopy; i<=ThrowAtComparison; i++ ) { |
|
496 try { |
|
497 throwType = (ThrowType)i; |
|
498 hash[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); |
|
499 } catch(...) { |
|
500 } |
|
501 QCOMPARE( hash.size(), 10 ); |
|
502 } |
|
503 |
|
504 hash2 = hash; |
|
505 try { |
|
506 throwType = ThrowLater; |
|
507 hash2[ FlexibleThrowerSmall(10) ] = FlexibleThrowerSmall(10); |
|
508 } catch(...) { |
|
509 } |
|
510 QCOMPARE( hash[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); |
|
511 QCOMPARE( hash.size(), 10 ); |
|
512 QCOMPARE( hash2[ FlexibleThrowerSmall(1) ], FlexibleThrowerSmall(1) ); |
|
513 QCOMPARE( hash2.size(), 10 ); |
|
514 |
|
515 hash2.clear(); |
|
516 try { |
|
517 throwType = ThrowLater; |
|
518 hash2.reserve(30); |
|
519 } catch(...) { |
|
520 } |
|
521 QCOMPARE( hash2.size(), 0 ); |
|
522 |
|
523 /* |
|
524 try { |
|
525 throwType = ThrowAtCopy; |
|
526 hash.prepend( FlexibleThrowerSmall(10)); |
|
527 } catch (...) { |
|
528 } |
|
529 QCOMPARE( hash.at(0).value(), 0 ); |
|
530 QCOMPARE( hash.size(), 10 ); |
|
531 |
|
532 try { |
|
533 throwType = ThrowAtCopy; |
|
534 hash.insert( 8, FlexibleThrowerSmall(10)); |
|
535 } catch (...) { |
|
536 } |
|
537 QCOMPARE( hash.at(7).value(), 7 ); |
|
538 QCOMPARE( hash.at(8).value(), 8 ); |
|
539 QCOMPARE( hash.size(), 10 ); |
|
540 |
|
541 qDebug("val"); |
|
542 try { |
|
543 throwType = ThrowAtCopy; |
|
544 hash3 = hash; |
|
545 } catch (...) { |
|
546 } |
|
547 QCOMPARE( hash.at(0).value(), 0 ); |
|
548 QCOMPARE( hash.at(7).value(), 7 ); |
|
549 QCOMPARE( hash.size(), 10 ); |
|
550 QCOMPARE( hash3.at(0).value(), 0 ); |
|
551 QCOMPARE( hash3.at(7).value(), 7 ); |
|
552 QCOMPARE( hash3.size(), 10 ); |
|
553 |
|
554 try { |
|
555 throwType = ThrowAtCopy; |
|
556 hash3.append( FlexibleThrowerSmall(11) ); |
|
557 } catch (...) { |
|
558 } |
|
559 QCOMPARE( hash.at(0).value(), 0 ); |
|
560 QCOMPARE( hash.at(7).value(), 7 ); |
|
561 QCOMPARE( hash.size(), 10 ); |
|
562 QCOMPARE( hash3.at(0).value(), 0 ); |
|
563 QCOMPARE( hash3.at(7).value(), 7 ); |
|
564 QCOMPARE( hash3.at(11).value(), 11 ); |
|
565 |
|
566 try { |
|
567 hash2.clear(); |
|
568 hash2.append( FlexibleThrowerSmall(11)); |
|
569 throwType = ThrowAtCopy; |
|
570 hash3 = hash+hash2; |
|
571 } catch (...) { |
|
572 } |
|
573 QCOMPARE( hash.at(0).value(), 0 ); |
|
574 QCOMPARE( hash.at(7).value(), 7 ); |
|
575 QCOMPARE( hash.size(), 10 ); |
|
576 |
|
577 // check that copy on write works atomar |
|
578 hash2.clear(); |
|
579 hash2.append( FlexibleThrowerSmall(11)); |
|
580 hash3 = hash+hash2; |
|
581 try { |
|
582 throwType = ThrowAtCopy; |
|
583 hash3[7]=FlexibleThrowerSmall(12); |
|
584 } catch (...) { |
|
585 } |
|
586 QCOMPARE( hash.at(7).value(), 7 ); |
|
587 QCOMPARE( hash.size(), 10 ); |
|
588 QCOMPARE( hash3.at(7).value(), 7 ); |
|
589 QCOMPARE( hash3.size(), 11 ); |
|
590 */ |
|
591 |
|
592 |
|
593 } |
|
594 QCOMPARE(objCounter, 0 ); // check that every object has been freed |
|
595 } |
|
596 |
|
597 // Disable these tests until the level of exception safety in event loops is clear |
|
598 #if 0 |
|
599 enum |
|
600 { |
|
601 ThrowEventId = QEvent::User + 42, |
|
602 NoThrowEventId = QEvent::User + 43 |
|
603 }; |
|
604 |
|
605 class ThrowEvent : public QEvent |
|
606 { |
|
607 public: |
|
608 ThrowEvent() |
|
609 : QEvent(static_cast<QEvent::Type>(ThrowEventId)) |
|
610 { |
|
611 } |
|
612 }; |
|
613 |
|
614 class NoThrowEvent : public QEvent |
|
615 { |
|
616 public: |
|
617 NoThrowEvent() |
|
618 : QEvent(static_cast<QEvent::Type>(NoThrowEventId)) |
|
619 {} |
|
620 }; |
|
621 |
|
622 struct IntEx : public std::exception |
|
623 { |
|
624 IntEx(int aEx) : ex(aEx) {} |
|
625 int ex; |
|
626 }; |
|
627 |
|
628 class TestObject : public QObject |
|
629 { |
|
630 public: |
|
631 TestObject() |
|
632 : throwEventCount(0), noThrowEventCount(0) {} |
|
633 |
|
634 int throwEventCount; |
|
635 int noThrowEventCount; |
|
636 |
|
637 protected: |
|
638 bool event(QEvent *event) |
|
639 { |
|
640 if (int(event->type()) == ThrowEventId) { |
|
641 throw IntEx(++throwEventCount); |
|
642 } else if (int(event->type()) == NoThrowEventId) { |
|
643 ++noThrowEventCount; |
|
644 } |
|
645 return QObject::event(event); |
|
646 } |
|
647 }; |
|
648 |
|
649 void tst_ExceptionSafety::exceptionEventLoop() |
|
650 { |
|
651 // send an event that throws |
|
652 TestObject obj; |
|
653 ThrowEvent throwEvent; |
|
654 try { |
|
655 qApp->sendEvent(&obj, &throwEvent); |
|
656 } catch (IntEx code) { |
|
657 QCOMPARE(code.ex, 1); |
|
658 } |
|
659 QCOMPARE(obj.throwEventCount, 1); |
|
660 |
|
661 // post an event that throws |
|
662 qApp->postEvent(&obj, new ThrowEvent); |
|
663 |
|
664 try { |
|
665 qApp->processEvents(); |
|
666 } catch (IntEx code) { |
|
667 QCOMPARE(code.ex, 2); |
|
668 } |
|
669 QCOMPARE(obj.throwEventCount, 2); |
|
670 |
|
671 // post a normal event, then a throwing event, then a normal event |
|
672 // run this in valgrind to ensure that it doesn't leak. |
|
673 |
|
674 qApp->postEvent(&obj, new NoThrowEvent); |
|
675 qApp->postEvent(&obj, new ThrowEvent); |
|
676 qApp->postEvent(&obj, new NoThrowEvent); |
|
677 |
|
678 try { |
|
679 qApp->processEvents(); |
|
680 } catch (IntEx code) { |
|
681 QCOMPARE(code.ex, 3); |
|
682 } |
|
683 // here, we should have received on non-throwing event and one throwing one |
|
684 QCOMPARE(obj.throwEventCount, 3); |
|
685 #ifndef __SYMBIAN32__ |
|
686 // symbian event loops will have absorbed the exceptions |
|
687 QCOMPARE(obj.noThrowEventCount, 1); |
|
688 #endif |
|
689 |
|
690 // spin the event loop again |
|
691 qApp->processEvents(); |
|
692 |
|
693 // now, we should have received the second non-throwing event |
|
694 QCOMPARE(obj.noThrowEventCount, 2); |
|
695 } |
|
696 |
|
697 void tst_ExceptionSafety::exceptionSignalSlot() |
|
698 { |
|
699 Emitter e; |
|
700 ExceptionThrower thrower; |
|
701 Receiver r1; |
|
702 Receiver r2; |
|
703 |
|
704 // connect a signal to a normal object, a thrower and a normal object again |
|
705 connect(&e, SIGNAL(testSignal()), &r1, SLOT(receiver())); |
|
706 connect(&e, SIGNAL(testSignal()), &thrower, SLOT(thrower())); |
|
707 connect(&e, SIGNAL(testSignal()), &r2, SLOT(receiver())); |
|
708 |
|
709 int code = 0; |
|
710 try { |
|
711 e.emitTestSignal(); |
|
712 } catch (int c) { |
|
713 code = c; |
|
714 } |
|
715 |
|
716 // 5 is the magic number that's thrown by thrower |
|
717 QCOMPARE(code, 5); |
|
718 |
|
719 // assumption: slots are called in the connection order |
|
720 QCOMPARE(r1.received, 1); |
|
721 QCOMPARE(r2.received, 0); |
|
722 } |
|
723 #endif |
|
724 |
|
725 QTEST_MAIN(tst_ExceptionSafety) |
|
726 #include "tst_exceptionsafety.moc" |
|
727 #endif // QT_NO_EXCEPTIONS |