From ff0e9d7f950d757ccbe1bb5267cd514348dadf35 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 12 Jun 2009 16:17:21 +0100 Subject: extra autotests for exceptions --- .../qmainexceptions/tst_qmainexceptions.cpp | 205 +++++++++++++++++++++ 1 file changed, 205 insertions(+) (limited to 'tests/auto/symbian') diff --git a/tests/auto/symbian/qmainexceptions/tst_qmainexceptions.cpp b/tests/auto/symbian/qmainexceptions/tst_qmainexceptions.cpp index 103dd62731..db804966c7 100644 --- a/tests/auto/symbian/qmainexceptions/tst_qmainexceptions.cpp +++ b/tests/auto/symbian/qmainexceptions/tst_qmainexceptions.cpp @@ -40,21 +40,38 @@ ****************************************************************************/ #include +#include #ifdef Q_OS_SYMBIAN +typedef void TLeavingFunc(); + class tst_qmainexceptions : public QObject { Q_OBJECT public: tst_qmainexceptions(){}; ~tst_qmainexceptions(){}; + + void TestSchedulerCatchesError(TLeavingFunc* f, int error); + void TestSymbianRoundTrip(int leave, int trap); + + bool event(QEvent *event); + public slots: void initTestCase(); private slots: void trap(); void cleanupstack(); void leave(); + void testTranslateBadAlloc(); + void testTranslateBigAlloc(); + void testRoundTrip(); + void testTrap(); + void testPropagation(); + void testDtor1(); + void testDtor2(); + void testNestedExceptions(); }; class CDummy : public CBase @@ -100,6 +117,194 @@ void tst_qmainexceptions::leave() __UHEAP_MARKEND; } +class CTestActive : public CActive + { +public: + CTestActive(TLeavingFunc* aFunc) : CActive(EPriorityStandard), iFunc(aFunc) + { + CActiveScheduler::Add(this); + } + ~CTestActive() + { + Cancel(); + } + void DoCancel() + {} + void Test() + { + // complete this AO in a nested scheduler, to make it synchronous + TRequestStatus* s = &iStatus; + SetActive(); + User::RequestComplete(s, KErrNone); + CActiveScheduler::Start(); + } + void RunL() + { + (*iFunc)(); + CActiveScheduler::Stop(); // will only get here if iFunc does not leave + } + TInt RunError(TInt aError) + { + error = aError; + CActiveScheduler::Stop(); // will only get here if iFunc leaves + return KErrNone; + } +public: + TLeavingFunc* iFunc; + int error; + }; + +void tst_qmainexceptions::TestSchedulerCatchesError(TLeavingFunc* f, int error) + { + CTestActive *act = new(ELeave) CTestActive(f); + act->Test(); + QCOMPARE(act->error, error); + delete act; + } + +void ThrowBadAlloc() +{ + throw std::bad_alloc(); +} + +void TranslateThrowBadAllocL() +{ + QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE(ThrowBadAlloc()); +} + +void tst_qmainexceptions::testTranslateBadAlloc() +{ + // bad_alloc should give KErrNoMemory in an AO + TestSchedulerCatchesError(&TranslateThrowBadAllocL, KErrNoMemory); +} + +void BigAlloc() +{ + int *x = new int[100000000]; + delete [] x; +} + +void TranslateBigAllocL() +{ + QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE(BigAlloc()); +} + +void tst_qmainexceptions::testTranslateBigAlloc() +{ + // this test will fail if new does not throw on failure, otherwise should give KErrNoMemory in AO + TestSchedulerCatchesError(&TranslateBigAllocL, KErrNoMemory); +} + +void tst_qmainexceptions::TestSymbianRoundTrip(int leave, int trap) +{ + // check that leave converted to exception, converted to error gives expected error code + int trapped; + QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_ERROR( + trapped, + QT_TRANSLATE_SYMBIAN_LEAVE_TO_EXCEPTION( + User::LeaveIfError(leave))); + QCOMPARE(trap, trapped); +} + +void tst_qmainexceptions::testRoundTrip() +{ + for (int e=-50; e<0; e++) + TestSymbianRoundTrip(e, e); + TestSymbianRoundTrip(KErrNone, KErrNone); + // positive error codes are not errors + TestSymbianRoundTrip(1, KErrNone); + TestSymbianRoundTrip(1000000000, KErrNone); +} + +void tst_qmainexceptions::testTrap() +{ + // testing qt_translateExceptionToSymbianErrorL + TRAPD(err, qt_translateExceptionToSymbianErrorL(std::bad_alloc())); + QCOMPARE(err, KErrNoMemory); +} + +bool tst_qmainexceptions::event(QEvent *aEvent) + { + if (aEvent->type() == QEvent::User+1) + throw std::bad_alloc(); + else if (aEvent->type() == QEvent::User+2) + { + QEvent event(QEvent::Type(QEvent::User+1)); + QApplication::sendEvent(this, &event); + } + return QObject::event(aEvent); + } + +void tst_qmainexceptions::testPropagation() +{ + // test exception thrown from event is propagated back to sender + QEvent event(QEvent::Type(QEvent::User+1)); + bool caught = false; + try { QApplication::sendEvent(this, &event); } + catch (const std::bad_alloc&) { caught = true; } + QCOMPARE(caught, true); + + // testing nested events propagate back to top level sender + caught = false; + QEvent event2(QEvent::Type(QEvent::User+2)); + try { QApplication::sendEvent(this, &event2); } + catch (const std::bad_alloc&) { caught = true; } + QCOMPARE(caught, true); +} + +void tst_qmainexceptions::testDtor1() +{ + // destructors work on exception + int i = 0; + struct SAutoInc { + SAutoInc(int& aI) : i(aI) { ++i; } + ~SAutoInc() { --i; } + int &i; + } ai(i); + QCOMPARE(i, 1); + try { + SAutoInc ai2(i); + QCOMPARE(i, 2); + throw std::bad_alloc(); + QFAIL("should not get here"); + } catch (const std::bad_alloc&) { + QCOMPARE(i, 1); + } + QCOMPARE(i, 1); +} + +void tst_qmainexceptions::testDtor2() +{ + // memory is cleaned up correctly on exception + // this crashes with winscw compiler build < 481 + __UHEAP_MARK; + try { + QString str("abc"); + str += "def"; + throw std::bad_alloc(); + QFAIL("should not get here"); + } catch (const std::bad_alloc&) { } + __UHEAP_MARKEND; +} + +void tst_qmainexceptions::testNestedExceptions() +{ + // throwing exceptions while handling exceptions + struct Oops { + Oops* next; + Oops(int level) : next(level > 0 ? new Oops(level-1) : 0) {} + ~Oops() { + try { throw std::bad_alloc(); } + catch (const std::exception&) {delete next;} + } + }; + try { + Oops oops(5); + throw std::bad_alloc(); + } + catch (const std::exception&) {} +} + QTEST_MAIN(tst_qmainexceptions) #include "tst_qmainexceptions.moc" -- cgit v1.2.3