tests/auto/exceptionsafety/tst_exceptionsafety.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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