diff options
author | Joona Petrell <joona.t.petrell@nokia.com> | 2011-02-22 04:12:05 (GMT) |
---|---|---|
committer | Joona Petrell <joona.t.petrell@nokia.com> | 2011-02-22 04:12:05 (GMT) |
commit | bf9ca539dc4c5efff801856ad9d3f7e14dabad26 (patch) | |
tree | a5ae494b6e8a2b33f4345f484ba2ead04aca761e /tests | |
parent | b254be20c03d4dbfc1803cd40dc95d52115b955c (diff) | |
parent | a34e2ab6f50cc91a4fca5cd7fd7bd22e6495b0c1 (diff) | |
download | Qt-bf9ca539dc4c5efff801856ad9d3f7e14dabad26.zip Qt-bf9ca539dc4c5efff801856ad9d3f7e14dabad26.tar.gz Qt-bf9ca539dc4c5efff801856ad9d3f7e14dabad26.tar.bz2 |
Merge branch '4.7' of git://scm.dev.nokia.troll.no/qt/qt into 4.7
Conflicts:
tools/qml/qml.pri
Diffstat (limited to 'tests')
26 files changed, 850 insertions, 245 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index c0004f7..c677249 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -19,4 +19,5 @@ contains(QT_CONFIG, multimedia): SUBDIRS += multimedia.pro contains(QT_CONFIG, phonon): SUBDIRS += phonon.pro contains(QT_CONFIG, svg): SUBDIRS += svg.pro contains(QT_CONFIG, declarative): SUBDIRS += declarative.pro +!symbian SUBDIRS += help.pro diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 802e74a..4b809fb 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -80,11 +80,6 @@ SUBDIRS=\ qgroupbox \ qguivariant \ qheaderview \ - qhelpcontentmodel \ - qhelpenginecore \ - qhelpgenerator \ - qhelpindexmodel \ - qhelpprojectdata \ qicoimageformat \ qicon \ qimageiohandler \ @@ -221,10 +216,5 @@ win32:SUBDIRS -= qtextpiecetable qtextpiecetable \ symbian:SUBDIRS -= \ - qhelpcontentmodel \ - qhelpenginecore \ - qhelpgenerator \ - qhelpindexmodel \ - qhelpprojectdata \ qsystemtrayicon \ diff --git a/tests/auto/help.pro b/tests/auto/help.pro new file mode 100644 index 0000000..e6ee552 --- /dev/null +++ b/tests/auto/help.pro @@ -0,0 +1,8 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qhelpcontentmodel \ + qhelpenginecore \ + qhelpgenerator \ + qhelpindexmodel \ + qhelpprojectdata \ + diff --git a/tests/auto/networkselftest/networkselftest.pro b/tests/auto/networkselftest/networkselftest.pro index d7cb7f3..3e680d8 100644 --- a/tests/auto/networkselftest/networkselftest.pro +++ b/tests/auto/networkselftest/networkselftest.pro @@ -6,12 +6,13 @@ QT = core network wince*: { addFiles.sources = rfc3252.txt addFiles.path = . - DEPLOYMENT = addFiles + DEPLOYMENT += addFiles DEFINES += SRCDIR=\\\"\\\" } else:symbian { addFiles.sources = rfc3252.txt addFiles.path = . - DEPLOYMENT = addFiles + DEPLOYMENT += addFiles + TARGET.CAPABILITY = NetworkServices ReadUserData } else:vxworks*: { DEFINES += SRCDIR=\\\"\\\" } else { diff --git a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp index c1938b1..39f0677 100644 --- a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp +++ b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp @@ -169,6 +169,25 @@ public slots: int MyObject::callCount = 0; QVariantList MyObject::callArgs; +class MyObjectUnknownType: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject") + Q_CLASSINFO("D-Bus Introspection", "" +" <interface name=\"com.trolltech.QtDBus.MyObjectUnknownTypes\" >\n" +" <property access=\"readwrite\" type=\"~\" name=\"prop1\" />\n" +" <signal name=\"somethingHappened\" >\n" +" <arg direction=\"out\" type=\"~\" />\n" +" </signal>\n" +" <method name=\"ping\" >\n" +" <arg direction=\"in\" type=\"~\" name=\"ping\" />\n" +" <arg direction=\"out\" type=\"~\" name=\"ping\" />\n" +" </method>\n" +" <method name=\"regularMethod\" />\n" +" </interface>\n" + "") +}; + class Spy: public QObject { Q_OBJECT @@ -228,6 +247,7 @@ private slots: void notValidDerived(); void invalidAfterServiceOwnerChanged(); void introspect(); + void introspectUnknownTypes(); void callMethod(); void invokeMethod(); void invokeMethodWithReturn(); @@ -250,8 +270,7 @@ void tst_QDBusInterface::initTestCase() con.registerObject("/", &obj, QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSlots - | QDBusConnection::ExportAllInvokables - | QDBusConnection::ExportChildObjects); + | QDBusConnection::ExportAllInvokables); } void tst_QDBusInterface::notConnected() @@ -322,6 +341,27 @@ void tst_QDBusInterface::introspect() QVERIFY(mo->indexOfProperty("complexProp") != -1); } +void tst_QDBusInterface::introspectUnknownTypes() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + MyObjectUnknownType obj; + con.registerObject("/unknownTypes", &obj, QDBusConnection::ExportAllContents); + QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/unknownTypes"), + "com.trolltech.QtDBus.MyObjectUnknownTypes"); + + const QMetaObject *mo = iface.metaObject(); + QVERIFY(mo->indexOfMethod("regularMethod()") != -1); // this is the control + QVERIFY(mo->indexOfMethod("somethingHappened(QDBusRawType<0x7e>*)") != -1); + + QVERIFY(mo->indexOfMethod("ping(QDBusRawType<0x7e>*)") != -1); + int midx = mo->indexOfMethod("ping(QDBusRawType<0x7e>*)"); + QCOMPARE(mo->method(midx).typeName(), "QDBusRawType<0x7e>*"); + + QVERIFY(mo->indexOfProperty("prop1") != -1); + int pidx = mo->indexOfProperty("prop1"); + QCOMPARE(mo->property(pidx).typeName(), "QDBusRawType<0x7e>*"); +} + void tst_QDBusInterface::callMethod() { QDBusConnection con = QDBusConnection::sessionBus(); diff --git a/tests/auto/qdbusmarshall/test/test.pro b/tests/auto/qdbusmarshall/test/test.pro index 8901999..71fc656 100644 --- a/tests/auto/qdbusmarshall/test/test.pro +++ b/tests/auto/qdbusmarshall/test/test.pro @@ -5,4 +5,5 @@ TARGET = ../tst_qdbusmarshall QT = core QT += dbus - +LIBS += $$QT_LIBS_DBUS +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index c05e49c..9bae6af 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -38,7 +38,6 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#define DBUS_API_SUBJECT_TO_CHANGE #include <QtCore/QtCore> #include <QtTest/QtTest> #include <QtDBus/QtDBus> @@ -47,6 +46,8 @@ #include "common.h" #include <limits> +#include <dbus/dbus.h> + static const char serviceName[] = "com.trolltech.autotests.qpong"; static const char objectPath[] = "/com/trolltech/qpong"; static const char *interfaceName = serviceName; @@ -88,66 +89,59 @@ private slots: void sendCallErrors_data(); void sendCallErrors(); + void receiveUnknownType_data(); + void receiveUnknownType(); + private: QProcess proc; }; -struct UnregisteredType { }; -Q_DECLARE_METATYPE(UnregisteredType) - -class WaitForQPong: public QObject +class QDBusMessageSpy: public QObject { Q_OBJECT -public: - WaitForQPong(); - bool ok(); -public Q_SLOTS: - void ownerChange(const QString &name) +public slots: + Q_SCRIPTABLE int theSlot(const QDBusMessage &msg) { - if (name == serviceName) - loop.quit(); + list << msg; + return 42; } - -private: - QEventLoop loop; +public: + QList<QDBusMessage> list; }; -WaitForQPong::WaitForQPong() -{ - QDBusConnection con = QDBusConnection::sessionBus(); - if (!ok()) { - connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), - SLOT(ownerChange(QString))); - QTimer::singleShot(2000, &loop, SLOT(quit())); - loop.exec(); - } -} - -bool WaitForQPong::ok() -{ - return QDBusConnection::sessionBus().isConnected() && - QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); -} +struct UnregisteredType { }; +Q_DECLARE_METATYPE(UnregisteredType) void tst_QDBusMarshall::initTestCase() { commonInit(); + QDBusConnection con = QDBusConnection::sessionBus(); #ifdef Q_OS_WIN proc.start("qpong"); #else proc.start("./qpong/qpong"); #endif - QVERIFY(proc.waitForStarted()); - - WaitForQPong w; - QVERIFY(w.ok()); - //QTest::qWait(2000); + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)) { + QVERIFY(proc.waitForStarted()); + + QVERIFY(con.isConnected()); + con.connect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged", + QStringList() << serviceName << QString(""), QString(), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)); + con.disconnect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged", + QStringList() << serviceName << QString(""), QString(), + &QTestEventLoop::instance(), SLOT(exitLoop())); + } } void tst_QDBusMarshall::cleanupTestCase() { proc.close(); - proc.kill(); + proc.terminate(); + proc.waitForFinished(200); } void tst_QDBusMarshall::sendBasic_data() @@ -700,6 +694,8 @@ void tst_QDBusMarshall::sendBasic() msg << value; QDBusMessage reply = con.call(msg); + QVERIFY2(reply.type() == QDBusMessage::ReplyMessage, + qPrintable(reply.errorName() + ": " + reply.errorMessage())); //qDebug() << reply; QCOMPARE(reply.arguments().count(), msg.arguments().count()); @@ -938,5 +934,145 @@ void tst_QDBusMarshall::sendCallErrors() QCOMPARE(reply.errorMessage(), errorMsg); } +void tst_QDBusMarshall::receiveUnknownType_data() +{ + QTest::addColumn<int>("receivedTypeId"); + QTest::newRow("in-call") << qMetaTypeId<void*>(); + QTest::newRow("type-variant") << qMetaTypeId<QDBusVariant>(); + QTest::newRow("type-array") << qMetaTypeId<QDBusArgument>(); + QTest::newRow("type-struct") << qMetaTypeId<QDBusArgument>(); + QTest::newRow("type-naked") << qMetaTypeId<void *>(); +} + +struct DisconnectRawDBus { + static void cleanup(DBusConnection *connection) + { + if (!connection) + return; + dbus_connection_close(connection); + dbus_connection_unref(connection); + } +}; +template <typename T, void (*unref)(T *)> struct GenericUnref +{ + static void cleanup(T *type) + { + if (!type) return; + unref(type); + } +}; + +// use these scoped types to avoid memory leaks if QVERIFY or QCOMPARE fails +typedef QScopedPointer<DBusConnection, DisconnectRawDBus> ScopedDBusConnection; +typedef QScopedPointer<DBusMessage, GenericUnref<DBusMessage, dbus_message_unref> > ScopedDBusMessage; +typedef QScopedPointer<DBusPendingCall, GenericUnref<DBusPendingCall, dbus_pending_call_unref> > ScopedDBusPendingCall; + +void tst_QDBusMarshall::receiveUnknownType() +{ +#ifndef DBUS_TYPE_UNIX_FD + QSKIP("Your system's D-Bus library is too old for this test", SkipAll); +#else + QDBusConnection con = QDBusConnection::sessionBus(); + QVERIFY(con.isConnected()); + + // this needs to be implemented in raw + // open a new connection to the bus daemon + DBusError error; + dbus_error_init(&error); + ScopedDBusConnection rawcon(dbus_bus_get_private(DBUS_BUS_SESSION, &error)); + QVERIFY2(rawcon.data(), error.name); + + // check if this bus supports passing file descriptors + if (!dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD)) + QSKIP("Your session bus does not allow sending Unix file descriptors", SkipAll); + + if (qstrcmp(QTest::currentDataTag(), "in-call") == 0) { + // create a call back to us containing a file descriptor + QDBusMessageSpy spy; + con.registerObject("/spyObject", &spy, QDBusConnection::ExportAllSlots); + ScopedDBusMessage msg(dbus_message_new_method_call(con.baseService().toLatin1(), "/spyObject", NULL, "theSlot")); + + int fd = fileno(stdout); + dbus_message_append_args(msg.data(), DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID); + + // try to send to us + DBusPendingCall *pending_ptr; + dbus_connection_send_with_reply(rawcon.data(), msg.data(), &pending_ptr, 1000); + ScopedDBusPendingCall pending(pending_ptr); + + // check that it got sent + while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS) + ; + + // now spin our event loop. We don't catch this call, so let's get the reply + QEventLoop loop; + QTimer::singleShot(200, &loop, SLOT(quit())); + loop.exec(); + + // now try to receive the reply + dbus_pending_call_block(pending.data()); + + // check that the spy received what it was supposed to receive + QCOMPARE(spy.list.size(), 1); + QCOMPARE(spy.list.at(0).arguments().size(), 1); + QFETCH(int, receivedTypeId); + QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); + + msg.reset(dbus_pending_call_steal_reply(pending.data())); + QVERIFY(msg); + QCOMPARE(dbus_message_get_type(msg.data()), DBUS_MESSAGE_TYPE_METHOD_RETURN); + QCOMPARE(dbus_message_get_signature(msg.data()), DBUS_TYPE_INT32_AS_STRING); + + int retval; + QVERIFY(dbus_message_get_args(msg.data(), &error, DBUS_TYPE_INT32, &retval, DBUS_TYPE_INVALID)); + QCOMPARE(retval, 42); + } else { + // create a signal that we'll emit + static const char signalName[] = "signalName"; + static const char interfaceName[] = "local.interface.name"; + ScopedDBusMessage msg(dbus_message_new_signal("/", interfaceName, signalName)); + con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &QTestEventLoop::instance(), SLOT(exitLoop())); + + QDBusMessageSpy spy; + con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &spy, SLOT(theSlot(QDBusMessage))); + + DBusMessageIter iter; + dbus_message_iter_init_append(msg.data(), &iter); + int fd = fileno(stdout); + + if (qstrcmp(QTest::currentDataTag(), "type-naked") == 0) { + // send naked + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd); + } else { + DBusMessageIter subiter; + if (qstrcmp(QTest::currentDataTag(), "type-variant") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter); + else if (qstrcmp(QTest::currentDataTag(), "type-array") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter); + else if (qstrcmp(QTest::currentDataTag(), "type-struct") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, 0, &subiter); + dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UNIX_FD, &fd); + dbus_message_iter_close_container(&iter, &subiter); + } + + // send it + dbus_connection_send(rawcon.data(), msg.data(), 0); + + // check that it got sent + while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS) + ; + + // now let's see what happens + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(spy.list.size(), 1); + QCOMPARE(spy.list.at(0).arguments().count(), 1); + QFETCH(int, receivedTypeId); + //qDebug() << spy.list.at(0).arguments().at(0).typeName(); + QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); + } +#endif +} + QTEST_MAIN(tst_QDBusMarshall) #include "tst_qdbusmarshall.moc" diff --git a/tests/auto/qdbusperformance/tst_qdbusperformance.cpp b/tests/auto/qdbusperformance/tst_qdbusperformance.cpp index 42db697..a5b4b98 100644 --- a/tests/auto/qdbusperformance/tst_qdbusperformance.cpp +++ b/tests/auto/qdbusperformance/tst_qdbusperformance.cpp @@ -125,7 +125,7 @@ void tst_QDBusPerformance::init() void tst_QDBusPerformance::callSpeed() { - QTime timer; + QElapsedTimer timer; int callCount = 0; timer.start(); @@ -141,7 +141,7 @@ void tst_QDBusPerformance::callSpeed() bool tst_QDBusPerformance::executeTest(const char *funcname, int size, const QVariant &data) { - QTime timer; + QElapsedTimer timer; int callCount = 0; qint64 transferred = 0; diff --git a/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp b/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp index 25595c5..f83795c 100644 --- a/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp +++ b/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp @@ -287,11 +287,14 @@ void tst_QDBusXmlParser::methods_data() "</method>" << map; // one invalid arg + method.inputArgs << arg("~", "invalid"); + map.clear(); + map << method; QTest::newRow("two-in-one-invalid") << "<method name=\"Method\">" "<arg type=\"s\" direction=\"in\"/>" - "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>" // this line should be ignored "<arg type=\"v\" direction=\"in\"/>" + "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>" "</method>" << map; // one out argument @@ -380,8 +383,6 @@ void tst_QDBusXmlParser::methods() QFETCH(QString, xmlDataFragment); - if (strcmp(QTest::currentDataTag(), "two-in-one-invalid") == 0) - QTest::ignoreMessage(QtWarningMsg, "Invalid D-BUS type signature '~' found while parsing introspection"); QDBusIntrospection::Interface iface = QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter); @@ -390,9 +391,9 @@ void tst_QDBusXmlParser::methods() QFETCH(MethodMap, methodMap); MethodMap parsedMap = iface.methods; - QCOMPARE(methodMap.count(), parsedMap.count()); - QCOMPARE(methodMap, parsedMap); -} + QCOMPARE(parsedMap.count(), methodMap.count()); + QCOMPARE(parsedMap, methodMap); +} void tst_QDBusXmlParser::signals__data() { diff --git a/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp index 2ca1a47..9875fb5 100644 --- a/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp +++ b/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp @@ -484,8 +484,6 @@ class ProgressTextTask : public RunFunctionTask<T> public: void runFunctor() { - while (this->isProgressUpdateNeeded() == false) - QTest::qSleep(1); this->setProgressValueAndText(1, QLatin1String("Foo 1")); while (this->isProgressUpdateNeeded() == false) @@ -495,6 +493,10 @@ public: while (this->isProgressUpdateNeeded() == false) QTest::qSleep(1); this->setProgressValueAndText(3, QLatin1String("Foo 3")); + + while (this->isProgressUpdateNeeded() == false) + QTest::qSleep(1); + this->setProgressValueAndText(4, QLatin1String("Foo 4")); } }; @@ -522,14 +524,16 @@ void tst_QFutureWatcher::progressText() QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(f.progressText(), QLatin1String("Foo 3")); - QCOMPARE(f.progressValue(), 3); + QCOMPARE(f.progressText(), QLatin1String("Foo 4")); + QCOMPARE(f.progressValue(), 4); QVERIFY(progressValues.contains(1)); QVERIFY(progressValues.contains(2)); QVERIFY(progressValues.contains(3)); + QVERIFY(progressValues.contains(4)); QVERIFY(progressTexts.contains(QLatin1String("Foo 1"))); QVERIFY(progressTexts.contains(QLatin1String("Foo 2"))); QVERIFY(progressTexts.contains(QLatin1String("Foo 3"))); + QVERIFY(progressTexts.contains(QLatin1String("Foo 4"))); } } diff --git a/tests/auto/qimagereader/images/corrupt-pixel-count.xpm b/tests/auto/qimagereader/images/corrupt-pixel-count.xpm new file mode 100644 index 0000000..3a736ff --- /dev/null +++ b/tests/auto/qimagereader/images/corrupt-pixel-count.xpm @@ -0,0 +1,11 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +"2 2 2 -2", +/* colors */ +"a c #adadad", +"b c #dedede", +/* pixels */ +"ab", +"ba" +}; diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 69e8ead..5321864 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -1399,6 +1399,9 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("corrupt-pixels.xpm") << QString("corrupt-pixels.xpm") << QByteArray("xpm") << QSize(0, 0) << QString("QImage: XPM pixels missing on image line 3"); + QTest::newRow("corrupt-pixel-count.xpm") << QString("corrupt-pixel-count.xpm") + << QByteArray("xpm") << QSize(0, 0) + << QString(""); QTest::newRow("marble.xpm") << QString("marble.xpm") << QByteArray("xpm") << QSize(240, 240) << QString(""); diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp index 3c4c767..ea983cb 100644 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ b/tests/auto/qmutex/tst_qmutex.cpp @@ -67,6 +67,7 @@ private slots: void lock_unlock_locked_tryLock(); void stressTest(); void tryLockRace(); + void qtbug16115_trylock(); }; static const int iterations = 100; @@ -464,5 +465,42 @@ void tst_QMutex::tryLockRace() TryLockRaceThread::mutex.unlock(); } +static volatile int qtbug16115_trylock_counter; + +void tst_QMutex::qtbug16115_trylock() +{ + //Used to deadlock on unix + struct TrylockThread : QThread { + TrylockThread(QMutex &mut) : mut(mut) {} + QMutex &mut; + void run() { + for (int i = 0; i < 1000000; ++i) { + if (mut.tryLock(0)) { + Q_ASSERT((++qtbug16115_trylock_counter) == 1); + Q_ASSERT((--qtbug16115_trylock_counter) == 0); + mut.unlock(); + } + } + } + }; + QMutex mut; + TrylockThread t1(mut); + TrylockThread t2(mut); + TrylockThread t3(mut); + t1.start(); + t2.start(); + t3.start(); + + for (int i = 0; i < 1000000; ++i) { + mut.lock(); + Q_ASSERT((++qtbug16115_trylock_counter) == 1); + Q_ASSERT((--qtbug16115_trylock_counter) == 0); + mut.unlock(); + } + t1.wait(); + t2.wait(); + t3.wait(); +} + QTEST_MAIN(tst_QMutex) #include "tst_qmutex.moc" diff --git a/tests/auto/qnetworksession/test/tst_qnetworksession.cpp b/tests/auto/qnetworksession/test/tst_qnetworksession.cpp index 37fc9cd..3315836 100644 --- a/tests/auto/qnetworksession/test/tst_qnetworksession.cpp +++ b/tests/auto/qnetworksession/test/tst_qnetworksession.cpp @@ -60,8 +60,6 @@ QT_USE_NAMESPACE Q_DECLARE_METATYPE(QNetworkConfiguration) Q_DECLARE_METATYPE(QNetworkConfiguration::Type); -Q_DECLARE_METATYPE(QNetworkSession::State); -Q_DECLARE_METATYPE(QNetworkSession::SessionError); class tst_QNetworkSession : public QObject { @@ -126,8 +124,6 @@ QNetworkConfiguration suitableConfiguration(QString bearerType, QNetworkConfigur void tst_QNetworkSession::initTestCase() { - qRegisterMetaType<QNetworkSession::State>("QNetworkSession::State"); - qRegisterMetaType<QNetworkSession::SessionError>("QNetworkSession::SessionError"); qRegisterMetaType<QNetworkConfiguration>("QNetworkConfiguration"); qRegisterMetaType<QNetworkConfiguration::Type>("QNetworkConfiguration::Type"); diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index 4ee8957..b0f7a9f 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -249,6 +249,8 @@ void tst_QProcess::constructing() char c; QCOMPARE(process.read(&c, 1), qlonglong(-1)); QCOMPARE(process.write(&c, 1), qlonglong(-1)); + + QProcess proc2; } void tst_QProcess::simpleStart() @@ -265,7 +267,7 @@ void tst_QProcess::simpleStart() process->start("testProcessNormal/testProcessNormal"); if (process->state() != QProcess::Starting) QCOMPARE(process->state(), QProcess::Running); - QVERIFY(process->waitForStarted(5000)); + QVERIFY2(process->waitForStarted(5000), qPrintable(process->errorString())); QCOMPARE(process->state(), QProcess::Running); #if defined(Q_OS_WINCE) // Note: This actually seems incorrect, it will only exit the while loop when finishing fails @@ -277,7 +279,7 @@ void tst_QProcess::simpleStart() while (process->waitForReadyRead(5000)) { } #endif - QCOMPARE(process->state(), QProcess::NotRunning); + QCOMPARE(int(process->state()), int(QProcess::NotRunning)); delete process; process = 0; diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp index 1a1576b..7915eb0 100644 --- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp +++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp @@ -860,6 +860,50 @@ void tst_QScriptContext::backtrace_data() QTest::newRow("js recursive") << source << expected; } + + { + QString source = QString::fromLatin1( + "[0].forEach(\n" + " function() {\n" + " result = bt();\n" + "}); result"); + + QStringList expected; + expected << "<native>() at -1" + << "<anonymous>(0, 0, 0) at testfile:3" + << QString::fromLatin1("forEach(%0) at -1") + // Because the JIT doesn't store the arguments in the frame + // for built-in functions, arguments are not available. + // Will work when the copy of JavaScriptCore is updated + // (QTBUG-16568). + .arg(qt_script_isJITEnabled() + ? "" + : "function () {\n result = bt();\n}") + << "<global>() at testfile:4"; + QTest::newRow("js callback from built-in") << source << expected; + } + + { + QString source = QString::fromLatin1( + "[10,20].forEach(\n" + " function() {\n" + " result = bt();\n" + "}); result"); + + QStringList expected; + expected << "<native>() at -1" + << "<anonymous>(20, 1, 10,20) at testfile:3" + << QString::fromLatin1("forEach(%0) at -1") + // Because the JIT doesn't store the arguments in the frame + // for built-in functions, arguments are not available. + // Will work when the copy of JavaScriptCore is updated + // (QTBUG-16568). + .arg(qt_script_isJITEnabled() + ? "" + : "function () {\n result = bt();\n}") + << "<global>() at testfile:4"; + QTest::newRow("js callback from built-in") << source << expected; + } } diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index c3a0ba1..8de6fbc 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -164,6 +164,7 @@ private slots: void translationContext_data(); void translationContext(); void translateScriptIdBased(); + void translateFromBuiltinCallback(); void functionScopes(); void nativeFunctionScopes(); void evaluateProgram(); @@ -4725,6 +4726,21 @@ void tst_QScriptEngine::translateScriptIdBased() QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural } +void tst_QScriptEngine::translateFromBuiltinCallback() +{ + QScriptEngine eng; + eng.installTranslatorFunctions(); + + // Callback has no translation context. + eng.evaluate("function foo() { qsTr('foo'); }"); + + // Stack at translation time will be: + // qsTr, foo, forEach, global + // qsTr() needs to walk to the outer-most (global) frame before it finds + // a translation context, and this should not crash. + eng.evaluate("[10,20].forEach(foo)", "script.js"); +} + void tst_QScriptEngine::functionScopes() { QScriptEngine eng; diff --git a/tests/auto/qset/tst_qset.cpp b/tests/auto/qset/tst_qset.cpp index 204ca55..164bf1e 100644 --- a/tests/auto/qset/tst_qset.cpp +++ b/tests/auto/qset/tst_qset.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +//#define QT_STRICT_ITERATORS #include <QtTest/QtTest> #include <qset.h> @@ -815,6 +816,16 @@ void tst_QSet::javaMutableIterator() int sum = 0; QMutableSetIterator<QString> i(set1); while (i.hasNext()) { + i.next(); + sum += toNumber(i.value()); + } + QVERIFY(sum == 24999 * 25000 / 2); + } + + { + int sum = 0; + QMutableSetIterator<QString> i(set1); + while (i.hasNext()) { sum += toNumber(i.peekNext()); i.next(); } diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 5dcf754..350e0d0 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -51,6 +51,7 @@ #include <QDir> #include <QVariant> #include <QDebug> +#include <QSqlTableModel> #include <QtTest/QtTest> @@ -166,6 +167,29 @@ public: return count; } + int fillTestTableWithStrategies( const QString& driverPrefix = QString() ) const + { + QTest::addColumn<QString>( "dbName" ); + QTest::addColumn<int>("submitpolicy_i"); + int count = 0; + + for ( int i = 0; i < dbNames.count(); ++i ) { + QSqlDatabase db = QSqlDatabase::database( dbNames.at( i ) ); + + if ( !db.isValid() ) + continue; + + if ( driverPrefix.isEmpty() || db.driverName().startsWith( driverPrefix ) ) { + QTest::newRow( QString("%1 [field]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnFieldChange; + QTest::newRow( QString("%1 [row]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnRowChange; + QTest::newRow( QString("%1 [manual]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnManualSubmit; + ++count; + } + } + + return count; + } + void addDb( const QString& driver, const QString& dbName, const QString& user = QString(), const QString& passwd = QString(), const QString& host = QString(), int port = -1, const QString params = QString() ) diff --git a/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp b/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp index 0ca1417..e876764 100644 --- a/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp +++ b/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp @@ -318,6 +318,11 @@ void tst_QSqlQueryModel::insertColumn() model.setQuery(QSqlQuery("select * from " + qTableName("test", __FILE__), db)); model.fetchMore(); // necessary??? + bool isToUpper = db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2"); + const QString idColumn(isToUpper ? "ID" : "id"); + const QString nameColumn(isToUpper ? "NAME" : "name"); + const QString titleColumn(isToUpper ? "TITLE" : "title"); + QSignalSpy spy(&model, SIGNAL(columnsInserted(QModelIndex, int, int))); QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); @@ -325,6 +330,11 @@ void tst_QSqlQueryModel::insertColumn() QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); QCOMPARE(model.data(model.index(0, 3)), QVariant()); + QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), idColumn); + QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), nameColumn); + QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), titleColumn); + QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), QString("4")); + QVERIFY(model.insertColumn(1)); QCOMPARE(spy.count(), 1); @@ -344,6 +354,12 @@ void tst_QSqlQueryModel::insertColumn() QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); QCOMPARE(model.data(model.index(0, 4)), QVariant()); + QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), idColumn); + QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), QString("2")); + QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), nameColumn); + QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), titleColumn); + QCOMPARE(model.headerData(4, Qt::Horizontal).toString(), QString("5")); + QVERIFY(!model.insertColumn(-1)); QVERIFY(!model.insertColumn(100)); QVERIFY(!model.insertColumn(1, model.index(1, 1))); @@ -378,14 +394,21 @@ void tst_QSqlQueryModel::insertColumn() QCOMPARE(model.indexInQuery(model.index(0, 5)).column(), -1); QCOMPARE(model.indexInQuery(model.index(0, 6)).column(), -1); - bool isToUpper = db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2"); QCOMPARE(model.record().field(0).name(), QString()); - QCOMPARE(model.record().field(1).name(), isToUpper ? QString("ID") : QString("id")); + QCOMPARE(model.record().field(1).name(), idColumn); QCOMPARE(model.record().field(2).name(), QString()); - QCOMPARE(model.record().field(3).name(), isToUpper ? QString("NAME") : QString("name")); - QCOMPARE(model.record().field(4).name(), isToUpper ? QString("TITLE") : QString("title")); + QCOMPARE(model.record().field(3).name(), nameColumn); + QCOMPARE(model.record().field(4).name(), titleColumn); QCOMPARE(model.record().field(5).name(), QString()); QCOMPARE(model.record().field(6).name(), QString()); + + QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), QString("1")); + QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), idColumn); + QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), QString("3")); + QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), nameColumn); + QCOMPARE(model.headerData(4, Qt::Horizontal).toString(), titleColumn); + QCOMPARE(model.headerData(5, Qt::Horizontal).toString(), QString("6")); + QCOMPARE(model.headerData(6, Qt::Horizontal).toString(), QString("7")); } void tst_QSqlQueryModel::record() diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index f9fcaf0..bf68375 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -78,11 +78,13 @@ private slots: void select_data() { generic_data(); } void select(); + void insertColumns_data() { generic_data_with_strategies(); } + void insertColumns(); void submitAll_data() { generic_data(); } void submitAll(); void setRecord_data() { generic_data(); } void setRecord(); - void insertRow_data() { generic_data(); } + void insertRow_data() { generic_data_with_strategies(); } void insertRow(); void insertRecord_data() { generic_data(); } void insertRecord(); @@ -92,8 +94,10 @@ private slots: void removeRow(); void removeRows_data() { generic_data(); } void removeRows(); - void removeInsertedRow_data() { generic_data(); } + void removeInsertedRow_data() { generic_data_with_strategies(); } void removeInsertedRow(); + void removeInsertedRows_data() { generic_data(); } + void removeInsertedRows(); void setFilter_data() { generic_data(); } void setFilter(); void setInvalidFilter_data() { generic_data(); } @@ -130,6 +134,7 @@ private slots: void insertBeforeDelete(); private: void generic_data(const QString& engine=QString()); + void generic_data_with_strategies(const QString& engine=QString()); }; tst_QSqlTableModel::tst_QSqlTableModel() @@ -227,7 +232,17 @@ void tst_QSqlTableModel::recreateTestTables() void tst_QSqlTableModel::generic_data(const QString &engine) { if ( dbs.fillTestTable(engine) == 0 ) { - if(engine.isEmpty()) + if (engine.isEmpty()) + QSKIP( "No database drivers are available in this Qt configuration", SkipAll ); + else + QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration").arg(engine)).toLocal8Bit(), SkipAll ); + } +} + +void tst_QSqlTableModel::generic_data_with_strategies(const QString &engine) +{ + if ( dbs.fillTestTableWithStrategies(engine) == 0 ) { + if (engine.isEmpty()) QSKIP( "No database drivers are available in this Qt configuration", SkipAll ); else QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration").arg(engine)).toLocal8Bit(), SkipAll ); @@ -289,6 +304,81 @@ void tst_QSqlTableModel::select() QCOMPARE(model.data(model.index(3, 3)), QVariant()); } +void tst_QSqlTableModel::insertColumns() +{ + // Just like the select test, with extra stuff + QFETCH(QString, dbName); + QFETCH(int, submitpolicy_i); + QSqlTableModel::EditStrategy submitpolicy = (QSqlTableModel::EditStrategy) submitpolicy_i; + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlTableModel model(0, db); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); + model.setEditStrategy(submitpolicy); + + QVERIFY_SQL(model, select()); + + QCOMPARE(model.rowCount(), 3); + QCOMPARE(model.columnCount(), 3); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 3)), QVariant()); + + QCOMPARE(model.data(model.index(1, 0)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 3)), QVariant()); + + QCOMPARE(model.data(model.index(2, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 3)), QVariant()); + + QCOMPARE(model.data(model.index(3, 0)), QVariant()); + QCOMPARE(model.data(model.index(3, 1)), QVariant()); + QCOMPARE(model.data(model.index(3, 2)), QVariant()); + QCOMPARE(model.data(model.index(3, 3)), QVariant()); + + // Now add a column at 0 and 2 + model.insertColumn(0); + model.insertColumn(2); + + QCOMPARE(model.rowCount(), 3); + QCOMPARE(model.columnCount(), 5); + + QCOMPARE(model.data(model.index(0, 0)), QVariant()); + QCOMPARE(model.data(model.index(0, 1)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 2)), QVariant()); + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 4)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 5)), QVariant()); + + QCOMPARE(model.data(model.index(1, 0)), QVariant()); + QCOMPARE(model.data(model.index(1, 1)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 2)), QVariant()); + QCOMPARE(model.data(model.index(1, 3)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 4)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 5)), QVariant()); + + QCOMPARE(model.data(model.index(2, 0)), QVariant()); + QCOMPARE(model.data(model.index(2, 1)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 2)), QVariant()); + QCOMPARE(model.data(model.index(2, 3)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(2, 4)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 5)), QVariant()); + + QCOMPARE(model.data(model.index(3, 0)), QVariant()); + QCOMPARE(model.data(model.index(3, 1)), QVariant()); + QCOMPARE(model.data(model.index(3, 2)), QVariant()); + QCOMPARE(model.data(model.index(3, 3)), QVariant()); + QCOMPARE(model.data(model.index(3, 4)), QVariant()); + QCOMPARE(model.data(model.index(3, 5)), QVariant()); +} + void tst_QSqlTableModel::setRecord() { QFETCH(QString, dbName); @@ -314,9 +404,14 @@ void tst_QSqlTableModel::setRecord() rec.setValue(2, rec.value(2).toString() + 'X'); QVERIFY(model.setRecord(i, rec)); - if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnManualSubmit) + if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnManualSubmit) { + // setRecord should emit dataChanged() itself for manualSubmit + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).count(), 2); + QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(0)), model.index(i, 0)); + QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(1)), model.index(i, rec.count() - 1)); QVERIFY(model.submitAll()); - else if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnRowChange && i == model.rowCount() -1) + } else if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnRowChange && i == model.rowCount() -1) model.submit(); else { // dataChanged() is not emitted when submitAll() is called @@ -339,26 +434,90 @@ void tst_QSqlTableModel::setRecord() void tst_QSqlTableModel::insertRow() { QFETCH(QString, dbName); + QFETCH(int, submitpolicy_i); + QSqlTableModel::EditStrategy submitpolicy = (QSqlTableModel::EditStrategy) submitpolicy_i; QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); QSqlTableModel model(0, db); - model.setEditStrategy(QSqlTableModel::OnRowChange); + model.setEditStrategy(submitpolicy); model.setTable(test); model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); + QCOMPARE(model.data(model.index(1, 0)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(2, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 3); + QVERIFY(model.insertRow(2)); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); + QCOMPARE(model.data(model.index(1, 0)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(2, 0)).toInt(), 0); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 0); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(3, 2)).toInt(), 3); + QSqlRecord rec = model.record(1); rec.setValue(0, 42); - rec.setValue(1, QString("vohi")); + rec.setValue(1, QString("francis")); + + // FieldChange updates immediately and resorts + // Row/Manual submit does not resort QVERIFY(model.setRecord(2, rec)); - QCOMPARE(model.data(model.index(2, 0)).toInt(), 42); - QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); - QCOMPARE(model.data(model.index(2, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); + QCOMPARE(model.data(model.index(1, 0)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 2)).toInt(), 2); + + // See comment above setRecord + if (submitpolicy == QSqlTableModel::OnFieldChange) { + QCOMPARE(model.data(model.index(2, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 3); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 42); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("francis")); + QCOMPARE(model.data(model.index(3, 2)).toInt(), 2); + } else { + QCOMPARE(model.data(model.index(2, 0)).toInt(), 42); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("francis")); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(3, 2)).toInt(), 3); + } QVERIFY(model.submitAll()); + + // After the submit we should have the resorted view + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 1); + QCOMPARE(model.data(model.index(1, 0)).toInt(), 2); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(2, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + QCOMPARE(model.data(model.index(2, 2)).toInt(), 3); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 42); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("francis")); + QCOMPARE(model.data(model.index(3, 2)).toInt(), 2); + } void tst_QSqlTableModel::insertRecord() @@ -538,10 +697,19 @@ void tst_QSqlTableModel::removeRows() QCOMPARE(model.rowCount(), 3); QSignalSpy beforeDeleteSpy(&model, SIGNAL(beforeDelete(int))); + + // Make sure wrong stuff is ok + QVERIFY(!model.removeRows(-1,1)); // negative start + QVERIFY(!model.removeRows(-1, 0)); // negative start, and zero count + QVERIFY(!model.removeRows(1, 0)); // zero count + QVERIFY(!model.removeRows(5, 1)); // past end (causes a beforeDelete to be emitted) + QVERIFY(!model.removeRows(1, 0, model.index(2, 0))); // can't pass a valid modelindex + QVERIFY_SQL(model, removeRows(0, 2)); - QVERIFY(beforeDeleteSpy.count() == 2); - QVERIFY(beforeDeleteSpy.at(0).at(0).toInt() == 0); - QVERIFY(beforeDeleteSpy.at(1).at(0).toInt() == 1); + QCOMPARE(beforeDeleteSpy.count(), 3); + QVERIFY(beforeDeleteSpy.at(0).at(0).toInt() == 5); + QVERIFY(beforeDeleteSpy.at(1).at(0).toInt() == 0); + QVERIFY(beforeDeleteSpy.at(2).at(0).toInt() == 1); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.data(model.index(0, 1)).toString(), QString("vohi")); model.clear(); @@ -555,6 +723,13 @@ void tst_QSqlTableModel::removeRows() // When the edit strategy is OnManualSubmit the beforeDelete() signal // isn't emitted until submitAll() is called. + + QVERIFY(!model.removeRows(-1,1)); // negative start + QVERIFY(!model.removeRows(-1, 0)); // negative start, and zero count + QVERIFY(!model.removeRows(1, 0)); // zero count + QVERIFY(!model.removeRows(5, 1)); // past end (DOESN'T cause a beforeDelete to be emitted) + QVERIFY(!model.removeRows(1, 0, model.index(2, 0))); // can't pass a valid modelindex + qRegisterMetaType<Qt::Orientation>("Qt::Orientation"); QSignalSpy headerDataChangedSpy(&model, SIGNAL(headerDataChanged(Qt::Orientation, int, int))); QVERIFY(model.removeRows(0, 2, QModelIndex())); @@ -576,33 +751,167 @@ void tst_QSqlTableModel::removeRows() void tst_QSqlTableModel::removeInsertedRow() { QFETCH(QString, dbName); + QFETCH(int, submitpolicy_i); + QSqlTableModel::EditStrategy submitpolicy = (QSqlTableModel::EditStrategy) submitpolicy_i; QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - for (int i = 0; i <= 1; ++i) { + QSqlTableModel model(0, db); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); - QSqlTableModel model(0, db); - model.setTable(test); - model.setSort(0, Qt::AscendingOrder); + model.setEditStrategy(submitpolicy); + QVERIFY_SQL(model, select()); + QCOMPARE(model.rowCount(), 3); - model.setEditStrategy(i == 0 - ? QSqlTableModel::OnRowChange : QSqlTableModel::OnManualSubmit); - QVERIFY_SQL(model, select()); - QCOMPARE(model.rowCount(), 3); + QVERIFY(model.insertRow(1)); + QCOMPARE(model.rowCount(), 4); - QVERIFY(model.insertRow(1)); - QCOMPARE(model.rowCount(), 4); + QVERIFY(model.removeRow(1)); + QCOMPARE(model.rowCount(), 3); - QVERIFY(model.removeRow(1)); - QCOMPARE(model.rowCount(), 3); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); - QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); - QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); - QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); - model.clear(); + // Now insert a row with a null, and check that removing it also works (QTBUG-15979 etc) + model.insertRow(1); + model.setData(model.index(1,0), 55); + model.setData(model.index(1,1), QString("null columns")); + model.setData(model.index(1,2), QVariant()); - recreateTestTables(); - } + model.submitAll(); + + QCOMPARE(model.rowCount(), 4); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 55); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("null columns")); + QCOMPARE(model.data(model.index(3, 2)).isNull(), true); + + QVERIFY(model.removeRow(3)); + model.submitAll(); + QCOMPARE(model.rowCount(), 3); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); +} + +void tst_QSqlTableModel::removeInsertedRows() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlTableModel model(0, db); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise + QVERIFY_SQL(model, select()); + QCOMPARE(model.rowCount(), 3); + + // First put two empty rows, and remove them one by one + QVERIFY(model.insertRows(1, 2)); + QCOMPARE(model.rowCount(), 5); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRow(1)); + QCOMPARE(model.rowCount(), 4); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRow(1)); + QCOMPARE(model.rowCount(), 3); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + + // Now put two empty rows, and remove them all at once + QVERIFY(model.insertRows(1, 2)); + QCOMPARE(model.rowCount(), 5); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRows(1, 2)); + QCOMPARE(model.rowCount(), 3); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + + + // Now put two empty rows, and remove one good and two empty + QVERIFY(model.insertRows(1, 2)); + QCOMPARE(model.rowCount(), 5); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRows(0, 3)); + QVERIFY(model.submitAll()); // otherwise the remove of the real row doesn't work + + QCOMPARE(model.rowCount(), 2); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi")); + + // Reset back again + model.clear(); + recreateTestTables(); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise + QVERIFY_SQL(model, select()); + QCOMPARE(model.rowCount(), 3); + + // Now two empty and one good + QVERIFY(model.insertRows(1, 2)); + QCOMPARE(model.rowCount(), 5); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRows(1, 3)); + QVERIFY(model.submitAll()); + QCOMPARE(model.rowCount(), 2); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi")); + + // Reset back again + model.clear(); + recreateTestTables(); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise + QVERIFY_SQL(model, select()); + QCOMPARE(model.rowCount(), 3); + + // one empty, one good, one empty + QVERIFY(model.insertRows(1, 1)); + QVERIFY(model.insertRows(3, 1)); + QCOMPARE(model.rowCount(), 5); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString()); + QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); + + QVERIFY(model.removeRows(1, 3)); + QVERIFY(model.submitAll()); + QCOMPARE(model.rowCount(), 2); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi")); } void tst_QSqlTableModel::emptyTable() diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index f3e21a0..c386ffb 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -100,6 +100,7 @@ private slots: void task188195_baseBackground(); void task232085_spinBoxLineEditBg(); void changeStyleInChangeEvent(); + void QTBUG15910_crashNullWidget(); //at the end because it mess with the style. void widgetStyle(); @@ -1626,6 +1627,24 @@ void tst_QStyleSheetStyle::changeStyleInChangeEvent() wid.ensurePolished(); } +void tst_QStyleSheetStyle::QTBUG15910_crashNullWidget() +{ + struct : QWidget { + virtual void paintEvent(QPaintEvent* ) { + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, 0); + style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, 0); + style()->drawControl(QStyle::CE_PushButton, &opt, &p, 0); + } + } w; + w.setStyleSheet("* { background-color: white; color:black; border 3px solid yellow }"); + w.show(); + QTest::qWaitForWindowShown(&w); +} + + QTEST_MAIN(tst_QStyleSheetStyle) #include "tst_qstylesheetstyle.moc" diff --git a/tests/auto/qsvgrenderer/qsvgrenderer.pro b/tests/auto/qsvgrenderer/qsvgrenderer.pro index 0b785e3..9f0f886 100644 --- a/tests/auto/qsvgrenderer/qsvgrenderer.pro +++ b/tests/auto/qsvgrenderer/qsvgrenderer.pro @@ -18,3 +18,6 @@ wince*|symbian { } } +!symbian: { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index 5928a09..9fbf2a0 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -51,6 +51,10 @@ #include <QPicture> #include <QXmlStreamReader> +#ifndef SRCDIR +#define SRCDIR +#endif + //TESTED_CLASS= //TESTED_FILES= @@ -647,13 +651,13 @@ void tst_QSvgRenderer::gradientRefs() #ifndef QT_NO_COMPRESS void tst_QSvgRenderer::testGzLoading() { - QSvgRenderer renderer(QLatin1String("heart.svgz")); + QSvgRenderer renderer(QLatin1String(SRCDIR "heart.svgz")); QVERIFY(renderer.isValid()); QSvgRenderer resourceRenderer(QLatin1String(":/heart.svgz")); QVERIFY(resourceRenderer.isValid()); - QFile largeFileGz("large.svgz"); + QFile largeFileGz(SRCDIR "large.svgz"); largeFileGz.open(QIODevice::ReadOnly); QByteArray data = largeFileGz.readAll(); QSvgRenderer autoDetectGzData(data); diff --git a/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp b/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp index a6499ff..92e8608 100644 --- a/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp +++ b/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp @@ -201,6 +201,7 @@ void tst_QtConcurrentIterateKernel::noIterations() startThreadEngine(new IterateKernel<TestIterator, void>(0, 0)).startBlocking(); } +QMutex threadsMutex; QSet<QThread *> threads; class ThrottleFor : public IterateKernel<TestIterator, void> { @@ -219,8 +220,10 @@ public: QThread *thread = QThread::currentThread(); - if (begin > 140 && end < 160) + if (begin > 140 && end < 160) { + QMutexLocker locker(&threadsMutex); threads.insert(thread); + } if (100 >= begin && 100 < end) { throttling = true; diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index c7036e4..e6bf9ce 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -86,7 +86,6 @@ private slots: void start(); void terminate(); void quit(); - void execAfterQuit(); void wait(); void started(); void finished(); @@ -266,34 +265,6 @@ public: } }; -class ExecAfterQuitThreadHelper: public QObject -{ - Q_OBJECT - QThread *thr; -public: - ExecAfterQuitThreadHelper(QThread *thr) : thr(thr) {} -public slots: - void doIt() { thr->exit(0); } -}; - -class ExecAfterQuitThread: public QThread -{ -public: - int returnValue; - void run() - { - ExecAfterQuitThreadHelper obj(this); - - QMetaObject::invokeMethod(&obj, "doIt", Qt::QueuedConnection); - exit(1); - - // returnValue will be either 0 or 1, depending on which of the two - // above take effect. The correct value is 0, since exit(1) before - // exec() should have no effect - returnValue = exec(); - } -}; - tst_QThread::tst_QThread() { @@ -453,52 +424,34 @@ void tst_QThread::stackSize() void tst_QThread::exit() { - { - Exit_Thread thread; - thread.object = new Exit_Object; - thread.object->moveToThread(&thread); - thread.code = 42; - thread.result = 0; - QVERIFY(!thread.isFinished()); - QVERIFY(!thread.isRunning()); - - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.isRunning()); - QVERIFY(!thread.isFinished()); - // but the thread is not running the event loop yet (the mutex is locked) - - // start the event loop - thread.cond.wait(locker.mutex()); - - // the Exit_Object above will cause the thread to exit - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); - QVERIFY(!thread.isRunning()); - QCOMPARE(thread.result, thread.code); - delete thread.object; - } + Exit_Thread thread; + thread.object = new Exit_Object; + thread.object->moveToThread(&thread); + thread.code = 42; + thread.result = 0; + QVERIFY(!thread.isFinished()); + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(thread.isRunning()); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); + QVERIFY(!thread.isRunning()); + QCOMPARE(thread.result, thread.code); + delete thread.object; - { - Exit_Thread thread2; - thread2.object = 0; - thread2.code = 53; - thread2.result = 0; - QMutexLocker locker2(&thread2.mutex); - thread2.start(); - - // the mutex is locked, so the thread has *not* started running the event loop yet - // this will do nothing: - thread2.exit(thread2.code); - - // the thread will now start running - thread2.cond.wait(locker2.mutex()); - - // this will cause it to exit now - thread2.exit(++thread2.code); - QVERIFY(thread2.wait(five_minutes)); - QCOMPARE(thread2.result, thread2.code); - } + Exit_Thread thread2; + thread2.object = 0; + thread2.code = 53; + thread2.result = 0; + QMutexLocker locker2(&thread2.mutex); + thread2.start(); + thread2.exit(thread2.code); + thread2.cond.wait(locker2.mutex()); + QVERIFY(thread2.wait(five_minutes)); + QCOMPARE(thread2.result, thread2.code); } void tst_QThread::start() @@ -545,59 +498,32 @@ void tst_QThread::terminate() void tst_QThread::quit() { - // very similar to exit() above - { - Quit_Thread thread; - thread.object = new Quit_Object; - thread.object->moveToThread(&thread); - thread.result = -1; - QVERIFY(!thread.isFinished()); - QVERIFY(!thread.isRunning()); - - // start the thread, but keep the event loop from starting - // (while the mutex is locked) - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.isRunning()); - QVERIFY(!thread.isFinished()); - - // unlock the mutex and let the event loop run - // the Quit_Object above will cause the thread to quit - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); - QVERIFY(!thread.isRunning()); - QCOMPARE(thread.result, 0); - delete thread.object; - } - - { - Quit_Thread thread2; - thread2.object = 0; - thread2.result = -1; - - // start the thread, but keep the event loop from starting - // (while the mutex is locked) - QMutexLocker locker2(&thread2.mutex); - thread2.start(); - thread2.quit(); // does nothing, the event loop is not running! - - // unlock the mutex and let the event loop run - thread2.cond.wait(locker2.mutex()); - - // there's no Quit_Object so it won't quit on its own - thread2.quit(); - QVERIFY(thread2.wait(five_minutes)); - QCOMPARE(thread2.result, 0); - } -} - -void tst_QThread::execAfterQuit() -{ - ExecAfterQuitThread thread; + Quit_Thread thread; + thread.object = new Quit_Object; + thread.object->moveToThread(&thread); + thread.result = -1; + QVERIFY(!thread.isFinished()); + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); thread.start(); - QVERIFY(thread.wait()); - QCOMPARE(thread.returnValue, 0); + QVERIFY(thread.isRunning()); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); + QVERIFY(!thread.isRunning()); + QCOMPARE(thread.result, 0); + delete thread.object; + + Quit_Thread thread2; + thread2.object = 0; + thread2.result = -1; + QMutexLocker locker2(&thread2.mutex); + thread2.start(); + thread2.quit(); + thread2.cond.wait(locker2.mutex()); + QVERIFY(thread2.wait(five_minutes)); + QCOMPARE(thread2.result, 0); } void tst_QThread::wait() @@ -1068,17 +994,8 @@ void tst_QThread::QTBUG15378_exitAndExec() Thread thread; thread.value = 0; thread.start(); - thread.exit(42); // will do nothing, this value should not appear - thread.sem1.release(); //should enter the first loop - - Exit_Object *exit_object = new Exit_Object; - exit_object->code = 556; - exit_object->thread = &thread; - QMetaObject::invokeMethod(exit_object, "slot", Qt::QueuedConnection); - exit_object->deleteLater(); - exit_object->moveToThread(&thread); // should exit the first loop - exit_object = 0; - + thread.exit(556); + thread.sem1.release(); //should exit the first loop thread.sem2.acquire(); int v = thread.value; QCOMPARE(v, 556); |