From eaaf45c7b8b8d810bbd77e73b72771543dd31b1a Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Wed, 5 Aug 2009 16:25:34 +0200 Subject: refactor a bit, and add container testing --- .../tst_exceptionsafety_objects.cpp | 306 ++++++++++++++++++--- 1 file changed, 272 insertions(+), 34 deletions(-) (limited to 'tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp') diff --git a/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp b/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp index c2c06851b3..0a95e5aaa3 100644 --- a/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp +++ b/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp @@ -71,49 +71,60 @@ private slots: void widgets_data(); void widgets(); + + void vector_data(); + void vector(); + + void list_data(); + void list(); + + void linkedList_data(); + void linkedList(); }; // helper structs to create an arbitrary widget -struct AbstractObjectCreator +struct AbstractTester { - virtual void test(QObject *parent) = 0; + virtual void operator()(QObject *parent) = 0; }; +Q_DECLARE_METATYPE(AbstractTester *) -Q_DECLARE_METATYPE(AbstractObjectCreator *) +typedef void (*TestFunction)(QObject*); +Q_DECLARE_METATYPE(TestFunction) template -struct ObjectCreator : public AbstractObjectCreator +struct ObjectCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QScopedPointer ptr(new T); } }; -struct BitArrayCreator : public AbstractObjectCreator +struct BitArrayCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QScopedPointer bitArray(new QBitArray(100, true)); } }; -struct ByteArrayMatcherCreator : public AbstractObjectCreator +struct ByteArrayMatcherCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QScopedPointer ptr(new QByteArrayMatcher("ralf test",8)); } }; -struct CryptographicHashCreator : public AbstractObjectCreator +struct CryptographicHashCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QScopedPointer ptr(new QCryptographicHash(QCryptographicHash::Sha1)); ptr->addData("ralf test",8); } }; -struct DataStreamCreator : public AbstractObjectCreator +struct DataStreamCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QScopedPointer arr(new QByteArray("hallo, test")); QScopedPointer ptr(new QDataStream(arr.data(), QIODevice::ReadWrite)); @@ -121,9 +132,9 @@ struct DataStreamCreator : public AbstractObjectCreator } }; -struct DirCreator : public AbstractObjectCreator +struct DirCreator : public AbstractTester { - void test(QObject *) + void operator()(QObject *) { QDir::cleanPath("../////././"); QScopedPointer ptr(new QDir(".")); @@ -140,9 +151,9 @@ struct DirCreator : public AbstractObjectCreator void tst_ExceptionSafetyObjects::objects_data() { - QTest::addColumn("objectCreator"); + QTest::addColumn("objectCreator"); -#define NEWROW(T) QTest::newRow(#T) << static_cast(new ObjectCreator) +#define NEWROW(T) QTest::newRow(#T) << static_cast(new ObjectCreator) NEWROW(QObject); NEWROW(QBuffer); NEWROW(QFile); @@ -154,7 +165,7 @@ void tst_ExceptionSafetyObjects::objects_data() NEWROW(QTranslator); NEWROW(QFSFileEngine); -#define NEWROW2(T, CREATOR) QTest::newRow(#T) << static_cast(new CREATOR) +#define NEWROW2(T, CREATOR) QTest::newRow(#T) << static_cast(new CREATOR) NEWROW2(QBitArray, BitArrayCreator); NEWROW2(QByteArrayMatcher, ByteArrayMatcherCreator); NEWROW2(QCryptographicHash, CryptographicHashCreator); @@ -165,7 +176,8 @@ void tst_ExceptionSafetyObjects::objects_data() // create and destructs an object, and lets each and every allocation // during construction and destruction fail. -static void doOOMTest(AbstractObjectCreator *creator, QObject *parent, int start=0) +template +static void doOOMTest(T &testFunc, QObject *parent, int start=0) { int currentOOMIndex = start; bool caught = false; @@ -180,7 +192,7 @@ static void doOOMTest(AbstractObjectCreator *creator, QObject *parent, int start caught = false; try { - creator->test(parent); + testFunc(parent); } catch (const std::bad_alloc &) { caught = true; } catch (const std::exception &ex) { @@ -198,6 +210,10 @@ static void doOOMTest(AbstractObjectCreator *creator, QObject *parent, int start } } + // if we get a FAIL, stop executing now + if (QTest::currentTestFailed()) + done = true; + //#define REALLY_VERBOSE #ifdef REALLY_VERBOSE fprintf(stderr, " OOM Index: %d\n", currentOOMIndex); @@ -212,6 +228,8 @@ static void doOOMTest(AbstractObjectCreator *creator, QObject *parent, int start #ifdef VERBOSE fprintf(stderr, "OOM Test done, checked allocs: %d (range %d - %d)\n", currentOOMIndex, allocCountBefore, allocFailer.currentAllocIndex()); +#else + Q_UNUSED(allocCountBefore); #endif } @@ -279,7 +297,7 @@ void tst_ExceptionSafetyObjects::initTestCase() #endif ObjectCreator *selfTest = new ObjectCreator; - doOOMTest(selfTest, 0); + doOOMTest(*selfTest, 0); delete selfTest; QCOMPARE(alloc1Failed, 1); QCOMPARE(alloc2Failed, 1); @@ -291,17 +309,17 @@ void tst_ExceptionSafetyObjects::initTestCase() void tst_ExceptionSafetyObjects::objects() { - QFETCH(AbstractObjectCreator *, objectCreator); + QFETCH(AbstractTester *, objectCreator); - doOOMTest(objectCreator, 0); + doOOMTest(*objectCreator, 0); delete objectCreator; } template -struct WidgetCreator : public AbstractObjectCreator +struct WidgetCreator : public AbstractTester { - void test(QObject *parent) + void operator()(QObject *parent) { Q_ASSERT(!parent || parent->isWidgetType()); QScopedPointer ptr(parent ? new T(static_cast(parent)) : new T); @@ -309,9 +327,9 @@ struct WidgetCreator : public AbstractObjectCreator }; // QSizeGrip doesn't have a default constructor - always pass parent (even though it might be 0) -template <> struct WidgetCreator : public AbstractObjectCreator +template <> struct WidgetCreator : public AbstractTester { - void test(QObject *parent) + void operator()(QObject *parent) { Q_ASSERT(!parent || parent->isWidgetType()); QScopedPointer ptr(new QSizeGrip(static_cast(parent))); @@ -319,9 +337,9 @@ template <> struct WidgetCreator : public AbstractObjectCreator }; // QDesktopWidget doesn't need a parent. -template <> struct WidgetCreator : public AbstractObjectCreator +template <> struct WidgetCreator : public AbstractTester { - void test(QObject *parent) + void operator()(QObject *parent) { Q_ASSERT(!parent || parent->isWidgetType()); QScopedPointer ptr(new QDesktopWidget()); @@ -329,10 +347,10 @@ template <> struct WidgetCreator : public AbstractObjectCreator }; void tst_ExceptionSafetyObjects::widgets_data() { - QTest::addColumn("widgetCreator"); + QTest::addColumn("widgetCreator"); #undef NEWROW -#define NEWROW(T) QTest::newRow(#T) << static_cast(new WidgetCreator) +#define NEWROW(T) QTest::newRow(#T) << static_cast(new WidgetCreator) NEWROW(QWidget); @@ -393,12 +411,12 @@ void tst_ExceptionSafetyObjects::widgets_data() void tst_ExceptionSafetyObjects::widgets() { - QFETCH(AbstractObjectCreator *, widgetCreator); + QFETCH(AbstractTester *, widgetCreator); - doOOMTest(widgetCreator, 0, 00000); + doOOMTest(*widgetCreator, 0, 00000); QWidget parent; - doOOMTest(widgetCreator, &parent, 00000); + doOOMTest(*widgetCreator, &parent, 00000); delete widgetCreator; @@ -406,6 +424,226 @@ void tst_ExceptionSafetyObjects::widgets() QVERIFY(true); } +struct Integer +{ + Integer(int value = 42) + : ptr(new int(value)) + { + ++instanceCount; + } + + Integer(const Integer &other) + : ptr(new int(*other.ptr)) + { + ++instanceCount; + } + + Integer &operator=(const Integer &other) + { + int *newPtr = new int(*other.ptr); + delete ptr; + ptr = newPtr; + return *this; + } + + ~Integer() + { + --instanceCount; + delete ptr; + } + + int value() const + { + return *ptr; + } + + int *ptr; + static int instanceCount; +}; + +int Integer::instanceCount = 0; + +template class Container> +void containerInsertTest(QObject*) +{ + Container container; + + // insert an item in an empty container + try { + container.insert(container.begin(), 41); + } catch (...) { + QVERIFY(container.isEmpty()); + QCOMPARE(Integer::instanceCount, 0); + return; + } + + QCOMPARE(container.size(), 1); + QCOMPARE(Integer::instanceCount, 1); + + // insert an item before another item + try { + container.insert(container.begin(), 42); + } catch (...) { + QCOMPARE(container.size(), 1); + QCOMPARE(container.first().value(), 41); + QCOMPARE(Integer::instanceCount, 1); + return; + } + + QCOMPARE(Integer::instanceCount, 2); + + // insert an item in between + try { + container.insert(container.begin() + 1, 43); + } catch (...) { + QCOMPARE(container.size(), 2); + QCOMPARE(container.first().value(), 41); + QCOMPARE((container.begin() + 1)->value(), 42); + QCOMPARE(Integer::instanceCount, 2); + return; + } + + QCOMPARE(Integer::instanceCount, 3); +} + +template class Container> +void containerAppendTest(QObject*) +{ + Container container; + + // append to an empty container + try { + container.append(42); + } catch (...) { + QCOMPARE(container.size(), 0); + QCOMPARE(Integer::instanceCount, 0); + return; + } + + // append to a container with one item + try { + container.append(43); + } catch (...) { + QCOMPARE(container.size(), 1); + QCOMPARE(container.first().value(), 42); + QCOMPARE(Integer::instanceCount, 1); + return; + } +} + +template class Container> +void containerEraseTest(QObject*) +{ + Container container; + + try { + container.append(42); + container.append(43); + container.append(44); + container.append(45); + container.append(46); + } catch (...) { + // don't care + return; + } + + // sanity checks + QCOMPARE(container.size(), 5); + QCOMPARE(Integer::instanceCount, 5); + + // delete the first one + try { + container.erase(container.begin()); + } catch (...) { + QCOMPARE(container.size(), 5); + QCOMPARE(container.first().value(), 42); + QCOMPARE(Integer::instanceCount, 5); + return; + } + + QCOMPARE(container.size(), 4); + QCOMPARE(container.first().value(), 43); + QCOMPARE(Integer::instanceCount, 4); + + // delete the last one + try { + container.erase(container.end() - 1); + } catch (...) { + QCOMPARE(container.size(), 4); + QCOMPARE(Integer::instanceCount, 4); + return; + } + + QCOMPARE(container.size(), 3); + QCOMPARE(container.first().value(), 43); + QCOMPARE((container.begin() + 1)->value(), 44); + QCOMPARE((container.begin() + 2)->value(), 45); + QCOMPARE(Integer::instanceCount, 3); + + // delete the middle one + try { + container.erase(container.begin() + 1); + } catch (...) { + QCOMPARE(container.size(), 3); + QCOMPARE(container.first().value(), 43); + QCOMPARE((container.begin() + 1)->value(), 44); + QCOMPARE((container.begin() + 2)->value(), 45); + QCOMPARE(Integer::instanceCount, 3); + return; + } + + QCOMPARE(container.size(), 2); + QCOMPARE(container.first().value(), 43); + QCOMPARE((container.begin() + 1)->value(), 45); + QCOMPARE(Integer::instanceCount, 2); +} + +template class Container> +static void containerData() +{ + QTest::addColumn("testFunction"); + + QTest::newRow("insert") << static_cast(containerInsertTest); + QTest::newRow("append") << static_cast(containerAppendTest); + QTest::newRow("erase") << static_cast(containerEraseTest); +} + +void tst_ExceptionSafetyObjects::vector_data() +{ + containerData(); +} + +void tst_ExceptionSafetyObjects::vector() +{ + QFETCH(TestFunction, testFunction); + + doOOMTest(testFunction, 0); +} + +void tst_ExceptionSafetyObjects::list_data() +{ + containerData(); +} + +void tst_ExceptionSafetyObjects::list() +{ + QFETCH(TestFunction, testFunction); + + doOOMTest(testFunction, 0); +} + +void tst_ExceptionSafetyObjects::linkedList_data() +{ + containerData(); +} + +void tst_ExceptionSafetyObjects::linkedList() +{ + QFETCH(TestFunction, testFunction); + + doOOMTest(testFunction, 0); +} + QTEST_MAIN(tst_ExceptionSafetyObjects) #include "tst_exceptionsafety_objects.moc" #endif // QT_NO_EXCEPTIONS -- cgit v1.2.3