diff options
Diffstat (limited to 'old/tests/qtuitest/tst_qalternatestack/tst_qalternatestack.cpp')
-rw-r--r-- | old/tests/qtuitest/tst_qalternatestack/tst_qalternatestack.cpp | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/old/tests/qtuitest/tst_qalternatestack/tst_qalternatestack.cpp b/old/tests/qtuitest/tst_qalternatestack/tst_qalternatestack.cpp new file mode 100644 index 0000000..7b4e745 --- /dev/null +++ b/old/tests/qtuitest/tst_qalternatestack/tst_qalternatestack.cpp @@ -0,0 +1,418 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of QtUiTest. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTest> +#include <QObject> +#include <qalternatestack_p.h> +#include <QCoreApplication> +//#include <shared/qtopiaunittest.h> + +#ifdef Q_OS_UNIX +#include <signal.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <string.h> +#include <errno.h> +#endif + +//TESTED_COMPONENT=QA: Testing Framework (18707) + +class tst_QAlternateStack : public QObject +{ + Q_OBJECT + +private slots: + void start(); + void switching(); + + void init(); + + void sigaltstack(); + + void multipleInstances(); + +private: + static void stack_entry(QAlternateStack*, QVariant const&); + + static void stack_entry1(QAlternateStack*, QVariant const&); + static void stack_entry2(QAlternateStack*, QVariant const&); + static void stack_entry3(QAlternateStack*, QVariant const&); + static void stack_entry4(QAlternateStack*, QVariant const&); + static void stack_entry_handler(QAlternateStack*,QVariant const&,int); + + int m_shouldSwitchFrom; + + QAlternateStack* m_stack; + QVariant m_data; + bool m_isActive; + bool m_isCurrentStack; + + QList<QPair<int,QAlternateStack*> > m_stackEntries; +}; + +class tst_QAlternateStackWithStackBuffer : public tst_QAlternateStack +{ + Q_OBJECT +}; + +#ifdef Q_OS_UNIX +extern char*& qalternatestack_stackbuf(); +extern int& qalternatestack_stackbuf_len(); +#endif + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + int ret = 0; + + // First, test the regular heap-allocated alternate stack. + { + tst_QAlternateStack test; + ret += QTest::qExec(&test, argc, argv); + } + +#ifdef Q_OS_UNIX + // Now try using memory allocated from the main stack only. + { + char buf[65536*4]; + qalternatestack_stackbuf() = buf; + qalternatestack_stackbuf_len() = 256*1024; + tst_QAlternateStackWithStackBuffer test; + ret += QTest::qExec(&test, argc, argv); + } +#endif + + return ret; +} + +void tst_QAlternateStack::stack_entry(QAlternateStack* stack, QVariant const& data) +{ + QVariantList list = data.toList(); + if (!list.count()) return; + if (!stack) return; + + tst_QAlternateStack* test = qobject_cast<tst_QAlternateStack*>(list.at(0).value<QObject*>()); + if (!test) return; + + test->m_stack = stack; + test->m_data = data; + test->m_isActive = stack->isActive(); + test->m_isCurrentStack = stack->isCurrentStack(); + + for (; test->m_shouldSwitchFrom > 0; --test->m_shouldSwitchFrom) { + stack->switchFrom(); + test->m_isActive = stack->isActive(); + test->m_isCurrentStack = stack->isCurrentStack(); + } +} + +void tst_QAlternateStack::stack_entry1(QAlternateStack* stack, QVariant const& data) +{ stack_entry_handler(stack, data, 1); } +void tst_QAlternateStack::stack_entry2(QAlternateStack* stack, QVariant const& data) +{ stack_entry_handler(stack, data, 2); } +void tst_QAlternateStack::stack_entry3(QAlternateStack* stack, QVariant const& data) +{ stack_entry_handler(stack, data, 3); } +void tst_QAlternateStack::stack_entry4(QAlternateStack* stack, QVariant const& data) +{ stack_entry_handler(stack, data, 4); } + +void tst_QAlternateStack::stack_entry_handler(QAlternateStack* stack, QVariant const& data, int number) +{ + QVariantList list = data.toList(); + if (!list.count()) return; + + tst_QAlternateStack* test = qobject_cast<tst_QAlternateStack*>(list.at(0).value<QObject*>()); + if (!test) return; + + test->m_stackEntries << qMakePair(number, stack); + test->m_stack = stack; + test->m_isActive = stack->isActive(); + test->m_isCurrentStack = stack->isCurrentStack(); + + // It is possible we've been called on a stack which overlaps some other memory. + // When this happens, try to increase the chances of causing a crash by corrupting memory. + static const int LEN = 32768; + char buf[LEN]; + for (int i = 0; i < LEN; i += 4) { + buf[i] = 0xDE; + buf[i+1] = 0xAD; + buf[i+2] = 0xBE; + buf[i+3] = 0xEF; + } + // Make sure compiler doesn't optimize it out + qChecksum(buf, LEN); +} + +/* + \req QTOPIA-78 + + \groups +*/ +void tst_QAlternateStack::start() +{ + if (!QAlternateStack::isAvailable()) { + QSKIP("QAlternateStack is not available on this platform.", SkipAll); + } + + QAlternateStack stack; + + QCOMPARE(stack.isActive(), false); + QCOMPARE(stack.isCurrentStack(), false); + + QVariantList list; + list.append( qVariantFromValue((QObject*)this) ); + + // Switch to the stack... + stack.start(tst_QAlternateStack::stack_entry, list); + // ... it should have returned almost immediately. + + // Check that our private members were set to the expected values. + QCOMPARE(m_stack, &stack); + QCOMPARE(m_data, qVariantFromValue(list)); + QCOMPARE(m_isActive, true); + QCOMPARE(m_isCurrentStack, true); + + QCOMPARE(stack.isActive(), false); + QCOMPARE(stack.isCurrentStack(), false); +} + +/* + \req QTOPIA-78 + + \groups +*/ +void tst_QAlternateStack::switching() +{ + if (!QAlternateStack::isAvailable()) { + QSKIP("QAlternateStack is not available on this platform.", SkipAll); + } + + QAlternateStack stack; + + QCOMPARE(stack.isActive(), false); + QCOMPARE(stack.isCurrentStack(), false); + + QVariantList list; + list.append( qVariantFromValue((QObject*)this) ); + + // Set it up so the alternate stack calls switchFrom() several times. + const int switchCount = 5; + m_shouldSwitchFrom = switchCount; + + stack.start(tst_QAlternateStack::stack_entry, list); + + for (int i = switchCount; i > 0; --i) { + // Check that our private members were set to the expected values. + QCOMPARE(m_stack, &stack); + QCOMPARE(m_data, qVariantFromValue(list)); + QCOMPARE(m_isActive, true); + QCOMPARE(m_isCurrentStack, true); + + QCOMPARE(m_shouldSwitchFrom, i); + + // Still active, since we switched using switchFrom(). + QCOMPARE(stack.isActive(), true); + QCOMPARE(stack.isCurrentStack(), false); + + // Switch to the stack... + stack.switchTo(); + } + + // No longer active. + QCOMPARE(m_shouldSwitchFrom, 0); + QCOMPARE(stack.isActive(), false); + QCOMPARE(stack.isCurrentStack(), false); +} + +char* addressof_dummy; +int got_signal; + +void test_sighandler(int signum) +{ + got_signal = signum; + + int dummy = 1; + addressof_dummy = (char*)&dummy; +} + +/* + \req QTOPIA-78 + + \groups + + Tests that sigaltstack() actually works on the target platform. + + On some platforms, like the Greenphone, sigaltstack seems to be broken + and always causes a segfault. When porting QtUitest to a new platform, + run this testfunction to make sure QAlternateStack will work properly. +*/ +void tst_QAlternateStack::sigaltstack() +{ +#ifdef Q_OS_UNIX + // isAvailable() returns false on platforms where sigaltstack is known + // to be broken. + if (!QAlternateStack::isAvailable()) { + QSKIP("QAlternateStack is not available on this platform.", SkipAll); + } + QByteArray buffer; + buffer.resize(SIGSTKSZ); + + stack_t stack; + stack.ss_sp = (qalternatestack_stackbuf() ? qalternatestack_stackbuf() : buffer.data()); + stack.ss_size = SIGSTKSZ; + stack.ss_flags = 0; + + QVERIFY( 0 == ::sigaltstack(&stack, 0) ); + + stack_t newstack; + QVERIFY( 0 == ::sigaltstack(0, &newstack) ); + QVERIFY(stack.ss_sp == newstack.ss_sp); + QVERIFY(stack.ss_size == newstack.ss_size); + QVERIFY(stack.ss_flags == newstack.ss_flags); + + struct sigaction action; + action.sa_handler = test_sighandler; + action.sa_flags = SA_ONSTACK; + sigemptyset(&action.sa_mask); + + QVERIFY2( 0 == sigaction(SIGUSR2, &action, 0), strerror(errno) ); + + struct sigaction newaction; + QVERIFY2( 0 == sigaction(SIGUSR2,0,&newaction), strerror(errno) ); + QVERIFY(newaction.sa_handler == action.sa_handler); + QVERIFY(newaction.sa_flags & SA_ONSTACK); + + addressof_dummy = 0; + got_signal = 0; + //qLog(Autotest) << "About to raise"; + + // Greenphone crashes here. + raise(SIGUSR2); + + QCOMPARE(got_signal, SIGUSR2); + //qLog(Autotest) << "dummy:" << (void*)addressof_dummy << "stack:" << stack.ss_sp; + QVERIFY( (addressof_dummy > (char*)stack.ss_sp) && (addressof_dummy < (char*)stack.ss_sp + stack.ss_size) ); +#else + QSKIP("Test not valid on this platform", SkipAll); +#endif +} + +void tst_QAlternateStack::multipleInstances() +{ + if (!QAlternateStack::isAvailable()) { + QSKIP("QAlternateStack is not available on this platform.", SkipAll); + } + + QVariantList list; + list.append( qVariantFromValue((QObject*)this) ); + + QAlternateStack stack1; + QAlternateStack stack2; + QAlternateStack stack3; + QAlternateStack stack4; + + QList<QAlternateStack*> stacks; + stacks << &stack1 << &stack2 << &stack3 << &stack4; + + // Verify the usual stack functions work as expected. + foreach (QAlternateStack* stack, stacks) { + m_stack = 0; + m_isActive = false; + m_isCurrentStack = false; + QVERIFY(!stack->isActive()); + QVERIFY(!stack->isCurrentStack()); + + stack->start(stack_entry1, list); + + QCOMPARE(m_stack, stack); + QVERIFY(m_isActive); + QVERIFY(m_isCurrentStack); + QVERIFY(!stack->isActive()); + QVERIFY(!stack->isCurrentStack()); + } + + { + QList<QPair<int,QAlternateStack*> > expected; + expected + << qMakePair(1, &stack1) + << qMakePair(1, &stack2) + << qMakePair(1, &stack3) + << qMakePair(1, &stack4) + ; + QCOMPARE(m_stackEntries, expected); + m_stackEntries.clear(); + } + + // Verify the correct functions all get called as expected. + stack1.start(stack_entry1, list); + stack4.start(stack_entry4, list); + stack2.start(stack_entry2, list); + stack3.start(stack_entry3, list); + stack1.start(stack_entry1, list); + stack4.start(stack_entry4, list); + stack3.start(stack_entry3, list); + + { + QList<QPair<int,QAlternateStack*> > expected; + expected + << qMakePair(1, &stack1) + << qMakePair(4, &stack4) + << qMakePair(2, &stack2) + << qMakePair(3, &stack3) + << qMakePair(1, &stack1) + << qMakePair(4, &stack4) + << qMakePair(3, &stack3) + ; + + QCOMPARE(m_stackEntries, expected); + } +} + +void tst_QAlternateStack::init() +{ + m_shouldSwitchFrom = 0; + m_stack = 0; + m_data = QVariant(); + m_isActive = false; + m_isCurrentStack = false; +} + +#include "tst_qalternatestack.moc" |