tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.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 #include <QtGui/QtGui>
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <stddef.h>
       
    46 
       
    47 QT_USE_NAMESPACE
       
    48 
       
    49 // this test only works with
       
    50 //   * GLIBC
       
    51 //   * MSVC - only debug builds (we need the crtdbg.h helpers)
       
    52 //   * SYMBIAN
       
    53 #if (defined(QT_NO_EXCEPTIONS) || (!defined(__GLIBC__) && !defined(Q_CC_MSVC) && !defined(Q_OS_SYMBIAN))) && !defined(Q_MOC_RUN)
       
    54     QTEST_NOOP_MAIN
       
    55 #else
       
    56 
       
    57 #include "oomsimulator.h"
       
    58 #if !defined(Q_OS_SYMBIAN)
       
    59 #include "3rdparty/memcheck.h"
       
    60 #endif
       
    61 
       
    62 class tst_ExceptionSafetyObjects: public QObject
       
    63 {
       
    64     Q_OBJECT
       
    65 
       
    66 public slots:
       
    67     void initTestCase();
       
    68     void cleanupTestCase();
       
    69 
       
    70 private slots:
       
    71     void objects_data();
       
    72     void objects();
       
    73 
       
    74     void widgets_data();
       
    75     void widgets();
       
    76 
       
    77     void vector_data();
       
    78     void vector();
       
    79 
       
    80     void list_data();
       
    81     void list();
       
    82 
       
    83     void linkedList_data();
       
    84     void linkedList();
       
    85 
       
    86 private:
       
    87     static QtMsgHandler testMessageHandler;
       
    88     static void safeMessageHandler(QtMsgType, const char *);
       
    89 };
       
    90 
       
    91 // helper structs to create an arbitrary widget
       
    92 struct AbstractTester
       
    93 {
       
    94     virtual void operator()(QObject *parent) = 0;
       
    95 };
       
    96 Q_DECLARE_METATYPE(AbstractTester *)
       
    97 
       
    98 typedef void (*TestFunction)(QObject*);
       
    99 Q_DECLARE_METATYPE(TestFunction)
       
   100 
       
   101 template <typename T>
       
   102 struct ObjectCreator : public AbstractTester
       
   103 {
       
   104     void operator()(QObject *)
       
   105     {
       
   106         QScopedPointer<T> ptr(new T);
       
   107     }
       
   108 };
       
   109 
       
   110 struct BitArrayCreator : public AbstractTester
       
   111 {
       
   112     void operator()(QObject *)
       
   113     { QScopedPointer<QBitArray> bitArray(new QBitArray(100, true)); }
       
   114 };
       
   115 
       
   116 struct ByteArrayMatcherCreator : public AbstractTester
       
   117 {
       
   118     void operator()(QObject *)
       
   119     { QScopedPointer<QByteArrayMatcher> ptr(new QByteArrayMatcher("ralf test",8)); }
       
   120 };
       
   121 
       
   122 struct CryptographicHashCreator : public AbstractTester
       
   123 {
       
   124     void operator()(QObject *)
       
   125     {
       
   126         QScopedPointer<QCryptographicHash> ptr(new QCryptographicHash(QCryptographicHash::Sha1));
       
   127         ptr->addData("ralf test",8);
       
   128     }
       
   129 };
       
   130 
       
   131 struct DataStreamCreator : public AbstractTester
       
   132 {
       
   133     void operator()(QObject *)
       
   134     {
       
   135         QScopedPointer<QByteArray> arr(new QByteArray("hallo, test"));
       
   136         QScopedPointer<QDataStream> ptr(new QDataStream(arr.data(), QIODevice::ReadWrite));
       
   137         ptr->writeBytes("ralf test",8);
       
   138     }
       
   139 };
       
   140 
       
   141 struct DirCreator : public AbstractTester
       
   142 {
       
   143     void operator()(QObject *)
       
   144     {
       
   145         QDir::cleanPath("../////././");
       
   146         QScopedPointer<QDir> ptr(new QDir("."));
       
   147         while( ptr->cdUp() )
       
   148             ; // just going up
       
   149         ptr->count();
       
   150         ptr->exists(ptr->path());
       
   151 
       
   152         QStringList filters;
       
   153         filters << "*.cpp" << "*.cxx" << "*.cc";
       
   154         ptr->setNameFilters(filters);
       
   155     }
       
   156 };
       
   157 
       
   158 void tst_ExceptionSafetyObjects::objects_data()
       
   159 {
       
   160     QTest::addColumn<AbstractTester *>("objectCreator");
       
   161 
       
   162 #define NEWROW(T) QTest::newRow(#T) << static_cast<AbstractTester *>(new ObjectCreator<T >)
       
   163     NEWROW(QObject);
       
   164     NEWROW(QBuffer);
       
   165     NEWROW(QFile);
       
   166     NEWROW(QProcess);
       
   167     NEWROW(QSettings);
       
   168     NEWROW(QThread);
       
   169     NEWROW(QThreadPool);
       
   170     NEWROW(QTranslator);
       
   171     NEWROW(QFSFileEngine);
       
   172 
       
   173 #define NEWROW2(T, CREATOR) QTest::newRow(#T) << static_cast<AbstractTester *>(new CREATOR)
       
   174     NEWROW2(QBitArray, BitArrayCreator);
       
   175     NEWROW2(QByteArrayMatcher, ByteArrayMatcherCreator);
       
   176     NEWROW2(QCryptographicHash, CryptographicHashCreator);
       
   177     NEWROW2(QDataStream, DataStreamCreator);
       
   178     NEWROW2(QDir, DirCreator);
       
   179 
       
   180 }
       
   181 
       
   182 // create and destructs an object, and lets each and every allocation
       
   183 // during construction and destruction fail.
       
   184 template <typename T>
       
   185 static void doOOMTest(T &testFunc, QObject *parent, int start=0)
       
   186 {
       
   187     int currentOOMIndex = start;
       
   188     bool caught = false;
       
   189     bool done = false;
       
   190 
       
   191     AllocFailer allocFailer(0);
       
   192     int allocCountBefore = allocFailer.currentAllocIndex();
       
   193 
       
   194     do {
       
   195         allocFailer.reactivateAt(++currentOOMIndex);
       
   196 
       
   197         caught = false;
       
   198 
       
   199         try {
       
   200             testFunc(parent);
       
   201         } catch (const std::bad_alloc &) {
       
   202             caught = true;
       
   203         } catch (const std::exception &ex) {
       
   204             if (strcmp(ex.what(), "autotest swallow") != 0)
       
   205                 throw;
       
   206             caught = true;
       
   207         }
       
   208 
       
   209         if (!caught) {
       
   210             void *buf = malloc(42);
       
   211             if (buf) {
       
   212                 // we got memory here - oom test is over.
       
   213                 free(buf);
       
   214                 done = true;
       
   215             }
       
   216         }
       
   217 
       
   218         // if we get a FAIL, stop executing now
       
   219         if (QTest::currentTestFailed())
       
   220             done = true;
       
   221 
       
   222 //#define REALLY_VERBOSE
       
   223 #ifdef REALLY_VERBOSE
       
   224     fprintf(stderr, " OOM Index: %d\n", currentOOMIndex);
       
   225 #endif
       
   226 
       
   227 
       
   228     } while (caught || !done);
       
   229 
       
   230     allocFailer.deactivate();
       
   231 
       
   232 //#define VERBOSE
       
   233 #ifdef VERBOSE
       
   234     fprintf(stderr, "OOM Test done, checked allocs: %d (range %d - %d)\n", currentOOMIndex,
       
   235                 allocCountBefore, allocFailer.currentAllocIndex());
       
   236 #else
       
   237     Q_UNUSED(allocCountBefore);
       
   238 #endif
       
   239 }
       
   240 
       
   241 static int alloc1Failed = 0;
       
   242 static int alloc2Failed = 0;
       
   243 static int alloc3Failed = 0;
       
   244 static int alloc4Failed = 0;
       
   245 static int malloc1Failed = 0;
       
   246 static int malloc2Failed = 0;
       
   247 
       
   248 // Tests that new, new[] and malloc() fail at least once during OOM testing.
       
   249 class SelfTestObject : public QObject
       
   250 {
       
   251 public:
       
   252     SelfTestObject(QObject *parent = 0)
       
   253         : QObject(parent)
       
   254     {
       
   255         try { delete new int; } catch (const std::bad_alloc &) { ++alloc1Failed; throw; }
       
   256         try { delete [] new double[5]; } catch (const std::bad_alloc &) { ++alloc2Failed; throw ;}
       
   257         void *buf = malloc(42);
       
   258         if (buf)
       
   259             free(buf);
       
   260         else
       
   261             ++malloc1Failed;
       
   262     }
       
   263 
       
   264     ~SelfTestObject()
       
   265     {
       
   266         try { delete new int; } catch (const std::bad_alloc &) { ++alloc3Failed; }
       
   267         try { delete [] new double[5]; } catch (const std::bad_alloc &) { ++alloc4Failed; }
       
   268         void *buf = malloc(42);
       
   269         if (buf)
       
   270             free(buf);
       
   271         else
       
   272             ++malloc2Failed = true;
       
   273     }
       
   274 };
       
   275 
       
   276 QtMsgHandler tst_ExceptionSafetyObjects::testMessageHandler;
       
   277 
       
   278 void tst_ExceptionSafetyObjects::safeMessageHandler(QtMsgType type, const char *msg)
       
   279 {
       
   280     // this temporarily suspends OOM testing while handling a message
       
   281     int currentIndex = mallocFailIndex;
       
   282     AllocFailer allocFailer(0);
       
   283     allocFailer.deactivate();
       
   284     (*testMessageHandler)(type, msg);
       
   285     allocFailer.reactivateAt(currentIndex);
       
   286 }
       
   287 
       
   288 void tst_ExceptionSafetyObjects::initTestCase()
       
   289 {
       
   290     testMessageHandler = qInstallMsgHandler(safeMessageHandler);
       
   291 
       
   292     QVERIFY(AllocFailer::initialize());
       
   293 
       
   294     // sanity check whether OOM simulation works
       
   295     AllocFailer allocFailer(0);
       
   296 
       
   297     // malloc fail index is 0 -> this malloc should fail.
       
   298     void *buf = malloc(42);
       
   299     allocFailer.deactivate();
       
   300     QVERIFY(!buf);
       
   301 
       
   302     // malloc fail index is 1 - second malloc should fail.
       
   303     allocFailer.reactivateAt(1);
       
   304     buf = malloc(42);
       
   305     void *buf2 = malloc(42);
       
   306     allocFailer.deactivate();
       
   307 
       
   308     QVERIFY(buf);
       
   309     free(buf);
       
   310     QVERIFY(!buf2);
       
   311 
       
   312 #ifdef Q_OS_SYMBIAN
       
   313     // temporary workaround for INC138398
       
   314     std::new_handler nh_func = std::set_new_handler(0);
       
   315     (void) std::set_new_handler(nh_func);
       
   316 #endif
       
   317 
       
   318     ObjectCreator<SelfTestObject> *selfTest = new ObjectCreator<SelfTestObject>;
       
   319     doOOMTest(*selfTest, 0);
       
   320     delete selfTest;
       
   321     QCOMPARE(alloc1Failed, 1);
       
   322     QCOMPARE(alloc2Failed, 1);
       
   323     QCOMPARE(alloc3Failed, 2);
       
   324     QCOMPARE(alloc4Failed, 3);
       
   325     QCOMPARE(malloc1Failed, 1);
       
   326     QCOMPARE(malloc2Failed, 1);
       
   327 }
       
   328 
       
   329 void tst_ExceptionSafetyObjects::cleanupTestCase()
       
   330 {
       
   331     qInstallMsgHandler(testMessageHandler);
       
   332 }
       
   333 
       
   334 void tst_ExceptionSafetyObjects::objects()
       
   335 {
       
   336     QFETCH(AbstractTester *, objectCreator);
       
   337 
       
   338     doOOMTest(*objectCreator, 0);
       
   339     
       
   340     delete objectCreator;
       
   341 }
       
   342 
       
   343 template <typename T>
       
   344 struct WidgetCreator : public AbstractTester
       
   345 {
       
   346     void operator()(QObject *parent)
       
   347     {
       
   348         Q_ASSERT(!parent || parent->isWidgetType());
       
   349         QScopedPointer<T> ptr(parent ? new T(static_cast<QWidget *>(parent)) : new T);
       
   350     }
       
   351 };
       
   352 
       
   353 // QSizeGrip doesn't have a default constructor - always pass parent (even though it might be 0)
       
   354 template <> struct WidgetCreator<QSizeGrip> : public AbstractTester
       
   355 {
       
   356     void operator()(QObject *parent)
       
   357     {
       
   358         Q_ASSERT(!parent || parent->isWidgetType());
       
   359         QScopedPointer<QSizeGrip> ptr(new QSizeGrip(static_cast<QWidget *>(parent)));
       
   360     }
       
   361 };
       
   362 
       
   363 // QDesktopWidget doesn't need a parent.
       
   364 template <> struct WidgetCreator<QDesktopWidget> : public AbstractTester
       
   365 {
       
   366     void operator()(QObject *parent)
       
   367     {
       
   368         Q_ASSERT(!parent || parent->isWidgetType());
       
   369         QScopedPointer<QDesktopWidget> ptr(new QDesktopWidget());
       
   370     }
       
   371 };
       
   372 void tst_ExceptionSafetyObjects::widgets_data()
       
   373 {
       
   374 #ifdef Q_OS_SYMBIAN
       
   375     // Initialise the S60 rasteriser, which crashes if started while out of memory
       
   376     QImage image(20, 20, QImage::Format_RGB32); 
       
   377     QPainter p(&image); 
       
   378     p.drawText(0, 15, "foo"); 
       
   379 #endif
       
   380 
       
   381     QTest::addColumn<AbstractTester *>("widgetCreator");
       
   382 
       
   383 #undef NEWROW
       
   384 #define NEWROW(T) QTest::newRow(#T) << static_cast<AbstractTester *>(new WidgetCreator<T >)
       
   385 
       
   386     NEWROW(QWidget);
       
   387 
       
   388     NEWROW(QButtonGroup);
       
   389     NEWROW(QDesktopWidget);
       
   390     NEWROW(QCheckBox);
       
   391     NEWROW(QComboBox);
       
   392     NEWROW(QCommandLinkButton);
       
   393     NEWROW(QDateEdit);
       
   394     NEWROW(QDateTimeEdit);
       
   395     NEWROW(QDial);
       
   396     NEWROW(QDoubleSpinBox);
       
   397     NEWROW(QFocusFrame);
       
   398     NEWROW(QFontComboBox);
       
   399     NEWROW(QFrame);
       
   400     NEWROW(QGroupBox);
       
   401     NEWROW(QLCDNumber);
       
   402     NEWROW(QLabel);
       
   403     NEWROW(QLCDNumber);
       
   404     NEWROW(QLineEdit);
       
   405     NEWROW(QMenu);
       
   406     NEWROW(QPlainTextEdit);
       
   407     NEWROW(QProgressBar);
       
   408     NEWROW(QPushButton);
       
   409     NEWROW(QRadioButton);
       
   410     NEWROW(QScrollArea);
       
   411     NEWROW(QScrollBar);
       
   412     NEWROW(QSizeGrip);
       
   413     NEWROW(QSlider);
       
   414     NEWROW(QSpinBox);
       
   415     NEWROW(QSplitter);
       
   416     NEWROW(QStackedWidget);
       
   417     NEWROW(QStatusBar);
       
   418     NEWROW(QTabBar);
       
   419     NEWROW(QTabWidget);
       
   420     NEWROW(QTextBrowser);
       
   421     NEWROW(QTextEdit);
       
   422     NEWROW(QTimeEdit);
       
   423     NEWROW(QToolBox);
       
   424     NEWROW(QToolButton);
       
   425     NEWROW(QStatusBar);
       
   426     NEWROW(QToolBar);
       
   427     NEWROW(QMenuBar);
       
   428     NEWROW(QMainWindow);
       
   429     NEWROW(QWorkspace);
       
   430     NEWROW(QColumnView);
       
   431     NEWROW(QListView);
       
   432     NEWROW(QListWidget);
       
   433     NEWROW(QTableView);
       
   434     NEWROW(QTableWidget);
       
   435     NEWROW(QTreeView);
       
   436     NEWROW(QTreeWidget);
       
   437 }
       
   438 
       
   439 void tst_ExceptionSafetyObjects::widgets()
       
   440 {
       
   441     QFETCH(AbstractTester *, widgetCreator);
       
   442 
       
   443     doOOMTest(*widgetCreator, 0, 00000);
       
   444 
       
   445     QWidget parent;
       
   446     doOOMTest(*widgetCreator, &parent, 00000);
       
   447 
       
   448     delete widgetCreator;
       
   449 
       
   450     // if the test reaches here without crashing, we passed :)
       
   451     QVERIFY(true);
       
   452 }
       
   453 
       
   454 struct Integer
       
   455 {
       
   456     Integer(int value = 42)
       
   457         : ptr(new int(value))
       
   458     {
       
   459         ++instanceCount;
       
   460     }
       
   461 
       
   462     Integer(const Integer &other)
       
   463         : ptr(new int(*other.ptr))
       
   464     {
       
   465         ++instanceCount;
       
   466     }
       
   467 
       
   468     Integer &operator=(const Integer &other)
       
   469     {
       
   470         int *newPtr = new int(*other.ptr);
       
   471         delete ptr;
       
   472         ptr = newPtr;
       
   473         return *this;
       
   474     }
       
   475 
       
   476     ~Integer()
       
   477     {
       
   478         --instanceCount;
       
   479         delete ptr;
       
   480     }
       
   481 
       
   482     int value() const
       
   483     {
       
   484         return *ptr;
       
   485     }
       
   486 
       
   487     int *ptr;
       
   488     static int instanceCount;
       
   489 };
       
   490 
       
   491 int Integer::instanceCount = 0;
       
   492 
       
   493 struct IntegerMoveable
       
   494     {
       
   495     IntegerMoveable(int value = 42)
       
   496         : val(value)
       
   497     {
       
   498         delete new int;
       
   499         ++instanceCount;
       
   500     }
       
   501 
       
   502     IntegerMoveable(const IntegerMoveable &other)
       
   503         : val(other.val)
       
   504     {
       
   505         delete new int;
       
   506         ++instanceCount;
       
   507     }
       
   508 
       
   509     IntegerMoveable &operator=(const IntegerMoveable &other)
       
   510     {
       
   511         delete new int;
       
   512         val = other.val;
       
   513         return *this;
       
   514     }
       
   515 
       
   516     ~IntegerMoveable()
       
   517     {
       
   518         --instanceCount;
       
   519     }
       
   520 
       
   521     int value() const
       
   522     {
       
   523         return val;
       
   524     }
       
   525 
       
   526     int val;
       
   527     static int instanceCount;
       
   528     };
       
   529 
       
   530 int IntegerMoveable::instanceCount = 0;
       
   531 Q_DECLARE_TYPEINFO(IntegerMoveable, Q_MOVABLE_TYPE);
       
   532 
       
   533 template <typename T, template<typename> class Container>
       
   534 void containerInsertTest(QObject*)
       
   535 {
       
   536     Container<T> container;
       
   537 
       
   538     // insert an item in an empty container
       
   539     try {
       
   540         container.insert(container.begin(), 41);
       
   541     } catch (...) {
       
   542         QVERIFY(container.isEmpty());
       
   543         QCOMPARE(T::instanceCount, 0);
       
   544         return;
       
   545     }
       
   546 
       
   547     QCOMPARE(container.size(), 1);
       
   548     QCOMPARE(T::instanceCount, 1);
       
   549 
       
   550     // insert an item before another item
       
   551     try {
       
   552         container.insert(container.begin(), 42);
       
   553     } catch (...) {
       
   554         QCOMPARE(container.size(), 1);
       
   555         QCOMPARE(container.first().value(), 41);
       
   556         QCOMPARE(T::instanceCount, 1);
       
   557         return;
       
   558     }
       
   559 
       
   560     QCOMPARE(T::instanceCount, 2);
       
   561 
       
   562     // insert an item in between
       
   563     try {
       
   564         container.insert(container.begin() + 1, 43);
       
   565     } catch (...) {
       
   566         QCOMPARE(container.size(), 2);
       
   567         QCOMPARE(container.first().value(), 41);
       
   568         QCOMPARE((container.begin() + 1)->value(), 42);
       
   569         QCOMPARE(T::instanceCount, 2);
       
   570         return;
       
   571     }
       
   572 
       
   573     QCOMPARE(T::instanceCount, 3);
       
   574 }
       
   575 
       
   576 template <typename T, template<typename> class Container>
       
   577 void containerAppendTest(QObject*)
       
   578 {
       
   579     Container<T> container;
       
   580 
       
   581     // append to an empty container
       
   582     try {
       
   583         container.append(42);
       
   584     } catch (...) {
       
   585         QCOMPARE(container.size(), 0);
       
   586         QCOMPARE(T::instanceCount, 0);
       
   587         return;
       
   588     }
       
   589 
       
   590     // append to a container with one item
       
   591     try {
       
   592         container.append(43);
       
   593     } catch (...) {
       
   594         QCOMPARE(container.size(), 1);
       
   595         QCOMPARE(container.first().value(), 42);
       
   596         QCOMPARE(T::instanceCount, 1);
       
   597         return;
       
   598     }
       
   599 
       
   600     Container<T> container2;
       
   601 
       
   602     try {
       
   603         container2.append(44);
       
   604     } catch (...) {
       
   605         // don't care
       
   606         return;
       
   607     }
       
   608     QCOMPARE(T::instanceCount, 3);
       
   609 
       
   610     // append another container with one item
       
   611     try {
       
   612         container += container2;
       
   613     } catch (...) {
       
   614         QCOMPARE(container.size(), 2);
       
   615         QCOMPARE(container.first().value(), 42);
       
   616         QCOMPARE((container.begin() + 1)->value(), 43);
       
   617         QCOMPARE(T::instanceCount, 3);
       
   618         return;
       
   619     }
       
   620 
       
   621     QCOMPARE(T::instanceCount, 4);
       
   622 }
       
   623 
       
   624 template <typename T, template<typename> class Container>
       
   625 void containerEraseTest(QObject*)
       
   626 {
       
   627     Container<T> container;
       
   628 
       
   629     try {
       
   630         container.append(42);
       
   631         container.append(43);
       
   632         container.append(44);
       
   633         container.append(45);
       
   634         container.append(46);
       
   635     } catch (...) {
       
   636         // don't care
       
   637         return;
       
   638     }
       
   639 
       
   640     // sanity checks
       
   641     QCOMPARE(container.size(), 5);
       
   642     QCOMPARE(T::instanceCount, 5);
       
   643 
       
   644     // delete the first one
       
   645     try {
       
   646         container.erase(container.begin());
       
   647     } catch (...) {
       
   648         QCOMPARE(container.size(), 5);
       
   649         QCOMPARE(container.first().value(), 42);
       
   650         QCOMPARE(T::instanceCount, 5);
       
   651         return;
       
   652     }
       
   653 
       
   654     QCOMPARE(container.size(), 4);
       
   655     QCOMPARE(container.first().value(), 43);
       
   656     QCOMPARE(T::instanceCount, 4);
       
   657 
       
   658     // delete the last one
       
   659     try {
       
   660         container.erase(container.end() - 1);
       
   661     } catch (...) {
       
   662         QCOMPARE(container.size(), 4);
       
   663         QCOMPARE(T::instanceCount, 4);
       
   664         return;
       
   665     }
       
   666 
       
   667     QCOMPARE(container.size(), 3);
       
   668     QCOMPARE(container.first().value(), 43);
       
   669     QCOMPARE((container.begin() + 1)->value(), 44);
       
   670     QCOMPARE((container.begin() + 2)->value(), 45);
       
   671     QCOMPARE(T::instanceCount, 3);
       
   672 
       
   673     // delete the middle one
       
   674     try {
       
   675         container.erase(container.begin() + 1);
       
   676     } catch (...) {
       
   677         QCOMPARE(container.size(), 3);
       
   678         QCOMPARE(container.first().value(), 43);
       
   679         QCOMPARE((container.begin() + 1)->value(), 44);
       
   680         QCOMPARE((container.begin() + 2)->value(), 45);
       
   681         QCOMPARE(T::instanceCount, 3);
       
   682         return;
       
   683     }
       
   684 
       
   685     QCOMPARE(container.size(), 2);
       
   686     QCOMPARE(container.first().value(), 43);
       
   687     QCOMPARE((container.begin() + 1)->value(), 45);
       
   688     QCOMPARE(T::instanceCount, 2);
       
   689 }
       
   690 
       
   691 template <template<typename T> class Container>
       
   692 static void containerData()
       
   693 {
       
   694     QTest::addColumn<TestFunction>("testFunction");
       
   695 
       
   696     QTest::newRow("insert static") << static_cast<TestFunction>(containerInsertTest<Integer, Container>);
       
   697     QTest::newRow("append static") << static_cast<TestFunction>(containerAppendTest<Integer, Container>);
       
   698     QTest::newRow("erase static") << static_cast<TestFunction>(containerEraseTest<Integer, Container>);
       
   699     QTest::newRow("insert moveable") << static_cast<TestFunction>(containerInsertTest<IntegerMoveable, Container>);
       
   700     QTest::newRow("append moveable") << static_cast<TestFunction>(containerAppendTest<IntegerMoveable, Container>);
       
   701     QTest::newRow("erase moveable") << static_cast<TestFunction>(containerEraseTest<IntegerMoveable, Container>);
       
   702 }
       
   703 
       
   704 void tst_ExceptionSafetyObjects::vector_data()
       
   705 {
       
   706     containerData<QVector>();
       
   707 }
       
   708 
       
   709 void tst_ExceptionSafetyObjects::vector()
       
   710 {
       
   711     QFETCH(TestFunction, testFunction);
       
   712 
       
   713     if (QLatin1String(QTest::currentDataTag()) == QLatin1String("insert static")
       
   714         || QLatin1String(QTest::currentDataTag()) == QLatin1String("insert moveable"))
       
   715         QSKIP("QVector::insert is currently not strongly exception safe", SkipSingle);
       
   716 
       
   717     doOOMTest(testFunction, 0);
       
   718 }
       
   719 
       
   720 void tst_ExceptionSafetyObjects::list_data()
       
   721 {
       
   722     containerData<QList>();
       
   723 }
       
   724 
       
   725 void tst_ExceptionSafetyObjects::list()
       
   726 {
       
   727     QFETCH(TestFunction, testFunction);
       
   728 
       
   729     doOOMTest(testFunction, 0);
       
   730 }
       
   731 
       
   732 void tst_ExceptionSafetyObjects::linkedList_data()
       
   733 {
       
   734     containerData<QLinkedList>();
       
   735 }
       
   736 
       
   737 void tst_ExceptionSafetyObjects::linkedList()
       
   738 {
       
   739     QFETCH(TestFunction, testFunction);
       
   740 
       
   741     doOOMTest(testFunction, 0);
       
   742 }
       
   743 
       
   744 QTEST_MAIN(tst_ExceptionSafetyObjects)
       
   745 #include "tst_exceptionsafety_objects.moc"
       
   746 #endif // QT_NO_EXCEPTIONS