diff options
Diffstat (limited to 'tests/auto')
96 files changed, 6168 insertions, 3230 deletions
diff --git a/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro b/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro index 21cab8f67d..7b374505ce 100644 --- a/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro +++ b/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro @@ -1,3 +1,4 @@ +CONFIG += testcase QT += testlib core-private QT -= gui diff --git a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp index f792b34d48..3b730d97f9 100644 --- a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp +++ b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp @@ -151,7 +151,7 @@ void tst_QBuffer::readBlock() QCOMPARE(b.bytesAvailable(), (qint64) arraySize); b.open(QIODevice::WriteOnly); QCOMPARE(b.bytesAvailable(), (qint64) arraySize); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read (QBuffer): WriteOnly device"); QCOMPARE(b.read(a, arraySize), (qint64) -1); // no read access b.close(); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 98963108be..5025dd38db 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -2334,7 +2334,7 @@ void tst_QFile::readFromWriteOnlyFile() QFile file("writeonlyfile"); QVERIFY(file.open(QFile::WriteOnly)); char c; - QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read (QFile, \"writeonlyfile\"): WriteOnly device"); QCOMPARE(file.read(&c, 1), qint64(-1)); } @@ -2343,7 +2343,7 @@ void tst_QFile::writeToReadOnlyFile() QFile file("readonlyfile"); QVERIFY(file.open(QFile::ReadOnly)); char c = 0; - QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::write (QFile, \"readonlyfile\"): ReadOnly device"); QCOMPARE(file.write(&c, 1), qint64(-1)); } diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp index f756588e80..565ca18899 100644 --- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -224,7 +224,7 @@ void tst_QIODevice::unget() buf[0] = '@'; buf[1] = '@'; QTest::ignoreMessage(QtWarningMsg, - "QIODevice::readLine: Called with maxSize < 2"); + "QIODevice::readLine (QBuffer): Called with maxSize < 2"); QCOMPARE(buffer.readLine(buf, 1), qint64(-1)); QCOMPARE(buffer.readLine(buf, 2), qint64(i < 4 ? 1 : -1)); switch (i) { diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index bef3d3a012..27614e0eb8 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -57,11 +57,16 @@ private slots: void waitForLock(); void staleLockFromCrashedProcess_data(); void staleLockFromCrashedProcess(); + void staleLockFromCrashedProcessReusedPid(); void staleShortLockFromBusyProcess(); void staleLongLockFromBusyProcess(); void staleLockRace(); void noPermissions(); void noPermissionsWindows(); + void corruptedLockFile(); + +private: + static bool overwritePidInLockFile(const QString &filePath, qint64 pid); public: QString m_helperApp; @@ -276,6 +281,30 @@ void tst_QLockFile::staleLockFromCrashedProcess() #endif // !QT_NO_PROCESS } +void tst_QLockFile::staleLockFromCrashedProcessReusedPid() +{ +#if defined(QT_NO_PROCESS) + QSKIP("This test requires QProcess support"); +#elif defined(Q_OS_WINRT) || defined(Q_OS_WINCE) || defined(Q_OS_IOS) + QSKIP("We cannot retrieve information about other processes on this platform."); +#else + const QString fileName = dir.path() + "/staleLockFromCrashedProcessReusedPid"; + + int ret = QProcess::execute(m_helperApp, QStringList() << fileName << "-crash"); + QCOMPARE(ret, int(QLockFile::NoError)); + QVERIFY(QFile::exists(fileName)); + QVERIFY(overwritePidInLockFile(fileName, QCoreApplication::applicationPid())); + + QLockFile secondLock(fileName); + qint64 pid = 0; + secondLock.getLockInfo(&pid, 0, 0); + QCOMPARE(pid, QCoreApplication::applicationPid()); + secondLock.setStaleLockTime(0); + QVERIFY(secondLock.tryLock()); + QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +#endif // !QT_NO_PROCESS +} + void tst_QLockFile::staleShortLockFromBusyProcess() { #ifdef QT_NO_PROCESS @@ -480,5 +509,41 @@ void tst_QLockFile::noPermissionsWindows() QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError)); } +void tst_QLockFile::corruptedLockFile() +{ + const QString fileName = dir.path() + "/corruptedLockFile"; + + { + // Create a empty file. Typically the result of a computer crash or hard disk full. + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly)); + } + + QLockFile secondLock(fileName); + secondLock.setStaleLockTime(100); + QVERIFY(secondLock.tryLock(10000)); + QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +} + +bool tst_QLockFile::overwritePidInLockFile(const QString &filePath, qint64 pid) +{ + QFile f(filePath); + if (!f.open(QFile::ReadWrite)) { + qWarning("Cannot open %s.", qPrintable(filePath)); + return false; + } + QByteArray buf = f.readAll(); + int i = buf.indexOf('\n'); + if (i < 0) { + qWarning("Unexpected lockfile content."); + return false; + } + buf.remove(0, i); + buf.prepend(QByteArray::number(pid)); + f.seek(0); + f.resize(buf.size()); + return f.write(buf) == buf.size(); +} + QTEST_MAIN(tst_QLockFile) #include "tst_qlockfile.moc" diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index ff4963a960..924db17c04 100644 --- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -112,6 +112,22 @@ void tst_QCoreApplication::qAppName() // The application name should still be available after destruction; // global statics often rely on this. QCOMPARE(QCoreApplication::applicationName(), QString::fromLatin1(appName)); + + // Setting the appname before creating the application should work (QTBUG-45283) + const QString wantedAppName("my app name"); + { + int argc = 1; + char *argv[] = { const_cast<char*>(appName) }; + QCoreApplication::setApplicationName(wantedAppName); + TestApplication app(argc, argv); + QCOMPARE(::qAppName(), QString::fromLatin1(appName)); + QCOMPARE(QCoreApplication::applicationName(), wantedAppName); + } + QCOMPARE(QCoreApplication::applicationName(), wantedAppName); + + // Restore to initial value + QCoreApplication::setApplicationName(QString()); + QCOMPARE(QCoreApplication::applicationName(), QString()); } void tst_QCoreApplication::argc() diff --git a/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp b/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp index 17b00ebf63..5a10cf51e6 100644 --- a/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp +++ b/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp @@ -91,5 +91,13 @@ void tst_QMetaEnum::valuesToKeys() QCOMPARE(me.valueToKeys(windowFlags), expected); } +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper<tst_QMetaEnum::SuperEnum>::Value); +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper<Qt::WindowFlags>::Value); +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper<Qt::Orientation>::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper<int>::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper<QObject>::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper<QObject*>::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper<void>::Value); + QTEST_MAIN(tst_QMetaEnum) #include "tst_qmetaenum.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index b3333c6d68..9cdb1f47f8 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -142,8 +142,14 @@ public: class CustomGadget { Q_GADGET }; +class CustomGadget_NonDefaultConstructible { + Q_GADGET +public: + CustomGadget_NonDefaultConstructible(int) {}; +}; class CustomNonQObject {}; +class GadgetDerived : public CustomGadget {}; void tst_QMetaType::defined() { @@ -153,11 +159,12 @@ void tst_QMetaType::defined() QCOMPARE(int(QMetaTypeId2<int*>::Defined), 0); QCOMPARE(int(QMetaTypeId2<CustomQObject::CustomQEnum>::Defined), 1); QCOMPARE(int(QMetaTypeId2<CustomGadget>::Defined), 1); + QVERIFY(!QMetaTypeId2<GadgetDerived>::Defined); QVERIFY(int(QMetaTypeId2<CustomQObject*>::Defined)); QVERIFY(!QMetaTypeId2<CustomQObject>::Defined); QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined); QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined); - QVERIFY(!QMetaTypeId2<CustomGadget*>::Defined); + QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined); } struct Bar diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 263cc5a07a..3ec84b5198 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -128,6 +128,7 @@ private slots: void connectWithReference(); void connectManyArguments(); void connectForwardDeclare(); + void connectNoDefaultConstructorArg(); void returnValue_data(); void returnValue(); void returnValue2_data(); @@ -5227,6 +5228,29 @@ void tst_QObject::connectForwardDeclare() QVERIFY(connect(&ob, &ForwardDeclareArguments::mySignal, &ob, &ForwardDeclareArguments::mySlot, Qt::QueuedConnection)); } +class NoDefaultConstructor +{ + Q_GADGET +public: + NoDefaultConstructor(int) {} +}; + +class NoDefaultContructorArguments : public QObject +{ + Q_OBJECT +signals: + void mySignal(const NoDefaultConstructor&); +public slots: + void mySlot(const NoDefaultConstructor&) {} +}; + +void tst_QObject::connectNoDefaultConstructorArg() +{ + NoDefaultContructorArguments ob; + // it should compile + QVERIFY(connect(&ob, &NoDefaultContructorArguments::mySignal, &ob, &NoDefaultContructorArguments::mySlot, Qt::QueuedConnection)); +} + class ReturnValue : public QObject { friend class tst_QObject; Q_OBJECT diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index 96d0a62f6b..1292c3b98f 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -247,6 +247,9 @@ private slots: void qtbug_44963(); void qtbug_44783(); + void internalTransition(); + void conflictingTransition(); + void qtbug_46059(); }; class TestState : public QState @@ -256,10 +259,12 @@ public: Entry, Exit }; - TestState(QState *parent) - : QState(parent) {} - TestState(ChildMode mode) - : QState(mode) {} + TestState(QState *parent, const QString &objectName = QString()) + : QState(parent) + { setObjectName(objectName); } + TestState(ChildMode mode, const QString &objectName = QString()) + : QState(mode) + { setObjectName(objectName); } QList<QPair<int, Event> > events; protected: virtual void onEntry(QEvent *) { @@ -273,9 +278,9 @@ protected: class TestTransition : public QAbstractTransition { public: - TestTransition(QAbstractState *target) + TestTransition(QAbstractState *target, const QString &objectName = QString()) : QAbstractTransition() - { setTargetState(target); } + { setTargetState(target); setObjectName(objectName); } QList<int> triggers; protected: virtual bool eventTest(QEvent *) { @@ -1352,15 +1357,16 @@ void tst_QStateMachine::stateEntryAndExit() { QStateMachine machine; - TestState *s1 = new TestState(&machine); - TestState *s11 = new TestState(s1); - TestState *s12 = new TestState(s1); - TestState *s2 = new TestState(&machine); + TestState *s1 = new TestState(&machine, "s1"); + TestState *s11 = new TestState(s1, "s11"); + TestState *s12 = new TestState(s1, "s12"); + TestState *s2 = new TestState(&machine, "s2"); QFinalState *s3 = new QFinalState(&machine); + s3->setObjectName("s3"); s1->setInitialState(s11); - TestTransition *t1 = new TestTransition(s12); + TestTransition *t1 = new TestTransition(s12, "t1"); s11->addTransition(t1); - TestTransition *t2 = new TestTransition(s2); + TestTransition *t2 = new TestTransition(s2, "t2"); s12->addTransition(t2); s2->addTransition(s3); @@ -6335,5 +6341,149 @@ void tst_QStateMachine::qtbug_44783() QVERIFY(machine.isRunning()); } +void tst_QStateMachine::internalTransition() +{ + SignalEmitter emitter; + + QStateMachine machine; + QState *s = new QState(&machine); + QState *s1 = new QState(s); + QState *s11 = new QState(s1); + + DEFINE_ACTIVE_SPY(s); + DEFINE_ACTIVE_SPY(s1); + DEFINE_ACTIVE_SPY(s11); + + machine.setInitialState(s); + s->setInitialState(s1); + s1->setInitialState(s11); + QSignalTransition *t = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s11); + t->setObjectName("s1->s11"); + t->setTransitionType(QAbstractTransition::InternalTransition); + + s->setObjectName("s"); + s1->setObjectName("s1"); + s11->setObjectName("s11"); + + machine.start(); + + QTRY_COMPARE(machine.configuration().contains(s), true); + QTRY_COMPARE(machine.configuration().contains(s1), true); + QTRY_COMPARE(machine.configuration().contains(s11), true); + TEST_ACTIVE_CHANGED(s, 1); + TEST_ACTIVE_CHANGED(s1, 1); + TEST_ACTIVE_CHANGED(s11, 1); + + emitter.emitSignalWithNoArg(); + + QTRY_COMPARE(machine.configuration().contains(s), true); + QTRY_COMPARE(machine.configuration().contains(s1), true); + QTRY_COMPARE(machine.configuration().contains(s11), true); + TEST_ACTIVE_CHANGED(s11, 3); + TEST_ACTIVE_CHANGED(s1, 1); // external transitions will return 3, internal transitions should return 1. + TEST_ACTIVE_CHANGED(s, 1); +} + +void tst_QStateMachine::conflictingTransition() +{ + SignalEmitter emitter; + + QStateMachine machine; + QState b(QState::ParallelStates, &machine); + QState c(&b); + QState d(QState::ParallelStates, &b); + QState e(&d); + QState e1(&e); + QState e2(&e); + QState f(&d); + QState f1(&f); + QState f2(&f); + QState a1(&machine); + + machine.setInitialState(&b); + e.setInitialState(&e1); + f.setInitialState(&f1); + c.addTransition(&emitter, SIGNAL(signalWithNoArg()), &a1)->setObjectName("c->a1"); + e1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &e2)->setObjectName("e1->e2"); + f1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &f2)->setObjectName("f1->f2"); + + b.setObjectName("b"); + c.setObjectName("c"); + d.setObjectName("d"); + e.setObjectName("e"); + e1.setObjectName("e1"); + e2.setObjectName("e2"); + f.setObjectName("f"); + f1.setObjectName("f1"); + f2.setObjectName("f2"); + a1.setObjectName("a1"); + + machine.start(); + + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), true); + QTRY_COMPARE(machine.configuration().contains(&d), true); + QTRY_COMPARE(machine.configuration().contains(&e), true); + QTRY_COMPARE(machine.configuration().contains(&e1), true); + QTRY_COMPARE(machine.configuration().contains(&e2), false); + QTRY_COMPARE(machine.configuration().contains(&f), true); + QTRY_COMPARE(machine.configuration().contains(&f1), true); + QTRY_COMPARE(machine.configuration().contains(&f2), false); + QTRY_COMPARE(machine.configuration().contains(&a1), false); + + emitter.emitSignalWithNoArg(); + + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), true); + QTRY_COMPARE(machine.configuration().contains(&d), true); + QTRY_COMPARE(machine.configuration().contains(&e), true); + QTRY_COMPARE(machine.configuration().contains(&e1), false); + QTRY_COMPARE(machine.configuration().contains(&e2), true); + QTRY_COMPARE(machine.configuration().contains(&f), true); + QTRY_COMPARE(machine.configuration().contains(&f1), false); + QTRY_COMPARE(machine.configuration().contains(&f2), true); + QTRY_COMPARE(machine.configuration().contains(&a1), false); + + QVERIFY(machine.isRunning()); +} + +void tst_QStateMachine::qtbug_46059() +{ + QStateMachine machine; + QState a(&machine); + QState b(&a); + QState c(&a); + QState success(&a); + QState failure(&machine); + + machine.setInitialState(&a); + a.setInitialState(&b); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), &c)); + c.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &success)); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &failure)); + + machine.start(); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), false); + + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 0)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 2)), QStateMachine::NormalPriority); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), false); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), true); + + QVERIFY(machine.isRunning()); +} + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" diff --git a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp index 01855a730e..76687bd478 100644 --- a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp +++ b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp @@ -43,6 +43,8 @@ class tst_QContiguousCache : public QObject { Q_OBJECT private slots: + void assignment(); + void empty(); void swap(); @@ -64,6 +66,16 @@ private slots: QTEST_MAIN(tst_QContiguousCache) +void tst_QContiguousCache::assignment() +{ + // compile-only test: QTBUG-45783 + QContiguousCache<int> cc1, cc2; + // copy: + cc1 = cc2; + // move: + cc1 = qMove(cc2); +} + void tst_QContiguousCache::empty() { QContiguousCache<int> c(10); diff --git a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp index 11c292db91..a07247316e 100644 --- a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp @@ -39,10 +39,7 @@ #include <QtDBus/private/qdbusutil_p.h> #include <QtDBus/private/qdbusconnection_p.h> - -#define QT_LINKED_LIBDBUS -#include <QtDBus/private/qdbusutil_p.h> -#include <QtDBus/private/qdbusconnection_p.h> +#include <QtDBus/private/qdbus_symbols_p.h> static const char serviceName[] = "org.qtproject.autotests.qpong"; static const char objectPath[] = "/org/qtproject/qpong"; @@ -85,10 +82,8 @@ private slots: void sendCallErrors_data(); void sendCallErrors(); -#ifdef DBUS_TYPE_UNIX_FD void receiveUnknownType_data(); void receiveUnknownType(); -#endif void demarshallPrimitives_data(); void demarshallPrimitives(); @@ -1017,7 +1012,6 @@ void tst_QDBusMarshall::sendCallErrors() QCOMPARE(reply.errorMessage(), errorMsg); } -#ifdef DBUS_TYPE_UNIX_FD // If DBUS_TYPE_UNIX_FD is not defined, it means the current system's D-Bus library is too old for this test void tst_QDBusMarshall::receiveUnknownType_data() { @@ -1075,6 +1069,27 @@ public: } }; +// mostly the same as qdbusintegrator.cpp:connectionCapabilies +static bool canSendUnixFd(DBusConnection *connection) +{ + typedef dbus_bool_t (*can_send_type_t)(DBusConnection *, int); + static can_send_type_t can_send_type = 0; + +#if defined(QT_LINKED_LIBDBUS) +# if DBUS_VERSION-0 >= 0x010400 + can_send_type = dbus_connection_can_send_type; +# endif +#else + // run-time check if the next functions are available + can_send_type = (can_send_type_t)qdbus_resolve_conditionally("dbus_connection_can_send_type"); +#endif + +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +#endif + return can_send_type && can_send_type(connection, DBUS_TYPE_UNIX_FD); +} + void tst_QDBusMarshall::receiveUnknownType() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -1088,7 +1103,8 @@ void tst_QDBusMarshall::receiveUnknownType() QVERIFY2(rawcon.data(), error.name); // check if this bus supports passing file descriptors - if (!q_dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD)) + + if (!canSendUnixFd(rawcon.data())) QSKIP("Your session bus does not allow sending Unix file descriptors"); // make sure this QDBusConnection won't handle Unix file descriptors @@ -1184,7 +1200,6 @@ void tst_QDBusMarshall::receiveUnknownType() QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); } } -#endif void tst_QDBusMarshall::demarshallPrimitives_data() { diff --git a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp index ced73dbf3b..63444b61ad 100644 --- a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp +++ b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp @@ -87,8 +87,19 @@ static void addFixedTypes() QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; + #ifdef DBUS_TYPE_UNIX_FD_AS_STRING - QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; +# ifndef QT_LINKED_LIBDBUS + // We have got the macro from dbus_minimal_p.h, so we need to check if + // the library recognizes this as valid type first. + // The following function was added for Unix FD support, so if it is + // present, so is support for Unix FDs. + bool supportsUnixFds = qdbus_resolve_conditionally("dbus_connection_can_send_type"); +# else + bool supportsUnixFds = true; +# endif + if (supportsUnixFds) + QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; #endif } diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg Binary files differnew file mode 100644 index 0000000000..97deae3e25 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 2931185c8b..da29a57f98 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -184,6 +184,8 @@ private slots: void exifOrientation_data(); void exifOrientation(); + void exif_QTBUG45865(); + void cleanupFunctions(); void devicePixelRatio(); @@ -2816,31 +2818,56 @@ void tst_QImage::invertPixelsRGB() void tst_QImage::exifOrientation_data() { QTest::addColumn<QString>("fileName"); - QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg"; - QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg"; - QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg"; - QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg"; - QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg"; - QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg"; - QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg"; - QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg"; - QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg"; -} + QTest::addColumn<int>("orientation"); + QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg" << (int)QImageIOHandler::TransformationNone; + QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg" << (int)QImageIOHandler::TransformationMirror; + QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg" << (int)QImageIOHandler::TransformationRotate180; + QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg" << (int)QImageIOHandler::TransformationFlip; + QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg" << (int)QImageIOHandler::TransformationFlipAndRotate90; + QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg" << (int)QImageIOHandler::TransformationMirrorAndRotate90; + QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg" << (int)QImageIOHandler::TransformationRotate270; +} + +QT_BEGIN_NAMESPACE +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); +QT_END_NAMESPACE +QT_USE_NAMESPACE void tst_QImage::exifOrientation() { QFETCH(QString, fileName); + QFETCH(int, orientation); - QImage img; + QImageReader imageReader(fileName); + imageReader.setAutoTransform(true); + QCOMPARE(imageReader.transformation(), orientation); + QImage img = imageReader.read(); QRgb px; - - QVERIFY(img.load(fileName)); + QVERIFY(!img.isNull()); px = img.pixel(0, 0); QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5); px = img.pixel(img.width() - 1, 0); QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250); + + QImageReader imageReader2(fileName); + QCOMPARE(imageReader2.autoTransform(), false); + QCOMPARE(imageReader2.transformation(), orientation); + QImage img2 = imageReader2.read(); + qt_imageTransform(img2, imageReader2.transformation()); + QCOMPARE(img, img2); +} + +void tst_QImage::exif_QTBUG45865() +{ + QFile file(m_prefix + "jpeg_exif_QTBUG-45865.jpg"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QByteArray byteArray = file.readAll(); + QImage image = QImage::fromData(byteArray); + QCOMPARE(image.size(), QSize(5, 8)); } static void cleanupFunction(void* info) diff --git a/tests/auto/gui/kernel/qtouchevent/BLACKLIST b/tests/auto/gui/kernel/qtouchevent/BLACKLIST new file mode 100644 index 0000000000..8e78d7e41f --- /dev/null +++ b/tests/auto/gui/kernel/qtouchevent/BLACKLIST @@ -0,0 +1,6 @@ +[basicRawEventTranslation] +linux +[multiPointRawEventTranslationOnTouchScreen] +linux +[multiPointRawEventTranslationOnTouchPad] +linux diff --git a/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro index 7136611165..b1e3c10724 100644 --- a/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro +++ b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro @@ -1,3 +1,5 @@ +CONFIG += testcase +osx: CONFIG += insignificant_test # QTBUG-46266, crashes SOURCES=tst_qtouchevent.cpp TARGET=tst_qtouchevent QT += testlib widgets gui-private diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp index fe11f39242..aa1f573aa9 100644 --- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -31,11 +31,16 @@ ** ****************************************************************************/ -#include <QtGui> -#include <QtWidgets> +#include <QtWidgets/QDesktopWidget> +#include <QtWidgets/QGraphicsItem> +#include <QtWidgets/QGraphicsScene> +#include <QtWidgets/QGraphicsView> +#include <QtWidgets/QGraphicsWidget> +#include <QtWidgets/QWidget> #include <QtTest> #include <qpa/qwindowsysteminterface.h> +// FIXME: Use static functions of QWindowSystemInterface introduced with HighDPI scaling in 5.6 instead. static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt) { QWindowSystemInterface::TouchPoint p; @@ -72,8 +77,7 @@ public: ulong timestamp; QTouchDevice *deviceFromEvent; - tst_QTouchEventWidget() - : QWidget() + explicit tst_QTouchEventWidget(QWidget *parent = Q_NULLPTR) : QWidget(parent) { reset(); } @@ -88,7 +92,7 @@ public: deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } - bool event(QEvent *event) + bool event(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()) { case QEvent::TouchBegin: @@ -142,8 +146,8 @@ public: bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventGraphicsItem **weakpointer; - tst_QTouchEventGraphicsItem() - : QGraphicsItem(), weakpointer(0) + explicit tst_QTouchEventGraphicsItem(QGraphicsItem *parent = Q_NULLPTR) + : QGraphicsItem(parent), weakpointer(0) { reset(); } @@ -165,10 +169,10 @@ public: deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } - QRectF boundingRect() const { return QRectF(0, 0, 10, 10); } - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) { } + QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(0, 0, 10, 10); } + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE { } - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()) { case QEvent::TouchBegin: @@ -214,9 +218,9 @@ class tst_QTouchEvent : public QObject Q_OBJECT public: tst_QTouchEvent(); - ~tst_QTouchEvent() { } private slots: + void cleanup(); void touchDisabledByDefault(); void touchEventAcceptedByDefault(); void touchBeginPropagatesWhenIgnored(); @@ -236,15 +240,18 @@ private: QTouchDevice *touchPadDevice; }; -tst_QTouchEvent::tst_QTouchEvent() +tst_QTouchEvent::tst_QTouchEvent() : touchScreenDevice(new QTouchDevice), touchPadDevice(new QTouchDevice) { - touchScreenDevice = new QTouchDevice; - touchPadDevice = new QTouchDevice; touchPadDevice->setType(QTouchDevice::TouchPad); QWindowSystemInterface::registerTouchDevice(touchScreenDevice); QWindowSystemInterface::registerTouchDevice(touchPadDevice); } +void tst_QTouchEvent::cleanup() +{ + QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); +} + void tst_QTouchEvent::touchDisabledByDefault() { // QWidget @@ -261,8 +268,7 @@ void tst_QTouchEvent::touchDisabledByDefault() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&widget, &touchEvent); - QVERIFY(!res); + QVERIFY(!QApplication::sendEvent(&widget, &touchEvent)); QVERIFY(!touchEvent.isAccepted()); } @@ -290,8 +296,7 @@ void tst_QTouchEvent::touchDisabledByDefault() Qt::NoModifier, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(!res); + QVERIFY(!QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(!touchEvent.isAccepted()); QVERIFY(!item.seenTouchBegin); } @@ -299,7 +304,7 @@ void tst_QTouchEvent::touchDisabledByDefault() void tst_QTouchEvent::touchEventAcceptedByDefault() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); // QWidget @@ -317,16 +322,14 @@ void tst_QTouchEvent::touchEventAcceptedByDefault() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&widget, &touchEvent); - QVERIFY(res); - QVERIFY(touchEvent.isAccepted()); + QVERIFY(QApplication::sendEvent(&widget, &touchEvent)); + QVERIFY(!touchEvent.isAccepted()); // Qt 5.X ignores touch events. // tst_QTouchEventWidget does handle, sending succeeds tst_QTouchEventWidget touchWidget; touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchEvent.ignore(); - res = QApplication::sendEvent(&touchWidget, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&touchWidget, &touchEvent)); QVERIFY(touchEvent.isAccepted()); } @@ -355,8 +358,7 @@ void tst_QTouchEvent::touchEventAcceptedByDefault() Qt::NoModifier, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(item.seenTouchBegin); } @@ -383,8 +385,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&grandchild, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -398,8 +399,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() grandchild.setAttribute(Qt::WA_AcceptTouchEvents, false); touchEvent.ignore(); - res = QApplication::sendEvent(&grandchild, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(!grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -435,8 +435,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -471,8 +470,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(!grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -499,8 +497,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&child, &touchBeginEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchBeginEvent)); QVERIFY(touchBeginEvent.isAccepted()); QVERIFY(child.seenTouchBegin); QVERIFY(!window.seenTouchBegin); @@ -511,8 +508,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointMoved, touchPoints); - res = QApplication::sendEvent(&child, &touchUpdateEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchUpdateEvent)); QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); QVERIFY(!window.seenTouchUpdate); @@ -523,8 +519,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - res = QApplication::sendEvent(&child, &touchEndEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchEndEvent)); QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); QVERIFY(!window.seenTouchEnd); @@ -558,8 +553,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); QVERIFY(touchBeginEvent.isAccepted()); QVERIFY(child.seenTouchBegin); QVERIFY(!root.seenTouchBegin); @@ -571,8 +565,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointMoved, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); // the scene accepts the event, since it found an item to send the event to QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); @@ -585,8 +578,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointReleased, (QList<QTouchEvent::TouchPoint>() << touchPoint)); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); // the scene accepts the event, since it found an item to send the event to QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); @@ -601,17 +593,20 @@ QPointF normalized(const QPointF &pos, const QRectF &rect) void tst_QTouchEvent::basicRawEventTranslation() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF pos = touchWidget.rect().center(); QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint()); QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QTouchEvent::TouchPoint rawTouchPoint; rawTouchPoint.setId(0); @@ -726,24 +721,24 @@ void tst_QTouchEvent::basicRawEventTranslation() void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); - tst_QTouchEventWidget leftWidget; - leftWidget.setParent(&touchWidget); + tst_QTouchEventWidget leftWidget(&touchWidget); leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); leftWidget.setGeometry(0, 100, 100, 100); - leftWidget.show(); - tst_QTouchEventWidget rightWidget; - rightWidget.setParent(&touchWidget); + tst_QTouchEventWidget rightWidget(&touchWidget); rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); rightWidget.setGeometry(300, 100, 100, 100); - rightWidget.show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF leftPos = leftWidget.rect().center(); QPointF rightPos = rightWidget.rect().center(); @@ -751,8 +746,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -956,24 +950,25 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); - tst_QTouchEventWidget leftWidget; - leftWidget.setParent(&touchWidget); + tst_QTouchEventWidget leftWidget(&touchWidget); leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); leftWidget.setGeometry(0, 100, 100, 100); - leftWidget.show(); + leftWidget.acceptTouchBegin =true; - tst_QTouchEventWidget rightWidget; - rightWidget.setParent(&touchWidget); + tst_QTouchEventWidget rightWidget(&touchWidget); rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); rightWidget.setGeometry(300, 100, 100, 100); - rightWidget.show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF leftPos = leftWidget.rect().center(); QPointF rightPos = rightWidget.rect().center(); @@ -981,8 +976,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -1003,7 +997,8 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() QVERIFY(!touchWidget.seenTouchBegin); QVERIFY(!touchWidget.seenTouchUpdate); QVERIFY(!touchWidget.seenTouchEnd); - QVERIFY(leftWidget.seenTouchBegin); + QEXPECT_FAIL("", "QTBUG-46266, fails in Qt 5", Abort); + QVERIFY(!leftWidget.seenTouchBegin); QVERIFY(!leftWidget.seenTouchUpdate); QVERIFY(!leftWidget.seenTouchEnd); QVERIFY(!rightWidget.seenTouchBegin); @@ -1186,19 +1181,15 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() void tst_QTouchEvent::deleteInEventHandler() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); // QWidget { QWidget window; - tst_QTouchEventWidget *child1, *child2, *child3; - child1 = new tst_QTouchEventWidget; - child2 = new tst_QTouchEventWidget; - child3 = new tst_QTouchEventWidget; - child1->setParent(&window); - child2->setParent(&window); - child3->setParent(&window); + QPointer<tst_QTouchEventWidget> child1 = new tst_QTouchEventWidget(&window); + QPointer<tst_QTouchEventWidget> child2 = new tst_QTouchEventWidget(&window); + QPointer<tst_QTouchEventWidget> child3 = new tst_QTouchEventWidget(&window); child1->setAttribute(Qt::WA_AcceptTouchEvents); child2->setAttribute(Qt::WA_AcceptTouchEvents); child3->setAttribute(Qt::WA_AcceptTouchEvents); @@ -1223,47 +1214,43 @@ void tst_QTouchEvent::deleteInEventHandler() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - QPointer<QWidget> p; - bool res; - touchBeginEvent.ignore(); - p = child1; - res = QApplication::sendEvent(child1, &touchBeginEvent); + QVERIFY(QApplication::sendEvent(child1, &touchBeginEvent)); // event is handled, but widget should be deleted - QVERIFY(res && touchBeginEvent.isAccepted() && p.isNull()); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child1.isNull()); touchBeginEvent.ignore(); - p = child2; - res = QApplication::sendEvent(child2, &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child2, &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child2.isNull()); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(child2, &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && p.isNull()); + QVERIFY(QApplication::sendEvent(child2, &touchUpdateEvent)); + QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(child2.isNull()); touchBeginEvent.ignore(); - p = child3; - res = QApplication::sendEvent(child3, &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child3.isNull()); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(child3, &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchUpdateEvent)); + QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(!child3.isNull()); touchEndEvent.ignore(); - res = QApplication::sendEvent(child3, &touchEndEvent); - QVERIFY(res && touchEndEvent.isAccepted() && p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchEndEvent)); + QVERIFY(touchEndEvent.isAccepted()); + QVERIFY(child3.isNull()); } // QGraphicsView { QGraphicsScene scene; QGraphicsView view(&scene); - tst_QTouchEventGraphicsItem *root, *child1, *child2, *child3; - root = new tst_QTouchEventGraphicsItem; - child1 = new tst_QTouchEventGraphicsItem; - child2 = new tst_QTouchEventGraphicsItem; - child3 = new tst_QTouchEventGraphicsItem; - child1->setParentItem(root); - child2->setParentItem(root); - child3->setParentItem(root); + QScopedPointer<tst_QTouchEventGraphicsItem> root(new tst_QTouchEventGraphicsItem); + tst_QTouchEventGraphicsItem *child1 = new tst_QTouchEventGraphicsItem(root.data()); + tst_QTouchEventGraphicsItem *child2 = new tst_QTouchEventGraphicsItem(root.data()); + tst_QTouchEventGraphicsItem *child3 = new tst_QTouchEventGraphicsItem(root.data()); child1->setZValue(1.); child2->setZValue(0.); child3->setZValue(-1.); @@ -1274,7 +1261,7 @@ void tst_QTouchEvent::deleteInEventHandler() child2->deleteInTouchUpdate = true; child3->deleteInTouchEnd = true; - scene.addItem(root); + scene.addItem(root.data()); view.resize(200, 200); view.fitInView(scene.sceneRect()); @@ -1302,71 +1289,75 @@ void tst_QTouchEvent::deleteInEventHandler() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - bool res; child1->weakpointer = &child1; touchBeginEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child1); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); // Qt 5.X ignores touch events. + QVERIFY(!child1); touchEndEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child1); child2->weakpointer = &child2; touchBeginEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child2); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child2); touchEndEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child2); child3->weakpointer = &child3; - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && child3); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && child3); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && !touchEndEvent.isAccepted() && !child3); - - delete root; + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child3); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(child3); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchEndEvent.isAccepted()); + QVERIFY(!child3); } } void tst_QTouchEvent::deleteInRawEventTranslation() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 300, 300); - tst_QTouchEventWidget *leftWidget = new tst_QTouchEventWidget; - leftWidget->setParent(&touchWidget); + QPointer<tst_QTouchEventWidget> leftWidget = new tst_QTouchEventWidget(&touchWidget); leftWidget->setAttribute(Qt::WA_AcceptTouchEvents); leftWidget->setGeometry(0, 100, 100, 100); leftWidget->deleteInTouchBegin = true; - leftWidget->show(); - tst_QTouchEventWidget *centerWidget = new tst_QTouchEventWidget; - centerWidget->setParent(&touchWidget); + QPointer<tst_QTouchEventWidget> centerWidget = new tst_QTouchEventWidget(&touchWidget); centerWidget->setAttribute(Qt::WA_AcceptTouchEvents); centerWidget->setGeometry(100, 100, 100, 100); centerWidget->deleteInTouchUpdate = true; - centerWidget->show(); - tst_QTouchEventWidget *rightWidget = new tst_QTouchEventWidget; - rightWidget->setParent(&touchWidget); + QPointer<tst_QTouchEventWidget> rightWidget = new tst_QTouchEventWidget(&touchWidget); rightWidget->setAttribute(Qt::WA_AcceptTouchEvents); rightWidget->setGeometry(200, 100, 100, 100); rightWidget->deleteInTouchEnd = true; - rightWidget->show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&touchWidget)); QPointF leftPos = leftWidget->rect().center(); QPointF centerPos = centerWidget->rect().center(); @@ -1374,9 +1365,7 @@ void tst_QTouchEvent::deleteInRawEventTranslation() QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); - - QPointer<QWidget> pl = leftWidget, pc = centerWidget, pr = rightWidget; + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -1398,7 +1387,9 @@ void tst_QTouchEvent::deleteInRawEventTranslation() touchScreenDevice, touchPointList(rawTouchPoints)); QCoreApplication::processEvents(); - QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull()); + QVERIFY(leftWidget.isNull()); + QVERIFY(!centerWidget.isNull()); + QVERIFY(!rightWidget.isNull()); // generate update events on all widget, the center widget should die rawTouchPoints[0].setState(Qt::TouchPointMoved); @@ -1455,14 +1446,13 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() { QGraphicsScene scene; QGraphicsView view(&scene); - tst_QTouchEventGraphicsItem *root; - root = new tst_QTouchEventGraphicsItem; + QScopedPointer<tst_QTouchEventGraphicsItem> root(new tst_QTouchEventGraphicsItem); root->setAcceptTouchEvents(true); - scene.addItem(root); + scene.addItem(root.data()); - QGraphicsWidget *glassWidget = new QGraphicsWidget; + QScopedPointer<QGraphicsWidget> glassWidget(new QGraphicsWidget); glassWidget->setMinimumSize(100, 100); - scene.addItem(glassWidget); + scene.addItem(glassWidget.data()); view.resize(200, 200); view.show(); @@ -1478,7 +1468,7 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); - QCOMPARE(root->touchBeginCounter, 1); + QTRY_COMPARE(root->touchBeginCounter, 1); QCOMPARE(root->touchUpdateCounter, 1); QCOMPARE(root->touchEndCounter, 1); QCOMPARE(root->touchUpdatePoints.size(), 2); @@ -1498,17 +1488,13 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() QCOMPARE(root->touchBeginCounter, 0); QCOMPARE(root->touchUpdateCounter, 0); QCOMPARE(root->touchEndCounter, 0); - - - delete root; - delete glassWidget; } class WindowTouchEventFilter : public QObject { Q_OBJECT public: - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; struct TouchInfo { QList<QTouchEvent::TouchPoint> points; QEvent::Type lastSeenType; @@ -1537,18 +1523,18 @@ void tst_QTouchEvent::testQGuiAppDelivery() device->setType(QTouchDevice::TouchScreen); QWindowSystemInterface::registerTouchDevice(device); - QWindow *w = new QWindow; - w->setGeometry(100, 100, 100, 100); - w->show(); - QVERIFY(QTest::qWaitForWindowExposed(w)); + QWindow w; + w.setGeometry(100, 100, 100, 100); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); WindowTouchEventFilter filter; - w->installEventFilter(&filter); + w.installEventFilter(&filter); QList<QWindowSystemInterface::TouchPoint> points; // Pass empty list, should be ignored. - QWindowSystemInterface::handleTouchEvent(w, 0, points); + QWindowSystemInterface::handleTouchEvent(&w, 0, points); QCoreApplication::processEvents(); QCOMPARE(filter.d.isEmpty(), true); @@ -1559,12 +1545,12 @@ void tst_QTouchEvent::testQGuiAppDelivery() points.append(tp); // Pass 0 as device, should be ignored. - QWindowSystemInterface::handleTouchEvent(w, 0, points); + QWindowSystemInterface::handleTouchEvent(&w, 0, points); QCoreApplication::processEvents(); QCOMPARE(filter.d.isEmpty(), true); // Now the real thing. - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchBegin + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchBegin QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1572,7 +1558,7 @@ void tst_QTouchEvent::testQGuiAppDelivery() QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchBegin); points[0].state = Qt::TouchPointMoved; - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchUpdate + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchUpdate QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1580,7 +1566,7 @@ void tst_QTouchEvent::testQGuiAppDelivery() QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchUpdate); points[0].state = Qt::TouchPointReleased; - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchEnd + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchEnd QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1597,13 +1583,13 @@ void tst_QTouchEvent::testMultiDevice() deviceTwo->setType(QTouchDevice::TouchScreen); QWindowSystemInterface::registerTouchDevice(deviceTwo); - QWindow *w = new QWindow; - w->setGeometry(100, 100, 100, 100); - w->show(); - QVERIFY(QTest::qWaitForWindowExposed(w)); + QWindow w; + w.setGeometry(100, 100, 100, 100); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); WindowTouchEventFilter filter; - w->installEventFilter(&filter); + w.installEventFilter(&filter); QList<QWindowSystemInterface::TouchPoint> pointsOne, pointsTwo; @@ -1620,8 +1606,8 @@ void tst_QTouchEvent::testMultiDevice() tp.area = QRectF(140, 140, 20, 20); pointsTwo.append(tp); - QWindowSystemInterface::handleTouchEvent(w, deviceOne, pointsOne); - QWindowSystemInterface::handleTouchEvent(w, deviceTwo, pointsTwo); + QWindowSystemInterface::handleTouchEvent(&w, deviceOne, pointsOne); + QWindowSystemInterface::handleTouchEvent(&w, deviceTwo, pointsTwo); QCoreApplication::processEvents(); QCOMPARE(filter.d.contains(deviceOne), true); diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST new file mode 100644 index 0000000000..ee9709e68b --- /dev/null +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -0,0 +1,6 @@ +[positioning:default] +ubuntu-14.04 +[modalWindowPosition] +ubuntu-14.04 +[modalWithChildWindow] +ubuntu-14.04 diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 517f7fe3bd..666bedc8c2 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -470,6 +470,9 @@ private Q_SLOTS: void ioHttpChangeMaxRedirects(); void ioHttpRedirectErrors_data(); void ioHttpRedirectErrors(); +#ifndef QT_NO_SSL + void putWithServerClosingConnectionImmediately(); +#endif // NOTE: This test must be last! void parentingRepliesToTheApp(); @@ -4744,18 +4747,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() class SslServer : public QTcpServer { Q_OBJECT public: - SslServer() : socket(0) {}; + SslServer() : socket(0), m_ssl(true) {} void incomingConnection(qintptr socketDescriptor) { QSslSocket *serverSocket = new QSslSocket; serverSocket->setParent(this); if (serverSocket->setSocketDescriptor(socketDescriptor)) { + connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + if (!m_ssl) { + emit newPlainConnection(serverSocket); + return; + } QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath(); if (testDataDir.isEmpty()) testDataDir = QCoreApplication::applicationDirPath(); connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot())); - connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); serverSocket->setProtocol(QSsl::AnyProtocol); connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors())); serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem"); @@ -4766,11 +4773,12 @@ public: } } signals: - void newEncryptedConnection(); + void newEncryptedConnection(QSslSocket *s); + void newPlainConnection(QSslSocket *s); public slots: void encryptedSlot() { socket = (QSslSocket*) sender(); - emit newEncryptedConnection(); + emit newEncryptedConnection(socket); } void readyReadSlot() { // for the incoming sockets, not the server socket @@ -4779,6 +4787,7 @@ public slots: public: QSslSocket *socket; + bool m_ssl; }; // very similar to ioPostToHttpUploadProgress but for SSL @@ -4806,7 +4815,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QNetworkReplyPtr reply(manager.post(request, sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); - connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors())); // get the request started and the incoming socket connected @@ -4814,7 +4823,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QVERIFY(!QTestEventLoop::instance().timeout()); QTcpSocket *incomingSocket = server.socket; QVERIFY(incomingSocket); - disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); incomingSocket->setReadBufferSize(1*1024); @@ -8147,6 +8156,159 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QCOMPARE(spy.count(), 1); QVERIFY(reply->error() == error); } +#ifndef QT_NO_SSL + +class PutWithServerClosingConnectionImmediatelyHandler: public QObject +{ + Q_OBJECT +public: + bool m_parsedHeaders; + QByteArray m_receivedData; + QByteArray m_expectedData; + QSslSocket *m_socket; + PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s) + { + m_socket->setParent(this); + connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot())); + connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot())); + } +signals: + void correctFileUploadReceived(); + void corruptFileUploadReceived(); + +public slots: + void closeDelayed() { + m_socket->close(); + } + + void readyReadSlot() + { + QByteArray data = m_socket->readAll(); + m_receivedData += data; + if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) { + m_parsedHeaders = true; + QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency + // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout + // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload + // This test catches that. + } + + } + void disconnectedSlot() + { + if (m_parsedHeaders) { + //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n")); + m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data + } + if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) { + // We had received some data but it is corrupt! + qDebug() << "CORRUPT" << m_receivedData.count(); + + // Use this to track down the pattern of the corruption and conclude the source +// QFile a("/tmp/corrupt"); +// a.open(QIODevice::WriteOnly); +// a.write(m_receivedData); +// a.close(); + +// QFile b("/tmp/correct"); +// b.open(QIODevice::WriteOnly); +// b.write(m_expectedData); +// b.close(); + //exit(1); + emit corruptFileUploadReceived(); + } else { + emit correctFileUploadReceived(); + } + } +}; + +class PutWithServerClosingConnectionImmediatelyServer: public SslServer +{ + Q_OBJECT +public: + int m_correctUploads; + int m_corruptUploads; + int m_repliesFinished; + int m_expectedReplies; + QByteArray m_expectedData; + PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0) + { + QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + } + +public slots: + void createHandlerForConnection(QSslSocket* s) { + PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData); + handler->setParent(this); + QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect())); + QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt())); + } + void increaseCorrect() { + m_correctUploads++; + } + void increaseCorrupt() { + m_corruptUploads++; + } + void replyFinished() { + m_repliesFinished++; + if (m_repliesFinished == m_expectedReplies) { + QTestEventLoop::instance().exitLoop(); + } + } +}; + + + +void tst_QNetworkReply::putWithServerClosingConnectionImmediately() +{ + const int numUploads = 40; + qint64 wantedSize = 512*1024; // 512 kB + QByteArray sourceFile; + for (int i = 0; i < wantedSize; ++i) { + sourceFile += (char)'a' +(i%26); + } + bool withSsl = false; + + for (int s = 0; s <= 1; s++) { + withSsl = (s == 1); + // Test also needs to run several times because of 9c2ecf89 + for (int j = 0; j < 20; j++) { + // emulate a minimal https server + PutWithServerClosingConnectionImmediatelyServer server; + server.m_ssl = withSsl; + server.m_expectedData = sourceFile; + server.m_expectedReplies = numUploads; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + for (int i = 0; i < numUploads; i++) { + // create the request + QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i)); + QNetworkRequest request(url); + QNetworkReply *reply = manager.put(request, sourceFile); + connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished())); + reply->setParent(&server); + } + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + + //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads; + + // Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked + QVERIFY(server.m_correctUploads > 5); + // Because actually important is that we don't get any corruption: + QCOMPARE(server.m_corruptUploads, 0); + + server.close(); + } + } + + +} + +#endif // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() diff --git a/tests/auto/network/kernel/qhostinfo/BLACKLIST b/tests/auto/network/kernel/qhostinfo/BLACKLIST deleted file mode 100644 index ea4b64d7c2..0000000000 --- a/tests/auto/network/kernel/qhostinfo/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-23837 -[abortHostLookupInDifferentThread] -opensuse-13.1 64bit diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 9762e8244c..599e475beb 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -126,7 +126,6 @@ private slots: void cache(); void abortHostLookup(); - void abortHostLookupInDifferentThread(); protected slots: void resultsReady(const QHostInfo &); @@ -621,25 +620,5 @@ public: int id; }; -void tst_QHostInfo::abortHostLookupInDifferentThread() -{ - //reset counter - lookupsDoneCounter = 0; - bool valid = false; - int id = -1; - QHostInfo result = qt_qhostinfo_lookup("a-single" TEST_DOMAIN, this, SLOT(resultsReady(QHostInfo)), &valid, &id); - QVERIFY(!valid); - QThread thread; - LookupAborter aborter; - aborter.id = id; - aborter.moveToThread(&thread); - connect(&thread, SIGNAL(started()), &aborter, SLOT(abort())); - //it is assumed that the DNS request/response in the backend is slower than it takes to schedule the thread and call abort - thread.start(); - QVERIFY(thread.wait(5000)); - QTestEventLoop::instance().enterLoop(5); - QCOMPARE(lookupsDoneCounter, 0); -} - QTEST_MAIN(tst_QHostInfo) #include "tst_qhostinfo.moc" diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index d95f2fa546..b823b87125 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -404,8 +404,8 @@ void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent void tst_QSslSocket::constructing() { - const char readNotOpenMessage[] = "QIODevice::read: device not open"; - const char writeNotOpenMessage[] = "QIODevice::write: device not open"; + const char readNotOpenMessage[] = "QIODevice::read (QSslSocket): device not open"; + const char writeNotOpenMessage[] = "QIODevice::write (QSslSocket): device not open"; if (!QSslSocket::supportsSsl()) return; @@ -443,13 +443,13 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.read(0, 0), qint64(-1)); QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.readAll().isEmpty()); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine: Called with maxSize < 2"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): Called with maxSize < 2"); QCOMPARE(socket.readLine(0, 0), qint64(-1)); char buf[10]; QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1)); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: Cannot call seek on a sequential device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device"); QVERIFY(!socket.reset()); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: Cannot call seek on a sequential device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device"); QVERIFY(!socket.seek(2)); QCOMPARE(socket.size(), qint64(0)); QVERIFY(!socket.waitForBytesWritten(10)); diff --git a/tests/auto/other/baselineexample/baselineexample.pro b/tests/auto/other/baselineexample/baselineexample.pro deleted file mode 100644 index c1c4b31bfe..0000000000 --- a/tests/auto/other/baselineexample/baselineexample.pro +++ /dev/null @@ -1,19 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2010-12-09T14:55:13 -# -#------------------------------------------------- - -QT += testlib widgets - -TARGET = tst_baselineexample -CONFIG += console -CONFIG -= app_bundle - -TEMPLATE = app - -SOURCES += tst_baselineexample.cpp -DEFINES += SRCDIR=\\\"$$PWD/\\\" - -include($$PWD/../../../baselineserver/shared/qbaselinetest.pri) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/other/baselineexample/tst_baselineexample.cpp b/tests/auto/other/baselineexample/tst_baselineexample.cpp deleted file mode 100644 index 9059989015..0000000000 --- a/tests/auto/other/baselineexample/tst_baselineexample.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qbaselinetest.h> -#include <QPushButton> - -class tst_BaselineExample : public QObject -{ - Q_OBJECT - -public: - tst_BaselineExample(); - -private Q_SLOTS: - void testBasicUsage(); - void testMultipleImages(); - void testDataDriven_data(); - void testDataDriven(); - void testDataDrivenChecksum_data(); - void testDataDrivenChecksum(); -}; - - -tst_BaselineExample::tst_BaselineExample() -{ -} - - -void tst_BaselineExample::testBasicUsage() -{ - // Generate an image: - QPushButton b("Press me!"); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QImage img1 = b.grab().toImage(); - QVERIFY(!img1.isNull()); - - // Compare it to baseline on server: - QBASELINE_CHECK(img1, "button"); -} - - -void tst_BaselineExample::testMultipleImages() -{ - QPushButton b("Press me!"); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QBASELINE_CHECK(b.grab().toImage(), "text1"); - - b.setText("Kick me!"); - QTest::qWait(50); - QBASELINE_CHECK(b.grab().toImage(), "text2"); -} - - -void tst_BaselineExample::testDataDriven_data() -{ - QTest::addColumn<QString>("label"); - QBaselineTest::newRow("short") << "Ok!"; - QBaselineTest::newRow("long") << "A really long button text that just does not seem to end"; - QBaselineTest::newRow("empty") << ""; - QBaselineTest::newRow("signs") << "!@#$%^&*()_"; - QBaselineTest::newRow("html") << "<b>BOLD</b>"; -} - - -void tst_BaselineExample::testDataDriven() -{ - QFETCH(QString, label); - QPushButton b(label); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QBASELINE_TEST(b.grab().toImage()); -} - - -void tst_BaselineExample::testDataDrivenChecksum_data() -{ - QTest::addColumn<QString>("label"); - - const int numItems = 5; - const char *tags[numItems] = {"short", "long", "empty", "signs", "html"}; - const char *labels[numItems] = {"Ok!", "A really long button text that just does not seem to end", "", "!@#$%^&*()_", "<b>BOLD</b>"}; - - for (int i = 0; i<numItems; i++) { - quint16 checksum = qChecksum(labels[i], qstrlen(labels[i])); - QBaselineTest::newRow(tags[i], checksum) << labels[i]; - } -} - - -void tst_BaselineExample::testDataDrivenChecksum() -{ - QFETCH(QString, label); - QPushButton b(label); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QBASELINE_TEST(b.grab().toImage()); -} - - -QTEST_MAIN(tst_BaselineExample); - -#include "tst_baselineexample.moc" diff --git a/tests/auto/other/other.pro b/tests/auto/other/other.pro index a5ed4c5f31..8c911da2e0 100644 --- a/tests/auto/other/other.pro +++ b/tests/auto/other/other.pro @@ -1,7 +1,6 @@ TEMPLATE=subdirs SUBDIRS=\ # atwrapper \ # QTBUG-19452 - baselineexample \ compiler \ gestures \ lancelot \ @@ -26,7 +25,6 @@ SUBDIRS=\ toolsupport \ !qtHaveModule(widgets): SUBDIRS -= \ - baselineexample \ gestures \ lancelot \ languagechange \ @@ -41,7 +39,6 @@ SUBDIRS=\ qaccessibilitymac \ !qtHaveModule(network): SUBDIRS -= \ - baselineexample \ lancelot \ networkselftest \ qnetworkaccessmanager_and_qprogressdialog \ diff --git a/tests/auto/testlib/selftests/blacklisted/BLACKLIST b/tests/auto/testlib/selftests/blacklisted/BLACKLIST new file mode 100644 index 0000000000..36b7699cbd --- /dev/null +++ b/tests/auto/testlib/selftests/blacklisted/BLACKLIST @@ -0,0 +1,12 @@ +[pass] +* +[skip] +* +[fail] +* +[xpass] +* +[xfail] +* +[messages] +* diff --git a/tests/auto/testlib/selftests/blacklisted/blacklisted.pro b/tests/auto/testlib/selftests/blacklisted/blacklisted.pro new file mode 100644 index 0000000000..5bd22910b1 --- /dev/null +++ b/tests/auto/testlib/selftests/blacklisted/blacklisted.pro @@ -0,0 +1,7 @@ +SOURCES += tst_blacklisted.cpp +QT = core testlib-private + +mac: CONFIG -= app_bundle +CONFIG -= debug_and_release_target + +TARGET = blacklisted diff --git a/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp b/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp new file mode 100644 index 0000000000..f1df285a51 --- /dev/null +++ b/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QCoreApplication> +#include <QtTest/QtTest> +#include <private/qtestlog_p.h> + +class tst_Blacklisted : public QObject +{ + Q_OBJECT + +private slots: + void pass(); + void skip(); + void fail(); + void xfail(); + void xpass(); + + // This test function must be last, as it calls qFatal(). + void messages(); +}; + +// All the tests below have been blacklisted in blacklisted/BLACKLIST + +void tst_Blacklisted::pass() +{ + QVERIFY(true); +} + +void tst_Blacklisted::skip() +{ + QSKIP("This test should SKIP"); +} + +void tst_Blacklisted::fail() +{ + QVERIFY2(false, "This test should BFAIL"); +} + +void tst_Blacklisted::xfail() +{ + QEXPECT_FAIL("", "This test should XFAIL then BFAIL", Abort); + QVERIFY(false); +} + +void tst_Blacklisted::xpass() +{ + QEXPECT_FAIL("", "This test should XPASS", Abort); + QVERIFY2(true, "This test should XPASS, blacklist ignored for XPASS"); +} + +void tst_Blacklisted::messages() +{ + qWarning("This is a warning that should not appear in silent test output"); + QWARN("This is an internal testlib warning that should not appear in silent test output"); + qDebug("This is a debug message that should not appear in silent test output"); + qCritical("This is a critical message that should not appear in silent test output"); + qInfo("This is an info message that should not appear in silent test output"); + QTestLog::info("This is an internal testlib info message that should not appear in silent test output", __FILE__, __LINE__); + qFatal("This is a fatal error message that should still appear in silent test output"); +} + +QTEST_MAIN(tst_Blacklisted) +#include "tst_blacklisted.moc" diff --git a/tests/auto/testlib/selftests/expected_blacklisted.txt b/tests/auto/testlib/selftests/expected_blacklisted.txt new file mode 100644 index 0000000000..3afd93b0cc --- /dev/null +++ b/tests/auto/testlib/selftests/expected_blacklisted.txt @@ -0,0 +1,26 @@ +********* Start testing of tst_Blacklisted ********* +Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@ +PASS : tst_Blacklisted::initTestCase() +BPASS : tst_Blacklisted::pass() +SKIP : tst_Blacklisted::skip() This test should SKIP + Loc: [tst_blacklisted.cpp(62)] +BFAIL : tst_Blacklisted::fail() 'false' returned FALSE. (This test should BFAIL) + Loc: [tst_blacklisted.cpp(67)] +XFAIL : tst_Blacklisted::xfail() This test should XFAIL then BFAIL + Loc: [tst_blacklisted.cpp(73)] +BPASS : tst_Blacklisted::xfail() +XPASS : tst_Blacklisted::xpass() 'true' returned TRUE unexpectedly. (This test should XPASS, blacklist ignored for XPASS) + Loc: [tst_blacklisted.cpp(79)] +QWARN : tst_Blacklisted::messages() This is a warning that should not appear in silent test output +WARNING: tst_Blacklisted::messages() This is an internal testlib warning that should not appear in silent test output + Loc: [tst_blacklisted.cpp(85)] +QDEBUG : tst_Blacklisted::messages() This is a debug message that should not appear in silent test output +QSYSTEM: tst_Blacklisted::messages() This is a critical message that should not appear in silent test output +QINFO : tst_Blacklisted::messages() This is an info message that should not appear in silent test output +INFO : tst_Blacklisted::messages() This is an internal testlib info message that should not appear in silent test output + Loc: [tst_blacklisted.cpp(89)] +QFATAL : tst_Blacklisted::messages() This is a fatal error message that should still appear in silent test output +BFAIL : tst_Blacklisted::messages() Received a fatal error. + Loc: [Unknown file(0)] +Totals: 1 passed, 1 failed, 1 skipped, 4 blacklisted +********* Finished testing of tst_Blacklisted ********* diff --git a/tests/auto/testlib/selftests/selftests.pri b/tests/auto/testlib/selftests/selftests.pri index 7b706735a9..7404a1c49b 100644 --- a/tests/auto/testlib/selftests/selftests.pri +++ b/tests/auto/testlib/selftests/selftests.pri @@ -8,6 +8,7 @@ SUBPROGRAMS = \ benchliboptions \ benchlibtickcounter \ benchlibwalltime \ + blacklisted \ cmptest \ commandlinedata \ counting \ diff --git a/tests/auto/testlib/selftests/selftests.qrc b/tests/auto/testlib/selftests/selftests.qrc index ba567f1fb4..715e255e76 100644 --- a/tests/auto/testlib/selftests/selftests.qrc +++ b/tests/auto/testlib/selftests/selftests.qrc @@ -151,5 +151,6 @@ <file>expected_xunit.txt</file> <file>expected_xunit.xml</file> <file>expected_xunit.xunitxml</file> + <file>expected_blacklisted.txt</file> </qresource> </RCC> diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index a5840d16d2..5e97a9cfe4 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -352,6 +352,7 @@ void tst_Selftests::runSubTest_data() << "benchlibcounting" << "benchlibeventcounter" << "benchliboptions" + << "blacklisted" << "cmptest" << "commandlinedata" << "counting" @@ -470,6 +471,9 @@ void tst_Selftests::runSubTest_data() if (subtest == "benchliboptions") { continue; } + if (subtest == "blacklisted") { + continue; + } if (subtest == "printdatatags") { continue; } @@ -503,7 +507,8 @@ void tst_Selftests::runSubTest_data() const bool crashes = subtest == QLatin1String("assert") || subtest == QLatin1String("exceptionthrow") || subtest == QLatin1String("fetchbogus") || subtest == QLatin1String("crashedterminate") - || subtest == QLatin1String("crashes") || subtest == QLatin1String("silent"); + || subtest == QLatin1String("crashes") || subtest == QLatin1String("silent") + || subtest == QLatin1String("blacklisted"); QTest::newRow(qPrintable(QString("%1 %2").arg(subtest).arg(loggerSet.name))) << subtest << loggers @@ -612,6 +617,7 @@ void tst_Selftests::doRunSubTest(QString const& subdir, QStringList const& logge && subdir != QLatin1String("fetchbogus") && subdir != QLatin1String("xunit") #ifdef Q_CC_MINGW + && subdir != QLatin1String("blacklisted") // calls qFatal() && subdir != QLatin1String("silent") // calls qFatal() #endif && subdir != QLatin1String("benchlibcallgrind")) diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 00e5c60b29..350c6142d2 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -87,6 +87,18 @@ struct QTBUG_31218_Derived : QTBUG_31218<-1<0> {}; class QTBUG_45790 : Bug() { }; #endif +class CreatableGadget +{ + Q_GADGET +public: + Q_INVOKABLE CreatableGadget() + { + CreatableGadget::qt_static_metacall((QObject*)this, QMetaObject::ReadProperty, -1, Q_NULLPTR); + } +}; + +CreatableGadget creatableGadget; // Force the compiler to use the constructor + struct MyStruct {}; struct MyStruct2 {}; @@ -680,7 +692,7 @@ void tst_Moc::oldStyleCasts() QStringList args; args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -750,7 +762,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension() QStringList args; args << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -1029,7 +1041,7 @@ void tst_Moc::ignoreOptionClashes() // If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation. QStringList gccArgs; gccArgs << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", gccArgs); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -1870,6 +1882,13 @@ void tst_Moc::warnings_data() << 1 << QString() << QString("standard input:5: Error: Class declaration lacks Q_OBJECT macro."); + + QTest::newRow("QTBUG-46210: crash on invalid macro") + << QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c #d\n Foo(45);") + << QStringList() + << 1 + << QString("IGNORE_ALL_STDOUT") + << QString(":2: Error: '#' is not followed by a macro parameter"); } void tst_Moc::warnings() diff --git a/tests/auto/tools/qmake/testdata/comments/comments.pro b/tests/auto/tools/qmake/testdata/comments/comments.pro deleted file mode 100644 index 510ab95ab3..0000000000 --- a/tests/auto/tools/qmake/testdata/comments/comments.pro +++ /dev/null @@ -1,31 +0,0 @@ -LIST = 1 2 3 4 #a comment -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: inline comment" ) -} - -LIST = 1 \ - 2 \ -# 3 \ - 4 -!equals( LIST, 1 2 4 ) { - message( "FAILED: commented out continuation" ) -} - -LIST = 1 \ - 2 \#comment - 3 \ - 4 -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: comment at end of continuation") -} - - -LIST = 1 2 3 4#comment -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: no space before comment" ) -} - -LIST = 1 2 3 4$${LITERAL_HASH}five -!equals( LIST, 1 2 3 4$${LITERAL_HASH}five ) { - message( "FAILED: using LITERAL_HASH" ) -} diff --git a/tests/auto/tools/qmake/testdata/func_export/func_export.pro b/tests/auto/tools/qmake/testdata/func_export/func_export.pro deleted file mode 100644 index fc3818985b..0000000000 --- a/tests/auto/tools/qmake/testdata/func_export/func_export.pro +++ /dev/null @@ -1,19 +0,0 @@ -defineTest(doExport) { - EXPORTED += $$1 - export(EXPORTED) -} - -defineTest(callDoExport) { - doExport(bar) - doExport(baz) - EXPORTED = oink - !isEqual(EXPORTED, "oink") { - message( "FAILED: function-scope exports [$$EXPORTED] != oink" ) - } -} - -doExport(foo) -callDoExport() -!isEqual(EXPORTED, "foo bar baz") { - message( "FAILED: global-scope exports [$$EXPORTED] != foo bar baz" ) -} diff --git a/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro b/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro deleted file mode 100644 index cc13437f4a..0000000000 --- a/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro +++ /dev/null @@ -1,49 +0,0 @@ -defineTest(testVariable) { - varname=$$1 - value=$$eval($$varname) - RESULT=$$value - export(RESULT) -} - -defineTest(callTest) { - myvar=$$1 - testVariable(myvar) -} - -defineTest(callTestExport) { - myvar=$$1 - export(myvar) - testVariable(myvar) -} - -defineTest(callTestExportChange) { - myvar=foo - export(myvar) - myvar=$$1 - testVariable(myvar) -} - -value=direct -myvar=$$value -testVariable(myvar) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=export -callTestExport($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=export_and_change -callTestExportChange($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=local -callTest($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} diff --git a/tests/auto/tools/qmake/testdata/functions/1.cpp b/tests/auto/tools/qmake/testdata/functions/1.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/2.cpp b/tests/auto/tools/qmake/testdata/functions/2.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/2.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/functions.pro b/tests/auto/tools/qmake/testdata/functions/functions.pro deleted file mode 100644 index 5db8036188..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/functions.pro +++ /dev/null @@ -1,184 +0,0 @@ -VAR = qt thread - -defineTest(testReplace) { - !isEqual(1, $$2):message("FAILED: $$3: got $$1, expected $${2}.") -} - -#count -!count( VAR, 2 ) { - message( "FAILED: count function: $$VAR" ) -} - -#contains -!contains( VAR, thread ) { - message( "FAILED: contains function: $$VAR" ) -} - -#exists -!exists( functions.pro ) { - message( "FAILED: exists function" ) -} - -#isEmpty -isEmpty( VAR ) { - message( "FAILED: isEmpty function: $VAR" ) -} - -#files -!equals($$list($$files(one/*.cpp)), "one/1.cpp one/2.cpp") { - message( "FAILED: files function: one/*.cpp" ) -} -!equals($$list($$files(one/1*.cpp)), "one/1.cpp") { - message( "FAILED: files function: one/1*.cpp" ) -} -!equals($$list($$files(two/*.cpp)), "two/1.cpp two/2.cpp") { - message( "FAILED: files function: two/*.cpp" ) -} -!equals($$list($$files(three/wildcard*.cpp)), "three/wildcard21.cpp three/wildcard22.cpp") { - message( "FAILED: files function: three/wildcard*.cpp" ) -} -!equals($$list($$files(*.cpp)), "1.cpp 2.cpp wildcard21.cpp wildcard22.cpp") { - message( "FAILED: files function: *.cpp" ) -} -!equals($$list($$files(wildcard*.cpp)), "wildcard21.cpp wildcard22.cpp") { - message( "FAILED: files function: wildcard*.cpp" ) -} - -#infile -!infile( infiletest.pro, DEFINES, QT_DLL ){ - message( "FAILED: infile function" ) -} - -#include -include( infiletest.pro, "", true ) -!contains( DEFINES, QT_DLL ) { - message( "FAILED: include function: $$DEFINES" ) -} - -#replace -VERSION=1.0.0 -VERSION_replaced=$$replace(VERSION,\\.,_) -!isEqual(VERSION_replaced, 1_0_0) { - message( "FAILED: replace function: $$VERSION_replaced" ) -} - -#test functions -defineTest(myTestFunction) { - RESULT = - list=$$1 - for(l, list) { - RESULT += $$l - } - export(RESULT) -} -myTestFunction(oink baa moo) -!equals($$list($$member(RESULT, 0)), "oink") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction("oink baa" moo) -!equals($$list($$member(RESULT, 0)), "oink baa") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction(oink "baa moo") -!equals($$list($$member(RESULT, 0)), "oink") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction("oink baa moo") -!equals($$list($$member(RESULT, 0)), "oink baa moo") { - message("FAILED: myTestFunction: $$RESULT") -} - -#recursive -defineReplace(myRecursiveReplaceFunction) { - RESULT = - list = $$1 - RESULT += $$member(list, 0) - list -= $$RESULT - !isEmpty(list):RESULT += $$myRecursiveReplaceFunction($$list) - return($$RESULT) -} -RESULT = $$myRecursiveReplaceFunction(oink baa moo) -!isEqual(RESULT, "oink baa moo") { - message( "FAILED: myRecursiveReplaceFunction [$$RESULT] != oink baa moo" ) -} - -moo = "this is a test" "for real" -fn = $$OUT_PWD/testdir/afile -write_file($$fn, moo)|message("FAILED: write_file() failed") -exists($$fn)|message("FAILED: write_file() didn't write anything") -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong") -moo += "another line" -write_file($$fn, moo)|message("FAILED: write_file() failed (take 2)") -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong (take 2)") -mooadd = "yet another line" -write_file($$fn, mooadd, append)|message("FAILED: write_file() failed (append)") -moo += $$mooadd -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong when appending") - -pn = $$OUT_PWD/testpath/subdir -mkpath($$pn)|message("FAILED: mkpath() failed") -exists($$pn)|message("FAILED: mkpath() didn't create anything") - -in = easy "less easy" sca$${LITERAL_HASH}ry crazy$$escape_expand(\\t\\r\\n) $$escape_expand(\\t)shit \'no\"way\\here -out = "easy \"less easy\" sca\$\${LITERAL_HASH}ry crazy\$\$escape_expand(\\\\t\\\\r\\\\n) \$\$escape_expand(\\\\t)shit \\\'no\\\"way\\\\here" -testReplace($$val_escape(in), $$out, "val_escape") - -testReplace($$shadowed($$PWD/something), $$OUT_PWD/something, "shadowed") -testReplace($$shadowed($$PWD), $$OUT_PWD, "shadowed (take 2)") - -#format_number -spc = " " -testReplace($$format_number(13), 13, "simple number format") -testReplace($$format_number(-13), -13, "negative number format") -testReplace($$format_number(13, ibase=16), 19, "hex input number format") -testReplace($$format_number(13, obase=16), d, "hex output number format") -testReplace($$format_number(13, width=5), " $$spc 13", "right aligned number format") -testReplace($$format_number(13, width=5 leftalign), "13 $$spc ", "left aligned number format") -testReplace($$format_number(13, width=5 zeropad), "00013", "zero-padded number format") -testReplace($$format_number(13, width=5 alwayssign), "$$spc +13", "always signed number format") -testReplace($$format_number(13, width=5 alwayssign zeropad), "+0013", "zero-padded always signed number format") -testReplace($$format_number(13, width=5 padsign), " $$spc 13", "sign-padded number format") -testReplace($$format_number(13, width=5 padsign zeropad), " 0013", "zero-padded sign-padded number format") - -testReplace($$clean_path("c:$${DIR_SEPARATOR}crazy//path/../trolls"), "c:/crazy/trolls", "clean_path") - -testReplace($$shell_path("/crazy/trolls"), "$${QMAKE_DIR_SEP}crazy$${QMAKE_DIR_SEP}trolls", "shell_path") -testReplace($$system_path("/crazy/trolls"), "$${DIR_SEPARATOR}crazy$${DIR_SEPARATOR}trolls", "system_path") - -testReplace($$absolute_path("crazy/trolls"), "$$PWD/crazy/trolls", "absolute_path") -testReplace($$absolute_path("crazy/trolls", "/fake/path"), "/fake/path/crazy/trolls", "absolute_path with base") -testReplace($$absolute_path(""), "$$PWD", "absolute_path of empty") -testReplace($$relative_path($$_PRO_FILE_PWD_), $$basename($$_PRO_FILE_), "relative_path") -testReplace($$relative_path("/fake/trolls", "/fake/path"), "../trolls", "relative_path with base") -testReplace($$relative_path(""), "", "relative_path of empty") - -#this test is very rudimentary. the backend function is thoroughly tested in qt creator -in = "some nasty & ugly\" path & thing\\" -out_cmd = "\"some nasty & ugly\\\" path ^& thing\\\\^\"" -out_sh = "'some nasty & ugly\" path & thing\\'" -equals(QMAKE_HOST.os, Windows): \ - out = $$out_cmd -else: \ - out = $$out_sh -testReplace($$system_quote($$in), $$out, "system_quote") -!equals(QMAKE_DIR_SEP, /): \ - out = $$out_cmd -else: \ - out = $$out_sh -testReplace($$shell_quote($$in), $$out, "shell_quote") - -testReplace($$reverse($$list(one two three)), three two one, "reverse") - -testReplace($$cat(textfile), hi '"holla he"' 'hu!') - -MOD.a.depends = -MOD.b.depends = -MOD.b.priority = 1 -MOD.c.depends = a b -testReplace($$resolve_depends($$list(c), "MOD."), c b a) -MOD.a.priority = 1 -MOD.b.priority = 0 -testReplace($$resolve_depends($$list(c), "MOD."), c a b) diff --git a/tests/auto/tools/qmake/testdata/functions/one/1.cpp b/tests/auto/tools/qmake/testdata/functions/one/1.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/one/1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/one/2.cpp b/tests/auto/tools/qmake/testdata/functions/one/2.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/one/2.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/textfile b/tests/auto/tools/qmake/testdata/functions/textfile deleted file mode 100644 index a8248ed6f8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/textfile +++ /dev/null @@ -1 +0,0 @@ -hi "holla he" hu! diff --git a/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp b/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp b/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/two/1.cpp b/tests/auto/tools/qmake/testdata/functions/two/1.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/two/1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/two/2.cpp b/tests/auto/tools/qmake/testdata/functions/two/2.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/two/2.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp b/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp b/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/include_function/existing_file.pri b/tests/auto/tools/qmake/testdata/include_function/existing_file.pri deleted file mode 100644 index 8b9aaca340..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/existing_file.pri +++ /dev/null @@ -1,3 +0,0 @@ -QT = -CONFIG = console -SOURCES = main.cpp diff --git a/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro b/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro deleted file mode 100644 index 424062a9ac..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro +++ /dev/null @@ -1,7 +0,0 @@ -# Test to see if include(), by default, succeeds when the specific file -# to include exists -include(existing_file.pri) - -# Test to see if by specifying full set of parameters to include() -# succeeds when the specified filed to include exists -include(existing_file.pri, "", false) diff --git a/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro b/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro deleted file mode 100644 index 0b59981240..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro +++ /dev/null @@ -1,3 +0,0 @@ -# Test to see if include(), by default, fails when the specific file -# to include does not exist -include(missing_file.pri) diff --git a/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro b/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro deleted file mode 100644 index 542b9ff516..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro +++ /dev/null @@ -1,3 +0,0 @@ -# Specifying full set of parameters to include() to test that a warning -# is shown for this non-existing file. -include(missing_file.pri, "", false) diff --git a/tests/auto/tools/qmake/testdata/include_function/main.cpp b/tests/auto/tools/qmake/testdata/include_function/main.cpp deleted file mode 100644 index 68e9c98e77..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/main.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -int main(int /*argc*/, char ** /*argv*/) -{ - return 0; -} diff --git a/tests/auto/tools/qmake/testdata/json/json.pro b/tests/auto/tools/qmake/testdata/json/json.pro deleted file mode 100644 index 33440b3209..0000000000 --- a/tests/auto/tools/qmake/testdata/json/json.pro +++ /dev/null @@ -1,26 +0,0 @@ -jsontext = $$cat($$PWD/test.json) -parseJson(jsontext, json) - -# print all keys -message(json._KEYS_ $${json._KEYS_}) - -# print array -message(json.array._KEYS_ $${json.array._KEYS_}) -for(key, json.array._KEYS_): \ - message(json.array.$${key} $$eval(json.array.$${key})) - -# print object -message(json.object._KEYS_ $${json.object._KEYS_}) -for(key, json.object._KEYS_): \ - message(json.object.$${key} $$eval(json.object.$${key})) - -# print value tyes -message(json.string: $${json.string}) -message(json.number: $${json.number}) -message(json.true: $${json.true}) -message(json.false: $${json.false}) -message(json.null: $${json.null}) - -# check that booleans work -$${json.true}: message(json.true is true) -!$${json.false}: message(json.false is false) diff --git a/tests/auto/tools/qmake/testdata/json/test.json b/tests/auto/tools/qmake/testdata/json/test.json deleted file mode 100644 index cc82908eba..0000000000 --- a/tests/auto/tools/qmake/testdata/json/test.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "array" : ["arrayItem1", "arrayItem2", "arrayItem3"], - "object" : { "key1" : "objectValue1", "key2" : "objectValue2" }, - "string" : "test string", - "number" : 999, - "true" : true, - "false" :false, - "null" : null -} diff --git a/tests/auto/tools/qmake/testdata/operators/operators.pro b/tests/auto/tools/qmake/testdata/operators/operators.pro deleted file mode 100644 index 463fa73d81..0000000000 --- a/tests/auto/tools/qmake/testdata/operators/operators.pro +++ /dev/null @@ -1,23 +0,0 @@ -VAR = qt thread - -VAR += debug -!contains( VAR, debug ) { - message( "FAILED: +=" ) -} - -VAR -= thread -contains( VAR, thread ) { - message( "FAILED: -=" ) -} - -VAR = thread -VAR *= thread -!count( VAR, 1 ) { - message( "FAILED: *=" ) -} - -VAR = thread QT_DLL debug -VAR ~= s/QT_+/Q_ -!contains( VAR, Q_DLL ) { - message( "FAILED: ~=" ) -} diff --git a/tests/auto/tools/qmake/testdata/variables/variables.pro b/tests/auto/tools/qmake/testdata/variables/variables.pro deleted file mode 100644 index e4b9eaa884..0000000000 --- a/tests/auto/tools/qmake/testdata/variables/variables.pro +++ /dev/null @@ -1,12 +0,0 @@ -VAR = 1 2 3 4 5 -JOINEDVAR = $$join( VAR, "-GLUE-", "-BEFORE-", "-AFTER-" ) -!contains( JOINEDVAR, -BEFORE-1-GLUE-2-GLUE-3-GLUE-4-GLUE-5-AFTER- ) { - message( "FAILED: join [$$JOINEDVAR != -BEFORE-1-GLUE-2-GLUE-3-GLUE-4-GLUE-5-AFTER-]" ) -} - -# To test member we need to use join -NEWVAR = $$member( VAR, 4 ) $$member( VAR, 3 ) $$member( VAR, 2 ) -JOINEDNEWVAR = $$join( NEWVAR, "-" ) -!contains( JOINEDNEWVAR, 5-4-3 ) { - message( "FAILED: member [$$JOINEDNEWVAR != 5-4-3]" ) -} diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index 48c6c0ac84..ac94d1a2b9 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -68,12 +68,6 @@ private slots: void simple_dll(); void subdirs(); void subdir_via_pro_file_extra_target(); - void functions(); - void operators(); - void variables(); - void func_export(); - void func_variables(); - void comments(); void duplicateLibraryEntries(); void export_across_file_boundaries(); void include_dir(); @@ -88,11 +82,9 @@ private slots: #if defined(Q_OS_MAC) void bundle_spaces(); #endif - void includefunction(); void substitutes(); void project(); void proFileCache(); - void json(); void resources(); private: @@ -262,43 +254,6 @@ void tst_qmake::subdir_via_pro_file_extra_target() QVERIFY( test_compiler.make( workDir, "extratarget" )); } -void tst_qmake::functions() -{ - QString workDir = base_path + "/testdata/functions"; - QString buildDir = base_path + "/testdata/functions_build"; - QVERIFY( test_compiler.qmake( workDir, "functions", buildDir )); -} - -void tst_qmake::operators() -{ - QString workDir = base_path + "/testdata/operators"; - QVERIFY( test_compiler.qmake( workDir, "operators" )); -} - -void tst_qmake::variables() -{ - QString workDir = base_path + "/testdata/variables"; - QVERIFY(test_compiler.qmake( workDir, "variables" )); -} - -void tst_qmake::func_export() -{ - QString workDir = base_path + "/testdata/func_export"; - QVERIFY(test_compiler.qmake( workDir, "func_export" )); -} - -void tst_qmake::func_variables() -{ - QString workDir = base_path + "/testdata/func_variables"; - QVERIFY(test_compiler.qmake( workDir, "func_variables" )); -} - -void tst_qmake::comments() -{ - QString workDir = base_path + "/testdata/comments"; - QVERIFY(test_compiler.qmake( workDir, "comments" )); -} - void tst_qmake::duplicateLibraryEntries() { QVERIFY(true); @@ -499,26 +454,6 @@ void tst_qmake::bundle_spaces() } #endif // defined(Q_OS_MAC) -void tst_qmake::includefunction() -{ - QString workDir = base_path + "/testdata/include_function"; - QRegExp warningMsg("Cannot read .*: No such file or directory"); - QVERIFY(test_compiler.qmake( workDir, "include_existing_file")); - QVERIFY(!test_compiler.commandOutput().contains(warningMsg)); - - // test include() usage on a missing file - test_compiler.clearCommandOutput(); - workDir = base_path + "/testdata/include_function"; - QVERIFY(test_compiler.qmake( workDir, "include_missing_file" )); - QVERIFY(test_compiler.commandOutput().contains(warningMsg)); - - // test include() usage on a missing file when all function parameters are used - test_compiler.clearCommandOutput(); - workDir = base_path + "/testdata/include_function"; - QVERIFY(test_compiler.qmake( workDir, "include_missing_file2" )); - QVERIFY(test_compiler.commandOutput().contains(warningMsg)); -} - void tst_qmake::substitutes() { QString workDir = base_path + "/testdata/substitutes"; @@ -564,34 +499,6 @@ void tst_qmake::proFileCache() QVERIFY( test_compiler.qmake( workDir, "pro_file_cache" )); } -void tst_qmake::json() -{ - QString workDir = base_path + "/testdata/json"; - QVERIFY( test_compiler.qmake( workDir, "json.pro" )); - QString output = test_compiler.commandOutput(); - - // all keys - QVERIFY(output.contains("json._KEYS_ array false null number object string true")); - // array - QVERIFY(output.contains("json.array._KEYS_ 0 1 2")); - QVERIFY(output.contains("json.array.0 arrayItem1")); - QVERIFY(output.contains("json.array.1 arrayItem2")); - QVERIFY(output.contains("json.array.2 arrayItem3")); - // object - QVERIFY(output.contains("json.object._KEYS_ key1 key2")); - QVERIFY(output.contains("json.object.key1 objectValue1")); - QVERIFY(output.contains("json.object.key1 objectValue1")); - // value types - QVERIFY(output.contains("json.string: test string")); - QVERIFY(output.contains("json.number: 999")); - QVERIFY(output.contains("json.true: true")); - QVERIFY(output.contains("json.false: false")); - QVERIFY(output.contains("json.null:")); - // functional booleans - QVERIFY(output.contains("json.true is true")); - QVERIFY(output.contains("json.false is false")); -} - void tst_qmake::resources() { QString workDir = base_path + "/testdata/resources"; diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp new file mode 100644 index 0000000000..fab2cdce17 --- /dev/null +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -0,0 +1,2513 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_qmakelib.h" + +#include <proitems.h> +#include <qmakevfs.h> +#include <qmakeparser.h> +#include <qmakeglobals.h> +#include <qmakeevaluator.h> + +void tst_qmakelib::addAssignments() +{ + QTest::newRow("assignment") + << "VAR = foo bar baz" + << "VAR = foo bar baz" + << "" + << true; + + QTest::newRow("appending") + << "VAR = foo bar baz\nVAR += foo gaz gaz" + << "VAR = foo bar baz foo gaz gaz" + << "" + << true; + + QTest::newRow("unique appending") + << "VAR = foo bar baz\nVAR *= foo gaz gaz" + << "VAR = foo bar baz gaz" + << "" + << true; + + QTest::newRow("removing") + << "VAR = foo bar foo baz\nVAR -= foo gaz gaz" + << "VAR = bar baz" + << "" + << true; + + // Somewhat unexpectedly, the g modifier is implicit within each element. + QTest::newRow("replacing") + << "VAR = foo bar foo baz\nVAR ~= s,o,0," + << "VAR = f00 bar foo baz" + << "" + << true; + + // Consistently with the "there are no empty elements", what becomes empty gets zapped. + QTest::newRow("replacing with nothing") + << "VAR = foo bar foo baz\nVAR ~= s,foo,," + << "VAR = bar foo baz" + << "" + << true; + + QTest::newRow("replacing case-insensitively") + << "VAR = foO bar foo baz\nVAR ~= s,o,0,i" + << "VAR = f00 bar foo baz" + << "" + << true; + + // In all elements, not all within each/one/??? element. + QTest::newRow("replacing globally") + << "VAR = foo bar foo baz\nVAR ~= s,o,0,g" + << "VAR = f00 bar f00 baz" + << "" + << true; + + // Replacing with the same string counts as no match. + // This is rather questionable ... + QTest::newRow("replacing with same") + << "VAR = foo bar foo baz\nVAR ~= s,ba[rz],bar," + << "VAR = foo bar foo bar" + << "" + << true; + + QTest::newRow("replacing with auto-quote") + << "VAR = foo [bar] foo baz\nVAR ~= s,[bar],bar,q" + << "VAR = foo bar foo baz" + << "" + << true; + + QTest::newRow("replacing with expansions") + << "VAR = foo bar foo baz\nPAT = foo\nREPL = 'yee haw'\nVAR ~= s,$$PAT,$$REPL," + << "VAR = 'yee haw' bar foo baz" + << "" + << true; + + QTest::newRow("~= with bad function") + << "VAR ~= m/foo/" + << "" + << "##:1: The ~= operator can handle only the s/// function." + << true; // rather questionable + + QTest::newRow("~= s with bad number of arguments") + << "VAR ~= s/bla\nVAR ~= s/bla/foo//" + << "" + << "##:1: The s/// function expects 3 or 4 arguments.\n" + "##:2: The s/// function expects 3 or 4 arguments." + << true; // rather questionable +} + +void tst_qmakelib::addExpansions() +{ + QTest::newRow("expand variable") + << "V1 = foo\nVAR = $$V1" + << "VAR = foo" + << "" + << true; + + QTest::newRow("expand property") + << "VAR = $$[P1]" + << "VAR = 'prop val'" + << "" + << true; + + QTest::newRow("expand environment variable") + << "VAR = $$(E1)" + << "VAR = 'env var'" + << "" + << true; + + // These test addStr/addStr. + + QTest::newRow("expand: str $$(env)") + << "VAR = foo $$(E1)" + << "VAR = foo 'env var'" + << "" + << true; + + QTest::newRow("expand: str$$(env)") + << "VAR = foo$$(E1)" + << "VAR = 'fooenv var'" + << "" + << true; + + QTest::newRow("expand: 'str $$(env)'") + << "VAR = 'foo $$(E1)'" + << "VAR = 'foo env var'" + << "" + << true; + + // These test addStr/addStrList + + QTest::newRow("expand: str $$var") + << "V1 = foo barbaz\nVAR = str $$V1" + << "VAR = str foo barbaz" + << "" + << true; + + QTest::newRow("expand: $$var str") + << "V1 = foo barbaz\nVAR = $$V1 str" + << "VAR = foo barbaz str" + << "" + << true; + + QTest::newRow("expand: str$$var") + << "V1 = foo barbaz\nVAR = str$$V1" + << "VAR = strfoo barbaz" + << "" + << true; + + QTest::newRow("expand: $${var}str") + << "V1 = foo barbaz\nVAR = $${V1}str" + << "VAR = foo barbazstr" + << "" + << true; + + QTest::newRow("expand: 'str $$var'") + << "V1 = foo barbaz\nVAR = 'str $$V1'" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand: '$$var str'") + << "V1 = foo barbaz\nVAR = '$$V1 str'" + << "VAR = 'foo barbaz str'" + << "" + << true; + + // Same again in joined context + + QTest::newRow("expand joined: str $$(env)") + << "VAR = $$quote(foo $$(E1))" + << "VAR = 'foo env var'" + << "" + << true; + + QTest::newRow("expand joined: str$$(env)") + << "VAR = $$quote(foo$$(E1))" + << "VAR = 'fooenv var'" + << "" + << true; + + QTest::newRow("expand joined: 'str $$(env)'") + << "VAR = $$quote('foo $$(E1)')" + << "VAR = 'foo env var'" + << "" + << true; + + QTest::newRow("expand joined: str $$var") + << "V1 = foo barbaz\nVAR = $$quote(str $$V1)" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: $$var str") + << "V1 = foo barbaz\nVAR = $$quote($$V1 str)" + << "VAR = 'foo barbaz str'" + << "" + << true; + + QTest::newRow("expand joined: str$$var") + << "V1 = foo barbaz\nVAR = $$quote(str$$V1)" + << "VAR = 'strfoo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: $${var}str") + << "V1 = foo barbaz\nVAR = $$quote($${V1}str)" + << "VAR = 'foo barbazstr'" + << "" + << true; + + QTest::newRow("expand joined: 'str $$var'") + << "V1 = foo barbaz\nVAR = $$quote('str $$V1')" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: '$$var str'") + << "V1 = foo barbaz\nVAR = $$quote('$$V1 str')" + << "VAR = 'foo barbaz str'" + << "" + << true; + + // Variable expansions on LHS + + QTest::newRow("indirect assign: $$var") + << "V = VAR\n$$V = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: fix$$var") + << "V = AR\nV$$V = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: $${var}fix") + << "V = VA\n$${V}R = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: eval") + << "V = VAR\n$$eval(V) = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: multiple") + << "V = FOO BAR\n$$V = foo" + << "" + << "##:2: Left hand side of assignment must expand to exactly one word." + << true; +} + +void tst_qmakelib::addControlStructs() +{ + QTest::newRow("true") + << "true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false") + << "false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-config") + << "CONFIG += test\ntest: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-config") + << "test: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-wildcard") + << "CONFIG += testing\ntest*: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-wildcard") + << "test*: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-else") + << "true: VAR1 = 1\nelse: VAR2 = 1" + << "VAR1 = 1\nVAR2 = UNDEF" + << "" + << true; + + QTest::newRow("false-else") + << "false: VAR1 = 1\nelse: VAR2 = 1" + << "VAR1 = UNDEF\nVAR2 = 1" + << "" + << true; + + QTest::newRow("true-else-true-else") + << "true: VAR1 = 1\nelse: true: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = 1\nVAR2 = UNDEF\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("true-else-false-else") + << "true: VAR1 = 1\nelse: false: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = 1\nVAR2 = UNDEF\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("false-else-true-else") + << "false: VAR1 = 1\nelse: true: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = 1\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("false-else-false-else") + << "false: VAR1 = 1\nelse: false: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = UNDEF\nVAR3 = 1" + << "" + << true; + + QTest::newRow("true-{false-else}-else") + << "true {\nfalse: VAR1 = 1\nelse: VAR2 = 1\n}\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = 1\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("NOT-true") + << "!true: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("NOT-false") + << "!false: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-true") + << "true:true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-false") + << "true:false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-AND-true") + << "false:true: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-false") + << "false|false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-false") + << "true|false: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-OR-true") + << "false|true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("NOT-false-AND-true") + << "!false:true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-message") + << "true:message(hi): VAR = 1" + << "VAR = 1" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("false-AND-message") + << "false:message(hi): VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-message") + << "true|message(hi): VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-OR-message") + << "false|message(hi): VAR = 1" + << "VAR = 1" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("true-OR-message-AND-false") + << "true|message(hi):false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-message-AND-false") + << "false|message(hi):false: VAR = 1" + << "VAR = UNDEF" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("true (indirect)") + << "TEST = true\n$$TEST: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false (indirect)") + << "TEST = false\n$$TEST: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + // Yes, this is not supposed to work + QTest::newRow("true|false (indirect)") + << "TEST = true|false\n$$TEST: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("for (var, var)") + << "IN = one two three\nfor (IT, IN) { OUT += $$IT }" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("for (var, range)") + << "for (IT, 1..3) { OUT += $$IT }" + << "OUT = 1 2 3" + << "" + << true; + + QTest::newRow("for (var, reverse-range)") + << "for (IT, 3..1) { OUT += $$IT }" + << "OUT = 3 2 1" + << "" + << true; + + // This syntax is rather ridiculous. + QTest::newRow("for (ever)") + << "for (ever) {}" + << "" + << "##:1: Ran into infinite loop (> 1000 iterations)." + << true; + + // This is even worse. + QTest::newRow("for (VAR, forever)") + << "for (VAR, forever) { OUT = $$VAR }" + << "OUT = 999" + << "##:1: Ran into infinite loop (> 1000 iterations)." + << true; + + QTest::newRow("for (garbage)") + << "for (garbage) { OUT = FAIL }" + << "OUT = UNDEF" + << "##:1: Invalid loop expression." + << true; + + QTest::newRow("next()") + << "IN = one two three\nfor (IT, IN) {\nequals(IT, two):next()\nOUT += $$IT\n}" + << "OUT = one three" + << "" + << true; + + QTest::newRow("nested next()") + << "IN = one two three\nfor (IT, IN) {\nfor (NIT, IN):next()\nOUT += $$IT\n}" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("break()") + << "IN = one two three\nfor (IT, IN) {\nequals(IT, three):break()\nOUT += $$IT\n}" + << "OUT = one two" + << "" + << true; + + QTest::newRow("nested break()") + << "IN = one two three\nfor (IT, IN) {\nfor (NIT, IN):break()\nOUT += $$IT\n}" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("defineReplace()") + << "defineReplace(func) { return($$1 + $$2) }\n" + "VAR = $$func(test me, \"foo bar\")" + << "VAR = test me + 'foo bar'" + << "" + << true; + + QTest::newRow("defineTest()") + << "defineTest(func) { return($$1) }\n" + "func(true): VAR += true\n" + "func(false): VAR += false" + << "VAR = true" + << "" + << true; + + QTest::newRow("true-AND-defineTest()") + << "true: defineTest(func)\n" + "defined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("false-AND-defineTest()") + << "false: defineTest(func)\n" + "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-defineTest()") + << "true| defineTest(func)\n" + "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-defineTest()") + << "false| defineTest(func)\n" + "defined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("variable scoping") + << "defineTest(func) {\n" + "VAR1 = modified\n!equals(VAR1, modified): return(false)\n" + "VAR2 += modified\n!equals(VAR2, original modified): return(false)\n" + "VAR3 = new var\n!equals(VAR3, new var): return(false)\n" + "return(true)\n" + "}\n" + "VAR1 = pristine\nVAR2 = original\nfunc(): OK = 1" + << "OK = 1\nVAR1 = pristine\nVAR2 = original\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("ARGC and ARGS") + << "defineTest(func) {\n" + "export(ARGC)\n" + "export(ARGS)\n" + "}\n" + "func(test me, \"foo bar\")" + << "ARGC = 2\nARGS = test me 'foo bar'" + << "" + << true; + + QTest::newRow("recursion") + << "defineReplace(func) {\n" + "RET = *$$member(1, 0)*\n" + "REST = $$member(1, 1, -1)\n" + "!isEmpty(REST): RET += $$func($$REST)\n" + "return($$RET)\n" + "}\n" + "VAR = $$func(you are ...)" + << "VAR = *you* *are* *...*" + << "" + << true; + + QTest::newRow("top-level return()") + << "VAR = good\nreturn()\nVAR = bad" + << "VAR = good" + << "" + << true; + + QTest::newRow("return() from function") + << "defineTest(func) {\nVAR = good\nexport(VAR)\nreturn()\nVAR = bad\nexport(VAR)\n}\n" + "func()" + << "VAR = good" + << "" + << true; + + QTest::newRow("return() from nested function") + << "defineTest(inner) {\nVAR = initial\nexport(VAR)\nreturn()\nVAR = bad\nexport(VAR)\n}\n" + "defineTest(outer) {\ninner()\nVAR = final\nexport(VAR)\n}\n" + "outer()" + << "VAR = final" + << "" + << true; +} + +void tst_qmakelib::addReplaceFunctions(const QString &qindir) +{ + QTest::newRow("$$member(): empty") + << "IN = \nVAR = $$member(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$member(): too short") + << "IN = one two three\nVAR = $$member(IN, 1, 5)" + << "VAR =" // this is actually kinda stupid + << "" + << true; + + QTest::newRow("$$member(): ok") + << "IN = one two three four five six seven\nVAR = $$member(IN, 1, 4)" + << "VAR = two three four five" + << "" + << true; + + QTest::newRow("$$member(): ok (default start)") + << "IN = one two three\nVAR = $$member(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$member(): ok (default end)") + << "IN = one two three\nVAR = $$member(IN, 2)" + << "VAR = three" + << "" + << true; + + QTest::newRow("$$member(): negative") + << "IN = one two three four five six seven\nVAR = $$member(IN, -4, -3)" + << "VAR = four five" + << "" + << true; + + QTest::newRow("$$member(): inverse") + << "IN = one two three four five six seven\nVAR = $$member(IN, 4, 1)" + << "VAR = five four three two" + << "" + << true; + + QTest::newRow("$$member(): dots") + << "IN = one two three four five six seven\nVAR = $$member(IN, 1..4)" + << "VAR = two three four five" + << "" + << true; + + QTest::newRow("$$member(): bad number of arguments") + << "VAR = $$member(1, 2, 3, 4)" + << "VAR =" + << "##:1: member(var, start, end) requires one to three arguments." + << true; + + QTest::newRow("$$member(): bad args (1)") + << "IN = one two three\nVAR = $$member(IN, foo, 4)" + << "VAR =" + << "##:2: member() argument 2 (start) 'foo' invalid." + << true; + + QTest::newRow("$$member(): bad args (2)") + << "IN = one two three\nVAR = $$member(IN, foo..4)" + << "VAR =" + << "##:2: member() argument 2 (start) 'foo..4' invalid." + << true; + + QTest::newRow("$$member(): bad args (3)") + << "IN = one two three\nVAR = $$member(IN, 4, foo)" + << "VAR =" + << "##:2: member() argument 3 (end) 'foo' invalid." + << true; + + QTest::newRow("$$member(): bad args (4)") + << "IN = one two three\nVAR = $$member(IN, 4..foo)" + << "VAR =" + << "##:2: member() argument 2 (start) '4..foo' invalid." + << true; + + QTest::newRow("$$first(): empty") + << "IN = \nVAR = $$first(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$first(): one") + << "IN = one\nVAR = $$first(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$first(): multiple") + << "IN = one two three\nVAR = $$first(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$first(): bad number of arguments") + << "VAR = $$first(1, 2)" + << "VAR =" + << "##:1: first(var) requires one argument." + << true; + + QTest::newRow("$$last(): empty") + << "IN = \nVAR = $$last(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$last(): one") + << "IN = one\nVAR = $$last(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$last(): multiple") + << "IN = one two three\nVAR = $$last(IN)" + << "VAR = three" + << "" + << true; + + QTest::newRow("$$last(): bad number of arguments") + << "VAR = $$last(1, 2)" + << "VAR =" + << "##:1: last(var) requires one argument." + << true; + + QTest::newRow("$$size()") + << "IN = one two three\nVAR = $$size(IN)" + << "VAR = 3" + << "" + << true; + + QTest::newRow("$$size(): bad number of arguments") + << "VAR = $$size(1, 2)" + << "VAR =" + << "##:1: size(var) requires one argument." + << true; + + QTest::newRow("$$fromfile(): right var") + << "VAR = $$fromfile(" + qindir + "/fromfile/infile.prx, DEFINES)" + << "VAR = QT_DLL" + << "" + << true; + + QTest::newRow("$$fromfile(): wrong var") + << "VAR = $$fromfile(" + qindir + "/fromfile/infile.prx, INCLUDES)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$fromfile(): bad file") + << "VAR = $$fromfile(" + qindir + "/fromfile/badfile.prx, DEFINES)" + << "VAR =" + << "Project ERROR: fail!" + << true; + + QTest::newRow("$$fromfile(): bad number of arguments") + << "VAR = $$fromfile(1) \\\n$$fromfile(1, 2, 3)" + << "VAR =" + << "##:1: fromfile(file, variable) requires two arguments.\n" + "##:2: fromfile(file, variable) requires two arguments." + << true; + + QTest::newRow("$$eval()") + << "IN = one two three\nVAR = $$eval(IN)" + << "VAR = one two three" + << "" + << true; + + QTest::newRow("$$eval(): bad number of arguments") + << "VAR = $$eval(1, 2)" + << "VAR =" + << "##:1: eval(variable) requires one argument." + << true; + + QTest::newRow("$$list()") + << "VARNAME = $$list(one, two three, 'four five')\nVAR = $$eval($$VARNAME)" + << "VAR = one two three four five" // total nonsense ... + << "" + << true; + + QTest::newRow("$$sprintf()") + << "VAR = $$sprintf(hello %1 %2, you, there)" + << "VAR = 'hello you there'" + << "" + << true; + + QTest::newRow("$$format_number(): simple number format") + << "VAR = $$format_number(13)" + << "VAR = 13" + << "" + << true; + + QTest::newRow("$$format_number(): negative number format") + << "VAR = $$format_number(-13)" + << "VAR = -13" + << "" + << true; + + QTest::newRow("$$format_number(): hex input number format") + << "VAR = $$format_number(13, ibase=16)" + << "VAR = 19" + << "" + << true; + + QTest::newRow("$$format_number(): hex output number format") + << "VAR = $$format_number(13, obase=16)" + << "VAR = d" + << "" + << true; + + QTest::newRow("$$format_number(): right aligned number format") + << "VAR = $$format_number(13, width=5)" + << "VAR = ' 13'" + << "" + << true; + + QTest::newRow("$$format_number(): left aligned number format") + << "VAR = $$format_number(13, width=5 leftalign)" + << "VAR = '13 '" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded number format") + << "VAR = $$format_number(13, width=5 zeropad)" + << "VAR = 00013" + << "" + << true; + + QTest::newRow("$$format_number(): always signed number format") + << "VAR = $$format_number(13, width=5 alwayssign)" + << "VAR = ' +13'" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded always signed number format") + << "VAR = $$format_number(13, width=5 alwayssign zeropad)" + << "VAR = +0013" + << "" + << true; + + QTest::newRow("$$format_number(): sign-padded number format") + << "VAR = $$format_number(13, width=5 padsign)" + << "VAR = ' 13'" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded sign-padded number format") + + << "VAR = $$format_number(13, width=5 padsign zeropad)" + << "VAR = ' 0013'" + << "" + << true; + + QTest::newRow("$$format_number(): bad number of arguments") + << "VAR = $$format_number(13, 1, 2)" + << "VAR =" + << "##:1: format_number(number[, options...]) requires one or two arguments." + << true; + + QTest::newRow("$$format_number(): invalid option") + << "VAR = $$format_number(13, foo=bar)" + << "VAR =" + << "##:1: format_number(): invalid format option foo=bar." + << true; + + QTest::newRow("$$join(): empty") + << "IN = \nVAR = $$join(IN, //)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$join(): multiple") + << "IN = one two three\nVAR = $$join(IN, //)" + << "VAR = one//two//three" + << "" + << true; + + QTest::newRow("$$join(): multiple surrounded") + << "IN = one two three\nVAR = $$join(IN, //, <<, >>)" + << "VAR = <<one//two//three>>" + << "" + << true; + + QTest::newRow("$$join(): bad number of arguments") + << "VAR = $$join(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: join(var, glue, before, after) requires one to four arguments." + << true; + + QTest::newRow("$$split(): default sep") + << "IN = 'one/two three' 'four / five'\nVAR = $$split(IN)" + << "VAR = one/two three four / five" + << "" + << true; + + QTest::newRow("$$split(): specified sep") + << "IN = 'one/two three' 'four / five'\nVAR = $$split(IN, /)" + << "VAR = one 'two three' 'four ' ' five'" + << "" + << true; + + QTest::newRow("$$split(): bad number of arguments") + << "VAR = $$split(1, 2, 3)" + << "VAR =" + << "##:1: split(var, sep) requires one or two arguments." + << true; + + QTest::newRow("$$basename(): empty") + << "IN = \nVAR = $$basename(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$basename(): bare") + << "IN = file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): relative") + << "IN = path/file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): absolute") + << "IN = \\\\path\\\\file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): bad number of arguments") + << "VAR = $$basename(1, 2)" + << "VAR =" + << "##:1: basename(var) requires one argument." + << true; + + QTest::newRow("$$dirname(): empty") + << "IN = \nVAR = $$dirname(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$dirname(): bare") + << "IN = file\nVAR = $$dirname(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$dirname(): relative") + << "IN = path/file\nVAR = $$dirname(IN)" + << "VAR = path" + << "" + << true; + + QTest::newRow("$$dirname(): absolute") + << "IN = \\\\path\\\\file\nVAR = $$dirname(IN)" + << "VAR = \\\\path" + << "" + << true; + + QTest::newRow("$$dirname(): bad number of arguments") + << "VAR = $$dirname(1, 2)" + << "VAR =" + << "##:1: dirname(var) requires one argument." + << true; + + QTest::newRow("$$section(): explicit end") + << "IN = one~two~three~four~five~six\nVAR = $$section(IN, ~, 2, 4)" + << "VAR = three~four~five" + << "" + << true; + + QTest::newRow("$$section(): implicit end") + << "IN = one~two~three~four~five~six\nVAR = $$section(IN, ~, 3)" + << "VAR = four~five~six" + << "" + << true; + + QTest::newRow("$$section(): bad number of arguments") + << "VAR = $$section(1, 2) \\\n$$section(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: section(var) section(var, sep, begin, end) requires three or four arguments.\n" + "##:2: section(var) section(var, sep, begin, end) requires three or four arguments." + << true; + + QTest::newRow("$$find()") + << "IN = foo bar baz blubb\nVAR = $$find(IN, ^ba)" + << "VAR = bar baz" + << "" + << true; + + QTest::newRow("$$find(): bad number of arguments") + << "VAR = $$find(1) \\\n$$find(1, 2, 3)" + << "VAR =" + << "##:1: find(var, str) requires two arguments.\n" + "##:2: find(var, str) requires two arguments." + << true; + + // FIXME: $$cat() & $$system(): There is no way to generate the newlines + // necessary for testing "multi-line" and "blob" mode adequately. + // Note: these functions have *different* splitting behavior. + + // This gives split_value_list() an exercise + QTest::newRow("$$cat(): default mode") + << "VAR = $$cat(" + qindir + "/cat/file2.txt)" + << "VAR = foo bar baz \"\\\"Hello, \\' world.\\\"\" post \"\\'Hello, \\\" world.\\'\" post \\\\\\\" \\\\\\' \\\\\\\\ \\\\a \\\\ nix \"\\\" \\\"\"" + << "" + << true; + + QTest::newRow("$$cat(): lines mode") + << "VAR = $$cat(" + qindir + "/cat/file1.txt, lines)" + << "VAR = '\"Hello, world.\"' 'foo bar baz'" + << "" + << true; + + QTest::newRow("$$cat(): bad number of arguments") + << "VAR = $$cat(1, 2, 3)" + << "VAR =" + << "##:1: cat(file, singleline=true) requires one or two arguments." + << true; + + QTest::newRow("$$system(): default mode") +#ifdef Q_OS_WIN + << "VAR = $$system('echo Hello, ^\"world.&& echo foo^\" bar baz')" +#else + << "VAR = $$system('echo Hello, \\\\\\\"world. && echo foo\\\\\\\" bar baz')" +#endif + << "VAR = Hello, '\"world. foo\"' bar baz" + << "" + << true; + + QTest::newRow("$$system(): lines mode") +#ifdef Q_OS_WIN + << "VAR = $$system('echo Hello, ^\"world.&& echo foo^\" bar baz', lines)" +#else + << "VAR = $$system('echo Hello, \\\\\\\"world. && echo foo\\\\\\\" bar baz', lines)" +#endif + << "VAR = 'Hello, \"world.' 'foo\" bar baz'" + << "" + << true; + + QTest::newRow("$$system(): bad number of arguments") + << "VAR = $$system(1, 2, 3)" + << "VAR =" + << "##:1: system(execute) requires one or two arguments." + << true; + + QTest::newRow("$$unique()") + << "IN = foo bar foo baz\nVAR = $$unique(IN)" + << "VAR = foo bar baz" + << "" + << true; + + QTest::newRow("$$unique(): bad number of arguments") + << "VAR = $$unique(1, 2)" + << "VAR =" + << "##:1: unique(var) requires one argument." + << true; + + QTest::newRow("$$reverse()") + << "IN = one two three\nVAR = $$reverse(IN)" + << "VAR = three two one" + << "" + << true; + + QTest::newRow("$$reverse(): bad number of arguments") + << "VAR = $$reverse(1, 2)" + << "VAR =" + << "##:1: reverse(var) requires one argument." + << true; + + QTest::newRow("$$quote()") + << "VAR = $$quote(foo bar, 'foo bar')" + << "VAR = 'foo bar' 'foo bar'" + << "" + << true; + + // FIXME: \n and \r go untested, because there is no way to get them into the + // expected result. And if there was one, this function would be unnecessary. + // In other news, the behavior of backslash escaping makes no sense. + QTest::newRow("$$escape_expand()") + << "VAR = $$escape_expand(foo\\\\ttab\\\\\\\\slash\\\\invalid, verbatim)" + << "VAR = 'foo\ttab\\\\\\\\slash\\\\invalid' verbatim" + << "" + << true; + + QTest::newRow("$$upper()") + << "VAR = $$upper(kEwL, STuff)" + << "VAR = KEWL STUFF" + << "" + << true; + + QTest::newRow("$$lower()") + << "VAR = $$lower(kEwL, STuff)" + << "VAR = kewl stuff" + << "" + << true; + + QTest::newRow("$$title()") + << "VAR = $$title(kEwL, STuff)" + << "VAR = Kewl Stuff" + << "" + << true; + + QTest::newRow("$$re_escape()") + << "VAR = $$re_escape(one, hey.*you[funny]+people)" + << "VAR = one hey\\\\.\\\\*you\\\\[funny\\\\]\\\\+people" + << "" + << true; + + QTest::newRow("$$val_escape()") + << "IN = easy \"less easy\" sca$${LITERAL_HASH}ry" + " crazy$$escape_expand(\\\\t\\\\r\\\\n)" + " $$escape_expand(\\\\t)stuff \\'no\\\"way\\\\here\n" + "VAR = $$val_escape(IN)" + << "VAR = easy '\\\"less easy\\\"' sca\\$\\${LITERAL_HASH}ry" + " crazy\\$\\$escape_expand(\\\\\\\\t\\\\\\\\r\\\\\\\\n)" + " \\$\\$escape_expand(\\\\\\\\t)stuff \\\\\\'no\\\\\\\"way\\\\\\\\here" + << "" + << true; + + QTest::newRow("$$val_escape(): bad number of arguments") + << "VAR = $$val_escape(1, 2)" + << "VAR =" + << "##:1: val_escape(var) requires one argument." + << true; + + QTest::newRow("$$files(): non-recursive") + << "VAR = $$files(" + qindir + "/files/file*.txt)" + << "VAR = " + qindir + "/files/file1.txt " + + qindir + "/files/file2.txt" + << "" + << true; + + QTest::newRow("$$files(): recursive") + << "VAR = $$files(" + qindir + "/files/file*.txt, true)" + << "VAR = " + qindir + "/files/file1.txt " + + qindir + "/files/file2.txt " + + qindir + "/files/dir/file1.txt " + + qindir + "/files/dir/file2.txt" + << "" + << true; + + QTest::newRow("$$files(): bad number of arguments") + << "VAR = $$files(1, 2, 3)" + << "VAR =" + << "##:1: files(pattern, recursive=false) requires one or two arguments." + << true; + +#if 0 + // FIXME: no emulated input layer + QTest::newRow("$$prompt()") + << "VAR = $$prompt(que)" + << "VAR = whatever" + << "Project PROMPT: que? " + << true; +#endif + + QTest::newRow("$$replace()") + << "IN = foo 'bar baz'\nVAR = $$replace(IN, \\\\bba, hello)" + << "VAR = foo 'hellor helloz'" + << "" + << true; + + QTest::newRow("$$replace(): bad number of arguments") + << "VAR = $$replace(1, 2) \\\n$$replace(1, 2, 3, 4)" + << "VAR =" + << "##:1: replace(var, before, after) requires three arguments.\n" + "##:2: replace(var, before, after) requires three arguments." + << true; + + QTest::newRow("$$sort_depends()") + << "foo.depends = bar baz\n" + "bar.depends = baz bak duck\n" + "baz.depends = bak\n" + "bak.depends = duck\n" + "VAR = $$sort_depends($$list(baz foo duck bar))" + << "VAR = foo bar baz duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): basic") + << "foo.depends = bar baz\n" + "bar.depends = baz bak duck\n" + "baz.depends = bak\n" + "bak.depends = duck\n" + "VAR = $$resolve_depends($$list(baz foo duck bar))" + << "VAR = foo bar baz bak duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): prefix and multiple suffixes") + << "MOD.foo.dep = bar baz\n" + "MOD.bar.dep = baz bak\n" + "MOD.bar.priv_dep = duck\n" + "MOD.baz.dep = bak\n" + "MOD.bak.dep = duck\n" + "VAR = $$resolve_depends($$list(baz foo duck bar), MOD., .dep .priv_dep)" + << "VAR = foo bar baz bak duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: b first") + << "MOD.a.depends =\n" + "MOD.b.depends =\n" + "MOD.b.priority = 1\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD.)" + << "VAR = c b a" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: a first") + << "MOD.a.depends =\n" + "MOD.a.priority = 1\n" + "MOD.b.depends =\n" + "MOD.b.priority = 0\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD.)" + << "VAR = c a b" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: custom suffix") + << "MOD.a.depends =\n" + "MOD.a.prrt = 1\n" + "MOD.b.depends =\n" + "MOD.b.prrt = 0\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD., .depends, .prrt)" + << "VAR = c a b" + << "" + << true; + + QTest::newRow("$$resolve_depends(): bad number of arguments") + << "VAR = $$resolve_depends(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: resolve_depends(var, [prefix, [suffixes, [prio-suffix]]]) requires one to four arguments." + << true; + + QTest::newRow("$$enumerate_vars()") + << "V1 = foo\nV2 = bar\nVAR = $$enumerate_vars()\n" + "count(VAR, 2, >=):contains(VAR, V1):contains(VAR, V2): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("$$shadowed(): bare") + << "VAR = $$shadowed(test.txt)" + << "VAR = " + QMakeEvaluator::quoteValue(ProString(m_outdir + "/test.txt")) + << "" + << true; + + QTest::newRow("$$shadowed(): subdir") + << "VAR = $$shadowed(" + qindir + "/sub/test.txt)" + << "VAR = " + QMakeEvaluator::quoteValue(ProString(m_outdir + "/sub/test.txt")) + << "" + << true; + + QTest::newRow("$$shadowed(): outside source dir") + << "VAR = $$shadowed(/some/random/path)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$shadowed(): bad number of arguments") + << "VAR = $$shadowed(1, 2)" + << "VAR =" + << "##:1: shadowed(path) requires one argument." + << true; + + QTest::newRow("$$absolute_path(): relative file") + << "VAR = $$absolute_path(dir/file.ext)" + << "VAR = " + qindir + "/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): file & path") + << "VAR = $$absolute_path(dir/file.ext, /root/sub)" + << "VAR = /root/sub/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): absolute file & path") + << "VAR = $$absolute_path(/root/sub/dir/file.ext, /other)" + << "VAR = /root/sub/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): empty file & path") + << "VAR = $$absolute_path('', /root/sub)" + << "VAR = /root/sub" + << "" + << true; + + QTest::newRow("$$absolute_path(): bad number of arguments") + << "VAR = $$absolute_path(1, 2, 3)" + << "VAR =" + << "##:1: absolute_path(path[, base]) requires one or two arguments." + << true; + + QTest::newRow("$$relative_path(): relative file") + << "VAR = $$relative_path(dir/file.ext)" + << "VAR = dir/file.ext" + << "" + << true; + + QTest::newRow("$$relative_path(): relative file to empty") + << "VAR = $$relative_path(dir/..)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$relative_path(): absolute file & path") + << "VAR = $$relative_path(/root/sub/dir/file.ext, /root/sub)" + << "VAR = dir/file.ext" + << "" + << true; + + QTest::newRow("$$relative_path(): empty file & path") + << "VAR = $$relative_path('', /root/sub)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$relative_path(): bad number of arguments") + << "VAR = $$relative_path(1, 2, 3)" + << "VAR =" + << "##:1: relative_path(path[, base]) requires one or two arguments." + << true; + + QTest::newRow("$$clean_path()") +#ifdef Q_OS_WIN // This is actually kinda stupid. + << "VAR = $$clean_path(foo//bar\\\\../baz/)" +#else + << "VAR = $$clean_path(foo//bar/../baz/)" +#endif + << "VAR = foo/baz" + << "" + << true; + + QTest::newRow("$$clean_path(): bad number of arguments") + << "VAR = $$clean_path(1, 2)" + << "VAR =" + << "##:1: clean_path(path) requires one argument." + << true; + + QTest::newRow("$$system_path()") + << "VAR = $$system_path(foo/bar\\\\baz)" +#ifdef Q_OS_WIN + << "VAR = foo\\\\bar\\\\baz" +#else + << "VAR = foo/bar/baz" +#endif + << "" + << true; + + QTest::newRow("$$system_path(): bad number of arguments") + << "VAR = $$system_path(1, 2)" + << "VAR =" + << "##:1: system_path(path) requires one argument." + << true; + + // This is is effectively $$system_path() in this test, as we load no specs + QTest::newRow("$$shell_path()") + << "VAR = $$shell_path(foo/bar\\\\baz)" +#ifdef Q_OS_WIN + << "VAR = foo\\\\bar\\\\baz" +#else + << "VAR = foo/bar/baz" +#endif + << "" + << true; + + QTest::newRow("$$shell_path(): bad number of arguments") + << "VAR = $$shell_path(1, 2)" + << "VAR =" + << "##:1: shell_path(path) requires one argument." + << true; + + // The quoteArgs() test exercises this more thoroughly + QTest::newRow("$$system_quote()") + << "IN = \nVAR = $$system_quote(\"some nasty & ugly\\\" path & thing\\\\\")" +#ifdef Q_OS_WIN + << "VAR = \"\\\"some nasty & ugly\\\\\\\" path ^& thing\\\\\\\\^\\\"\"" +#else + << "VAR = \"'some nasty & ugly\\\" path & thing\\\\'\"" +#endif + << "" + << true; + + QTest::newRow("$$system_quote(): bad number of arguments") + << "VAR = $$system_quote(1, 2)" + << "VAR =" + << "##:1: system_quote(arg) requires one argument." + << true; + + // This is is effectively $$system_path() in this test, as we load no specs + QTest::newRow("$$shell_quote()") + << "IN = \nVAR = $$shell_quote(\"some nasty & ugly\\\" path & thing\\\\\")" +#ifdef Q_OS_WIN + << "VAR = \"\\\"some nasty & ugly\\\\\\\" path ^& thing\\\\\\\\^\\\"\"" +#else + << "VAR = \"'some nasty & ugly\\\" path & thing\\\\'\"" +#endif + << "" + << true; + + QTest::newRow("$$shell_quote(): bad number of arguments") + << "VAR = $$shell_quote(1, 2)" + << "VAR =" + << "##:1: shell_quote(arg) requires one argument." + << true; + + QTest::newRow("$$getenv()") + << "VAR = $$getenv(E1)" + << "VAR = 'env var'" + << "" + << true; + + QTest::newRow("$$getenv(): bad number of arguments") + << "VAR = $$getenv(1, 2)" + << "VAR =" + << "##:1: getenv(arg) requires one argument." + << true; +} + +void tst_qmakelib::addTestFunctions(const QString &qindir) +{ + QTest::newRow("defined(): found replace") + << "defineReplace(func) {}\ndefined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(): found test") + << "defineTest(func) {}\ndefined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(): not found") + << "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(replace): found") + << "defineReplace(func) {}\ndefined(func, replace): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(replace): not found") + << "defineTest(func) {}\ndefined(func, replace): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(test): found") + << "defineTest(func) {}\ndefined(func, test): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(test): not found") + << "defineReplace(func) {}\ndefined(func, test): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(var): found") + << "VAR = 1\ndefined(VAR, var): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(var): not found") + << "defined(VAR, var): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(): invalid type") + << "defined(VAR, nope): OK = 1" + << "OK = UNDEF" + << "##:1: defined(function, type): unexpected type [nope]." + << true; + + QTest::newRow("defined(): bad number of arguments") + << "defined(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: defined(function, [\"test\"|\"replace\"|\"var\"]) requires one or two arguments." + << true; + + QTest::newRow("export()") + << "defineTest(func) {\n" + "VAR1 += different\nexport(VAR1)\n" + "unset(VAR2)\nexport(VAR2): OK = 1\nexport(OK)\n" + "VAR3 = new var\nexport(VAR3)\n" + "}\n" + "VAR1 = entirely\nVAR2 = set\nfunc()" + << "OK = 1\nVAR1 = entirely different\nVAR2 =\nVAR3 = new var" + << "" + << true; + + QTest::newRow("export(): bad number of arguments") + << "export(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: export(variable) requires one argument." + << true; + + QTest::newRow("infile(): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(): not found") + << "infile(" + qindir + "/fromfile/infile.prx, INCLUDES): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("infile(plain): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, QT_DLL): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(plain): not found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, NOPE): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("infile(regex): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, QT_.*): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(regex): not found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, NO.*): OK = 1" + << "OK = UNDEF" + << "" + << true; + + // The early return is debatable, esp. as it's inconsistent with $$fromfile() + QTest::newRow("infile(): bad file") + << "infile(" + qindir + "/fromfile/badfile.prx, DEFINES): OK = 1\nOKE = 1" + << "OK = UNDEF\nOKE = UNDEF" + << "Project ERROR: fail!" + << false; + + QTest::newRow("infile(): bad number of arguments") + << "infile(1): OK = 1\ninfile(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: infile(file, var, [values]) requires two or three arguments.\n" + "##:2: infile(file, var, [values]) requires two or three arguments." + << true; + + QTest::newRow("requires()") + << "requires(true, false, isEmpty(FOO), !isEmpty(BAR), true|false, true:false)" + << "QMAKE_FAILED_REQUIREMENTS = false !isEmpty(BAR) true:false" + << "" + << true; + + // The sparator semantics are *very* questionable. + // The return value semantics are rather questionable. + QTest::newRow("eval()") + << "eval(FOO = one, two$$escape_expand(\\\\n)BAR = blah$$escape_expand(\\\\n)error(fail)$$escape_expand(\\\\n)BAZ = nope)" + << "FOO = one two\nBAR = blah\nBAZ = UNDEF" + << "Project ERROR: fail" + << true; + + QTest::newRow("if(): true") + << "if(false|true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): true (space)") + << "if(false| true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): true (spaces)") + << "if( false | true ): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): false") + << "if(false:true): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): false (space)") + << "if(false: true): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): false (spaces)") + << "if( false : true ): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): bad number of arguments") + << "if(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: if(condition) requires one argument." + << true; + + QTest::newRow("CONFIG(simple): true") + << "CONFIG = debug release\nCONFIG(debug): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("CONFIG(simple): false") + << "CONFIG = debug release\nCONFIG(nope): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(alt): true") + << "CONFIG = debug release\nCONFIG(release, debug|release): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("CONFIG(alt): false (presence)") + << "CONFIG = not here\nCONFIG(debug, debug|release): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(alt): false (order)") + << "CONFIG = debug release\nCONFIG(debug, debug|release): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(): bad number of arguments") + << "CONFIG(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: CONFIG(config) requires one or two arguments." + << true; + + QTest::newRow("contains(simple plain): true") + << "VAR = one two three\ncontains(VAR, two): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(simple plain): false") + << "VAR = one two three\ncontains(VAR, four): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(simple regex): true") + << "VAR = one two three\ncontains(VAR, tw.*): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(simple regex): false") + << "VAR = one two three\ncontains(VAR, fo.*): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt plain): true") + << "VAR = one two three\ncontains(VAR, three, two|three): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(alt plain): false (presence)") + << "VAR = one four five\ncontains(VAR, three, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt plain): false (order)") + << "VAR = one two three\ncontains(VAR, two, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt regex): true") + << "VAR = one two three\ncontains(VAR, th.*, two|three): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(alt regex): false (presence)") + << "VAR = one four five\ncontains(VAR, th.*, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt regex): false (order)") + << "VAR = one two three\ncontains(VAR, tw.*, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(): bad number of arguments") + << "contains(1): OK = 1\ncontains(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: contains(var, val) requires two or three arguments.\n" + "##:2: contains(var, val) requires two or three arguments." + << true; + + QTest::newRow("count(): true") + << "VAR = one two three\ncount(VAR, 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("count(): false") + << "VAR = one two three\ncount(VAR, 4): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("count(operators): true") + << "VAR = one two three\n" + "count(VAR, 3, equals): OKE1 = 1\n" + "count(VAR, 3, isEqual): OKE2 = 1\n" + "count(VAR, 3, =): OKE3 = 1\n" + "count(VAR, 3, ==): OKE4 = 1\n" + "count(VAR, 2, greaterThan): OKG1 = 1\n" + "count(VAR, 2, >): OKG2 = 1\n" + "count(VAR, 2, >=): OKGE = 1\n" + "count(VAR, 4, lessThan): OKL1 = 1\n" + "count(VAR, 4, <): OKL2 = 1\n" + "count(VAR, 4, <=): OKLE = 1\n" + << "OKE1 = 1\nOKE2 = 1\nOKE3 = 1\nOKE4 = 1\n" + "OKG1 = 1\nOKG2 = 1\nOKGE = 1\n" + "OKL1 = 1\nOKL2 = 1\nOKLE = 1" + << "" + << true; + + QTest::newRow("count(operators): false") + << "VAR = one two three\n" + "count(VAR, 4, equals): OKE1 = 1\n" + "count(VAR, 4, isEqual): OKE2 = 1\n" + "count(VAR, 4, =): OKE3 = 1\n" + "count(VAR, 4, ==): OKE4 = 1\n" + "count(VAR, 3, greaterThan): OKG1 = 1\n" + "count(VAR, 3, >): OKG2 = 1\n" + "count(VAR, 4, >=): OKGE = 1\n" + "count(VAR, 3, lessThan): OKL1 = 1\n" + "count(VAR, 3, <): OKL2 = 1\n" + "count(VAR, 2, <=): OKLE = 1\n" + << "OKE1 = UNDEF\nOKE2 = UNDEF\nOKE3 = UNDEF\nOKE4 = UNDEF\n" + "OKG1 = UNDEF\nOKG2 = UNDEF\nOKGE = UNDEF\n" + "OKL1 = UNDEF\nOKL2 = UNDEF\nOKLE = UNDEF" + << "" + << true; + + QTest::newRow("count(): bad operator") + << "VAR = one two three\ncount(VAR, 2, !!!): OK = 1" + << "OK = UNDEF" + << "##:2: Unexpected modifier to count(!!!)." + << true; + + QTest::newRow("count(): bad number of arguments") + << "count(1): OK = 1\ncount(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: count(var, count, op=\"equals\") requires two or three arguments.\n" + "##:2: count(var, count, op=\"equals\") requires two or three arguments." + << true; + + QTest::newRow("greaterThan(int): true") + << "VAR = 20\ngreaterThan(VAR, 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("greaterThan(int): false") + << "VAR = 3\ngreaterThan(VAR, 20): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("greaterThan(string): true") + << "VAR = foo 3\ngreaterThan(VAR, foo 20): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("greaterThan(string): false") + << "VAR = foo 20\ngreaterThan(VAR, foo 3): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("greaterThan(): bad number of arguments") + << "greaterThan(1): OK = 1\ngreaterThan(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: greaterThan(variable, value) requires two arguments.\n" + "##:2: greaterThan(variable, value) requires two arguments." + << true; + + QTest::newRow("lessThan(int): true") + << "VAR = 3\nlessThan(VAR, 20): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("lessThan(int): false") + << "VAR = 20\nlessThan(VAR, 3): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("lessThan(string): true") + << "VAR = foo 20\nlessThan(VAR, foo 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("lessThan(string): false") + << "VAR = foo 3\nlessThan(VAR, foo 20): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("lessThan(): bad number of arguments") + << "lessThan(1): OK = 1\nlessThan(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: lessThan(variable, value) requires two arguments.\n" + "##:2: lessThan(variable, value) requires two arguments." + << true; + + QTest::newRow("equals(): true") + << "VAR = foo\nequals(VAR, foo): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("equals(): false") + << "VAR = foo\nequals(VAR, bar): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("equals(): bad number of arguments") + << "equals(1): OK = 1\nequals(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: equals(variable, value) requires two arguments.\n" + "##:2: equals(variable, value) requires two arguments." + << true; + + // That's just an alias, so don't test much. + QTest::newRow("isEqual(): true") + << "VAR = foo\nisEqual(VAR, foo): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("clear(): top-level") + << "VAR = there\nclear(VAR): OK = 1" + << "OK = 1\nVAR =" + << "" + << true; + + QTest::newRow("clear(): scoped") + << "defineTest(func) {\n" + "clear(VAR): OK = 1\nexport(OK)\n" + "equals(VAR, \"\"): OKE = 1\nexport(OKE)\n" + "}\n" + "VAR = there\nfunc()" + << "OK = 1\nOKE = 1" + << "" + << true; + + QTest::newRow("clear(): absent") + << "clear(VAR): OK = 1" + << "OK = UNDEF\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("clear(): bad number of arguments") + << "clear(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: clear(variable) requires one argument." + << true; + + QTest::newRow("unset(): top-level") + << "VAR = there\nunset(VAR): OK = 1" + << "OK = 1\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("unset(): scoped") + << "defineTest(func) {\n" + "unset(VAR): OK = 1\nexport(OK)\n" + "!defined(VAR, var): OKE = 1\nexport(OKE)\n" + "}\n" + "VAR = there\nfunc()" + << "OK = 1\nOKE = 1" + << "" + << true; + + QTest::newRow("unset(): absent") + << "unset(VAR): OK = 1" + << "OK = UNDEF\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("unset(): bad number of arguments") + << "unset(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: unset(variable) requires one argument." + << true; + + // This function does not follow the established naming pattern. + QTest::newRow("parseJson()") + << "jsontext = \\\n" + " \"{\"\\\n" + " \" \\\"array\\\" : [\\\"arrayItem1\\\", \\\"arrayItem2\\\", \\\"arrayItem3\\\"],\"\\\n" + " \" \\\"object\\\" : { \\\"key1\\\" : \\\"objectValue1\\\", \\\"key2\\\" : \\\"objectValue2\\\" },\"\\\n" + " \" \\\"string\\\" : \\\"test string\\\",\"\\\n" + " \" \\\"number\\\" : 999,\"\\\n" + " \" \\\"true\\\" : true,\"\\\n" + " \" \\\"false\\\" :false,\"\"\\\n" + " \" \\\"null\\\" : null\"\"\\\n" + " \"}\"\n" + "parseJson(jsontext, json): OK = 1" + << "OK = 1\n" + "json._KEYS_ = array false null number object string true\n" + // array + "json.array._KEYS_ = 0 1 2\n" + "json.array.0 = arrayItem1\n" + "json.array.1 = arrayItem2\n" + "json.array.2 = arrayItem3\n" + // object + "json.object._KEYS_ = key1 key2\n" + "json.object.key1 = objectValue1\n" + "json.object.key1 = objectValue1\n" + // value types + "json.string = 'test string'\n" + "json.number = 999\n" + "json.true = true\n" + "json.false = false\n" + "json.null = UNDEF" + << "" + << true; + + QTest::newRow("parseJson(): bad input") + << "jsontext = not good\n" + "parseJson(jsontext, json): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("parseJson(): bad number of arguments") + << "parseJson(1): OK = 1\nparseJson(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: parseJson(variable, into) requires two arguments.\n" + "##:2: parseJson(variable, into) requires two arguments." + << true; + + QTest::newRow("include()") + << "include(include/inc.pri): OK = 1\nfunc()" + << "OK = 1\nVAR = val\n.VAR = nope" + << "Project MESSAGE: say hi!" + << true; + + QTest::newRow("include(): fail") + << "include(include/nope.pri): OK = 1" + << "OK = UNDEF" + << "Cannot read " + m_indir + "/include/nope.pri: No such file or directory" + << true; + + QTest::newRow("include(): silent fail") + << "include(include/nope.pri, , true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("include(into)") + << "SUB.MISS = 1\ninclude(include/inc.pri, SUB): OK = 1" + << "OK = 1\nSUB.VAR = val\nSUB..VAR = UNDEF\nSUB.MISS = UNDEF\n" + // As a side effect, we test some things that need full project setup + "SUB.MATCH = 1\nSUB.QMAKESPEC = " + qindir + "/mkspecs/fake-g++" + << "" + << true; + + QTest::newRow("include(): bad number of arguments") + << "include(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: include(file, [into, [silent]]) requires one, two or three arguments." + << true; + + QTest::newRow("load()") + << "load(testfeat): OK = 1" + << "OK = 1\nVAR = foo bar" + << "" + << true; + + QTest::newRow("load(): fail") + << "load(no_such_feature): OK = 1" + << "OK = UNDEF" + << "##:1: Cannot find feature no_such_feature" + << true; + + QTest::newRow("load(): silent fail") + << "load(no_such_feature, true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("load(): bad number of arguments") + << "load(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: load(feature) requires one or two arguments." + << true; + + // We don't test debug() and log(), because they print directly to stderr. + + QTest::newRow("message()") + << "message('Hello, World!'): OK = 1\nOKE = 1" + << "OK = 1\nOKE = 1" + << "Project MESSAGE: Hello, World!" + << true; + + // Don't test that for warning() and error(), as it's the same code path. + QTest::newRow("message(): bad number of arguments") + << "message(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: message(message) requires one argument." + << true; + + QTest::newRow("warning()") + << "warning('World, be warned!'): OK = 1\nOKE = 1" + << "OK = 1\nOKE = 1" + << "Project WARNING: World, be warned!" + << true; + + QTest::newRow("error()") + << "error('World, you FAIL!'): OK = 1\nOKE = 1" + << "OK = UNDEF\nOKE = UNDEF" + << "Project ERROR: World, you FAIL!" + << false; + + QTest::newRow("system()") + << "system('" +#ifdef Q_OS_WIN + "cd" +#else + "pwd" +#endif + "> '" + QMakeEvaluator::quoteValue(ProString(QDir::toNativeSeparators( + m_outdir + "/system_out.txt"))) + "): OK = 1\n" + "DIR = $$cat(" + QMakeEvaluator::quoteValue(ProString( + m_outdir + "/system_out.txt")) + ")" + << "OK = 1\nDIR = " + QMakeEvaluator::quoteValue(ProString(QDir::toNativeSeparators(m_indir))) + << "" + << true; + + QTest::newRow("system(): fail") +#ifdef Q_OS_WIN + << "system(no_such_cmd 2> NUL): OK = 1" +#else + << "system(no_such_cmd 2> /dev/null): OK = 1" +#endif + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("system(): bad number of arguments") + << "system(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: system(exec) requires one argument." + << true; + + QTest::newRow("isEmpty(): true (empty)") + << "VAR =\nisEmpty(VAR): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("isEmpty(): true (undef)") + << "isEmpty(VAR): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("isEmpty(): false") + << "VAR = val\nisEmpty(VAR): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("isEmpty(): bad number of arguments") + << "isEmpty(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: isEmpty(var) requires one argument." + << true; + + QTest::newRow("exists(plain): true") + << "exists(files/file1.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("exists(plain): false") + << "exists(files/not_there.txt): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("exists(wildcard): true") + << "exists(files/fil*.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("exists(wildcard): false") + << "exists(files/not_th*.txt): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("exists(): bad number of arguments") + << "exists(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: exists(file) requires one argument." + << true; + + QString wpath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/outdir/written.txt")); + QTest::newRow("write_file(): create") + << "VAR = 'this is text' 'yet again'\n" + "write_file(" + wpath + ", VAR): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'this is text' 'yet again'" + << "" + << true; + + QTest::newRow("write_file(): truncate") + << "VAR = 'other content'\n" + "write_file(" + wpath + ", VAR): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'other content'" + << "" + << true; + + QTest::newRow("write_file(): append") + << "VAR = 'one more line'\n" + "write_file(" + wpath + ", VAR, append): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'other content' 'one more line'" + << "" + << true; + + QString vpath = QMakeEvaluator::quoteValue(ProString(m_outdir)); + QTest::newRow("write_file(): fail") + << "write_file(" + vpath + "): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot write file " + QDir::toNativeSeparators(m_outdir) + ": Access is denied." +#else + << "##:1: Cannot write file " + m_outdir + ": Is a directory" +#endif + << true; + + QTest::newRow("write_file(): bad number of arguments") + << "write_file(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: write_file(name, [content var, [append]]) requires one to three arguments." + << true; + + // FIXME: This doesn't test whether it actually works. + QTest::newRow("touch()") + << "touch(" + wpath + ", files/other.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("touch(): missing target") + << "touch(/does/not/exist, files/other.txt): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot open /does/not/exist: The system cannot find the path specified." +#else + << "##:1: Cannot touch /does/not/exist: No such file or directory." +#endif + << true; + + QTest::newRow("touch(): missing reference") + << "touch(" + wpath + ", /does/not/exist): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot open reference file /does/not/exist: The system cannot find the path specified." +#else + << "##:1: Cannot stat() reference file /does/not/exist: No such file or directory." +#endif + << true; + + QTest::newRow("touch(): bad number of arguments") + << "touch(1): OK = 1\ntouch(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: touch(file, reffile) requires two arguments.\n" + "##:2: touch(file, reffile) requires two arguments." + << true; + + QString apath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/a/path")); + QTest::newRow("mkpath()") + << "mkpath(" + apath + "): OK = 1\n" + "exists(" + apath + "): OKE = 1" + << "OK = 1\nOKE = 1" + << "" + << true; + + QString bpath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/fail_me")); + QTest::newRow("mkpath(): fail") + << "write_file(" + bpath + ")|error(FAIL)\n" + "mkpath(" + bpath + "): OK = 1" + << "OK = UNDEF" + << "##:2: Cannot create directory " + QDir::toNativeSeparators(m_outdir + "/fail_me") + '.' + << true; + + QTest::newRow("mkpath(): bad number of arguments") + << "mkpath(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: mkpath(file) requires one argument." + << true; + +#if 0 + // FIXME ... insanity lies ahead + QTest::newRow("cache()") + << "" + << "" + << "" + << true; +#endif +} + +void tst_qmakelib::proEval_data() +{ + QTest::addColumn<QString>("in"); + QTest::addColumn<QString>("out"); + QTest::addColumn<QString>("msgs"); + QTest::addColumn<bool>("ok"); + + QTest::newRow("empty") + << "" + << "VAR = UNDEF" + << "" + << true; + + addAssignments(); + addExpansions(); // Variable, etc. expansions on RHS + addControlStructs(); // Conditions, loops, custom functions + + QString qindir = QMakeEvaluator::quoteValue(ProString(m_indir)); + addReplaceFunctions(qindir); // Built-in replace functions + addTestFunctions(qindir); // Built-in test functions + + // Some compound tests that verify compatibility with odd Qt 4 edge cases + + QTest::newRow("empty (leading)") + << "defineTest(myMsg) { message(\"$$1\") }\n" + "XMPL = /this/is/a/test\n" + "message(split: $$split(XMPL, /))\n" + "message(split joined:$$split(XMPL, /))\n" + "message(\"split quoted: $$split(XMPL, /)\")\n" + "myMsg(my split: $$split(XMPL, /) :post)\n" + "myMsg(my split joined:$$split(XMPL, /):post)\n" + "myMsg(\"my split quoted: $$split(XMPL, /) post\")\n" + "OUT = word $$split(XMPL, /) done\n" + "message(\"assign split separate: $$OUT\")\n" + "OUT = word:$$split(XMPL, /):done\n" + "message(\"assign split joined: $$OUT\")\n" + "OUT = \"word $$split(XMPL, /) done\"\n" + "message(\"assign split quoted: $$OUT\")\n" + << "" + << "Project MESSAGE: split: this is a test\n" + "Project MESSAGE: split joined: this is a test\n" + "Project MESSAGE: split quoted: this is a test\n" + "Project MESSAGE: my split: this is a test :post\n" + "Project MESSAGE: my split joined: this is a test:post\n" + "Project MESSAGE: my split quoted: this is a test post\n" + "Project MESSAGE: assign split separate: word this is a test done\n" + "Project MESSAGE: assign split joined: word: this is a test:done\n" + "Project MESSAGE: assign split quoted: word this is a test done" + << true; + + QTest::newRow("empty (multiple)") + << "defineTest(myMsg) { message(\"$$1\") }\n" + "XMPL = //this///is/a/////test\n" + "message(split: $$split(XMPL, /) :post)\n" + "message(split joined:$$split(XMPL, /):post)\n" + "message(\"split quoted: $$split(XMPL, /) post\")\n" + "myMsg(my split: $$split(XMPL, /) :post)\n" + "myMsg(my split joined:$$split(XMPL, /):post)\n" + "myMsg(\"my split quoted: $$split(XMPL, /) post\")\n" + "OUT = word $$split(XMPL, /) done\n" + "message(\"assign split separate: $$OUT\")\n" + "OUT = word:$$split(XMPL, /):done\n" + "message(\"assign split joined: $$OUT\")\n" + "OUT = \"word $$split(XMPL, /) done\"\n" + "message(\"assign split quoted: $$OUT\")\n" + << "" + << "Project MESSAGE: split: this is a test :post\n" + "Project MESSAGE: split joined: this is a test:post\n" + "Project MESSAGE: split quoted: this is a test post\n" + "Project MESSAGE: my split: this is a test :post\n" + "Project MESSAGE: my split joined: this is a test:post\n" + "Project MESSAGE: my split quoted: this is a test post\n" + "Project MESSAGE: assign split separate: word this is a test done\n" + "Project MESSAGE: assign split joined: word: this is a test:done\n" + "Project MESSAGE: assign split quoted: word this is a test done" + << true; +} + +static QString formatValue(const ProStringList &vals) +{ + QString ret; + + foreach (const ProString &str, vals) { + ret += QLatin1Char(' '); + ret += QMakeEvaluator::quoteValue(str); + } + return ret; +} + +static void skipNoise(const ushort *&tokPtr) +{ + forever { + ushort tok = *tokPtr; + if (tok != TokLine) + break; + tokPtr += 2; + } +} + +static bool compareState(QMakeEvaluator *eval, ProFile *out) +{ + bool ret = true; + const ushort *tokPtr = out->tokPtr(); + forever { + skipNoise(tokPtr); + ushort tok = *tokPtr++; + if (!tok) + break; + if (tok != TokHashLiteral) { + qWarning("Expected output is malformed: not variable%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + const ProKey &var = out->getHashStr(tokPtr); + tok = *tokPtr++; + if (tok != TokAssign) { + qWarning("Expected output is malformed: not assignment%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + ProStringList value; + value.reserve(*tokPtr++); + forever { + skipNoise(tokPtr); + tok = *tokPtr++; + if (tok == TokValueTerminator) + break; + if (tok != (TokLiteral | TokNewStr)) { + qWarning("Expected output is malformed: not literal%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + value << out->getStr(tokPtr); + } + ProValueMap::Iterator it; + ProValueMap *vmap = eval->findValues(var, &it); + if (value.length() == 1 && value.at(0) == "UNDEF") { + if (vmap) { + qWarning("Value of %s is incorrect.\n Actual:%s\nExpected: <UNDEFINED>", + qPrintable(var.toQString()), + qPrintable(formatValue(*it))); + ret = false; + } + } else { + if (!vmap) { + qWarning("Value of %s is incorrect.\n Actual: <UNDEFINED>\nExpected:%s", + qPrintable(var.toQString()), + qPrintable(formatValue(value))); + ret = false; + } else if (*it != value) { + qWarning("Value of %s is incorrect.\n Actual:%s\nExpected:%s", + qPrintable(var.toQString()), + qPrintable(formatValue(*it)), qPrintable(formatValue(value))); + ret = false; + } + } + } + return ret; +} + +void tst_qmakelib::proEval() +{ + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, msgs); + QFETCH(bool, ok); + + QString infile = m_indir + "/test.pro"; + bool verified = true; + QMakeTestHandler handler; + handler.setExpectedMessages(msgs.replace("##:", infile + ':').split('\n', QString::SkipEmptyParts)); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &handler); + QMakeGlobals globals; + globals.do_cache = false; + globals.xqmakespec = "fake-g++"; + globals.environment = m_env; + globals.setProperties(m_prop); + globals.setDirectories(m_indir, m_outdir); + ProFile *outPro = parser.parsedProBlock(out, "out", 1, QMakeParser::FullGrammar); + if (!outPro->isOk()) { + qWarning("Expected output is malformed"); + verified = false; + } + ProFile *pro = parser.parsedProBlock(in, infile, 1, QMakeParser::FullGrammar); + QMakeEvaluator visitor(&globals, &parser, &vfs, &handler); + visitor.setOutputDir(m_outdir); +#ifdef Q_OS_WIN + visitor.m_dirSep = ProString("\\"); +#else + visitor.m_dirSep = ProString("/"); +#endif + QMakeEvaluator::VisitReturn ret + = visitor.visitProFile(pro, QMakeHandler::EvalAuxFile, QMakeEvaluator::LoadProOnly); + if (handler.printedMessages()) { + qWarning("Got unexpected message(s)"); + verified = false; + } + QStringList missingMsgs = handler.expectedMessages(); + if (!missingMsgs.isEmpty()) { + foreach (const QString &msg, missingMsgs) + qWarning("Missing message: %s", qPrintable(msg)); + verified = false; + } + if ((ret == QMakeEvaluator::ReturnTrue) != ok) { + static const char * const lbl[] = { "failure", "success" }; + qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); + verified = false; + } + if (!compareState(&visitor, outPro)) + verified = false; + pro->deref(); + outPro->deref(); + QVERIFY(verified); +} diff --git a/tests/auto/tools/qmakelib/parsertest.cpp b/tests/auto/tools/qmakelib/parsertest.cpp new file mode 100644 index 0000000000..a7b7431a98 --- /dev/null +++ b/tests/auto/tools/qmakelib/parsertest.cpp @@ -0,0 +1,1987 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_qmakelib.h" + +#include <proitems.h> +#include <qmakevfs.h> +#include <qmakeparser.h> + +class TokenStream +{ +public: + TokenStream() {} + QString toString() const { return ts; } + + TokenStream &operator<<(ushort n) { ts += QChar(n); return *this; } + TokenStream &operator<<(uint n) { ts += QChar(n & 0xffff); ts += QChar(n >> 16); return *this; } + TokenStream &operator<<(const QStringRef &s) { ts += s; return *this; } + TokenStream &operator<<(const ProString &s) { return *this << ushort(s.length()) << s.toQStringRef(); } + TokenStream &operator<<(const ProKey &s) { return *this << s.hash() << s.toString(); } + +private: + QString ts; +}; + +#define TS(s) (TokenStream() s).toString() +#define H(n) ushort(n) +#define I(n) uint(n) +#define S(s) ProString(QString::fromWCharArray(s)) +#define HS(s) ProKey(QString::fromWCharArray(s)) + +QT_WARNING_PUSH +QT_WARNING_DISABLE_MSVC(4003) // "not enough actual parameters for macro TS()" + +void tst_qmakelib::addParseOperators() +{ + QTest::newRow("assign none") + << "VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("append none") + << "VAR +=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAppend) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("unique append none") + << "VAR *=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAppendUnique) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("remove none") + << "VAR -=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokRemove) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("replace empty") + << "VAR ~=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokReplace) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("assignment without variable") + << "=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokAssign) << H(0) + /* 4 */ << H(TokValueTerminator)) + << "in:1: Assignment needs exactly one word on the left hand side." + << false; + + QTest::newRow("assignment with multiple variables") + << "VAR VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokAssign) << H(0) + /* 4 */ << H(TokValueTerminator)) + << "in:1: Assignment needs exactly one word on the left hand side." + << false; +} + +void tst_qmakelib::addParseValues() +{ +#define ASSIGN_VAR(h) \ + H(TokLine) << H(1) \ + << H(TokHashLiteral) << HS(L"VAR") \ + << H(TokAssign) << H(h) + + QTest::newRow("one literal") + << "VAR = val" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("one literal (squeezed)") + << "VAR=val" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many literals") + << "VAR = foo barbaz bak hello" + << TS( + /* 0 */ << ASSIGN_VAR(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") + /* 36 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many literals (tab-separated") + << "VAR\t=\tfoo\tbarbaz\tbak\thello" + << TS( + /* 0 */ << ASSIGN_VAR(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") + /* 36 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("one quoted literal") + << "VAR = \"val ue\"" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue") + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted literal with missing quote") + << "VAR = val \"ue" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "in:1: Missing closing \" quote" + << false; + + QTest::newRow("many quoted literals") + << "VAR = \"foo\" barbaz 'bak hello' \"\"" + << TS( + /* 0 */ << ASSIGN_VAR(3) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak hello") + /* 35 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many quoted literals (with tabs)") + << "VAR\t=\t\"foo\"\tbarbaz\t'bak\thello'" + << TS( + /* 0 */ << ASSIGN_VAR(3) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak\thello") + /* 35 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted and unquoted spaces") + << " VAR = \"val ue \" " + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue ") + /* 22 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("funny literals") + << "VAR = foo:bar|!baz(blam!, ${foo})" + << TS( + /* 0 */ << ASSIGN_VAR(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo:bar|!baz(blam!,") + /* 32 */ << H(TokLiteral | TokNewStr) << S(L"${foo})") + /* 41 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("literals with escapes") + << "VAR = \\{hi\\} \\[ho\\] \\)uh\\( \"\\\\oh\\$\"\\' \\$\\${FOO}" + << TS( + /* 0 */ << ASSIGN_VAR(5) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{hi}") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"[ho]") + /* 23 */ << H(TokLiteral | TokNewStr) << S(L")uh(") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"\\oh$'") + /* 36 */ << H(TokLiteral | TokNewStr) << S(L"$${FOO}") + /* 45 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("magic variables") + << "VAR = $$LITERAL_HASH $$LITERAL_DOLLAR $$LITERAL_WHITESPACE $$_FILE_ $$_LINE_" + << TS( + /* 0 */ << ASSIGN_VAR(5) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"#") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"$") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"\t") + /* 20 */ << H(TokLiteral | TokNewStr) << S(L"in") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"1") + /* 27 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("continuations and comments") + << "VAR = foo \\\n bar\n \n" + "GAR = foo \\ # comment\n bar \\\n # comment\n baz \\\n" + "\"quoted \\ #comment\n escape\" \\\n right\\\n after \\\n gorilla!\n \n\n" + "MOO = \\\n kuh # comment\nLOO =\n\n" + "FOO = bar \\\n# comment\n baz \\\n \n# comment\n" + "GAZ=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 21 */ << H(TokValueTerminator) + /* 22 */ << H(TokLine) << H(4) + /* 24 */ << H(TokHashLiteral) << HS(L"GAR") + /* 31 */ << H(TokAssign) << H(7) + /* 33 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 38 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 43 */ << H(TokLiteral | TokNewStr) << S(L"baz") + /* 48 */ << H(TokLiteral | TokNewStr) << S(L"quoted escape") + /* 64 */ << H(TokLiteral | TokNewStr) << S(L"right") + /* 71 */ << H(TokLiteral | TokNewStr) << S(L"after") + /* 78 */ << H(TokLiteral | TokNewStr) << S(L"gorilla!") + /* 88 */ << H(TokValueTerminator) + /* 89 */ << H(TokLine) << H(15) + /* 91 */ << H(TokHashLiteral) << HS(L"MOO") + /* 98 */ << H(TokAssign) << H(0) + /* 100 */ << H(TokLiteral | TokNewStr) << S(L"kuh") + /* 105 */ << H(TokValueTerminator) + /* 106 */ << H(TokLine) << H(17) + /* 108 */ << H(TokHashLiteral) << HS(L"LOO") + /* 115 */ << H(TokAssign) << H(0) + /* 117 */ << H(TokValueTerminator) + /* 118 */ << H(TokLine) << H(19) + /* 120 */ << H(TokHashLiteral) << HS(L"FOO") + /* 127 */ << H(TokAssign) << H(2) + /* 129 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 134 */ << H(TokLiteral | TokNewStr) << S(L"baz") + /* 139 */ << H(TokValueTerminator) + /* 140 */ << H(TokLine) << H(24) + /* 142 */ << H(TokHashLiteral) << HS(L"GAZ") + /* 149 */ << H(TokAssign) << H(0) + /* 151 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("accidental continuation") + << "VAR0 = \\\n this \\\n is \\\n ok\n" + "VAR1 = \\\n this \\\n is=still \\\n ok\n" + "VAR2 = \\\n this \\\n is \\\n" + "VAR3 = \\\n not ok\n" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR0") + /* 10 */ << H(TokAssign) << H(3) + /* 12 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"is") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 26 */ << H(TokValueTerminator) + /* 27 */ << H(TokLine) << H(5) + /* 29 */ << H(TokHashLiteral) << HS(L"VAR1") + /* 37 */ << H(TokAssign) << H(3) + /* 39 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 45 */ << H(TokLiteral | TokNewStr) << S(L"is=still") + /* 55 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 59 */ << H(TokValueTerminator) + /* 60 */ << H(TokLine) << H(9) + /* 62 */ << H(TokHashLiteral) << HS(L"VAR2") + /* 70 */ << H(TokAssign) << H(6) + /* 72 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 78 */ << H(TokLiteral | TokNewStr) << S(L"is") + /* 82 */ << H(TokLiteral | TokNewStr) << S(L"VAR3") + /* 88 */ << H(TokLiteral | TokNewStr) << S(L"=") + /* 91 */ << H(TokLiteral | TokNewStr) << S(L"not") + /* 96 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 100 */ << H(TokValueTerminator)) + << "WARNING: in:12: Possible accidental line continuation" + << true; + + QTest::newRow("plain variable expansion") + << "VAR = $$bar" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced variable expansion") + << "VAR = $${foo/bar}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"foo/bar") + /* 22 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("bogus variable expansion") + << "VAR = $$ " + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") + /* 15 */ << H(TokValueTerminator)) + << "WARNING: in:1: Missing name in expansion" + << true; + + QTest::newRow("bogus braced variable expansion") + << "VAR = $${}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") + /* 15 */ << H(TokValueTerminator)) + << "WARNING: in:1: Missing name in expansion" + << true; + + QTest::newRow("unterminated braced variable expansion") + << "VAR = $${FOO" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO") + /* 18 */ << H(TokValueTerminator)) + << "in:1: Missing } terminator [found end-of-line]" + << false; + + QTest::newRow("invalid identifier in braced variable expansion") + << "VAR = $${FOO/BAR+BAZ}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO/BAR") + /* 22 */ << H(TokLiteral) << S(L"+BAZ") + /* 28 */ << H(TokValueTerminator)) + << "in:1: Missing } terminator [found +]" + << false; + + QTest::newRow("property expansion") + << "VAR = $$[bar]" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokProperty | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("environment expansion") + << "VAR = $$(bar)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokEnvVar | TokNewStr) << S(L"bar") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("plain function call") + << "VAR = $$bar()" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokFuncTerminator) + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced function call") + << "VAR = $${bar()}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokFuncTerminator) + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("function call with one argument") + << "VAR = $$bar(blubb)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokFuncTerminator) + /* 26 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("function call with multiple arguments") + << "VAR = $$bar( blubb blubb, hey ,$$you)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 32 */ << H(TokArgSeparator) + /* 33 */ << H(TokLiteral | TokNewStr) << S(L"hey") + /* 38 */ << H(TokArgSeparator) + /* 39 */ << H(TokVariable | TokNewStr) << HS(L"you") + /* 46 */ << H(TokFuncTerminator) + /* 47 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("nested function call") + << "VAR = $$foo(yo, $$bar(blubb))" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"foo") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"yo") + /* 22 */ << H(TokArgSeparator) + /* 23 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 30 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 37 */ << H(TokFuncTerminator) + /* 38 */ << H(TokFuncTerminator) + /* 39 */ << H(TokValueTerminator)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("function call with parenthesized argument") + << "VAR = $$bar(blubb (yo, man) blabb, nope)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"(yo,") + /* 31 */ << H(TokLiteral | TokNewStr) << S(L"man)") + /* 37 */ << H(TokLiteral | TokNewStr) << S(L"blabb") + /* 44 */ << H(TokArgSeparator) + /* 45 */ << H(TokLiteral | TokNewStr) << S(L"nope") + /* 51 */ << H(TokFuncTerminator) + /* 52 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("separate literal and expansion") + << "VAR = foo $$bar" + << TS( + /* 0 */ << ASSIGN_VAR(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("separate expansion and literal") + << "VAR = $$bar foo" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("joined literal and expansion") + << "VAR = foo$$bar" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("joined expansion and literal") + << "VAR = $${bar}foo" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral) << S(L"foo") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("plain variable expansion with funny name and literal") + << "VAR = $$az_AZ_09.dot/nix" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot") + /* 27 */ << H(TokLiteral) << S(L"/nix") + /* 33 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced variable expansion with funny name") + << "VAR = $${az_AZ_09.dot/nix}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot/nix") + /* 31 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted joined literal and expansion") + << "VAR = 'foo$$bar'" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable | TokQuoted) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("assignment with expansion in variable name") + << "VAR$$EXTRA =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokVariable) << HS(L"EXTRA") + /* 18 */ << H(TokAssign) << H(0) + /* 20 */ << H(TokValueTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseConditions() +{ + QTest::newRow("one test") + << "foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("wildcard-test") + << "foo-*" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo-*") + /* 11 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("one quoted test") + << "\"foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("two tests") + << "foo\nbar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokLine) << H(2) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("bogus two tests") + << "foo bar\nbaz" + << TS() + << "in:1: Extra characters after test expression." + << false; + + QTest::newRow("test-AND-test") + << "foo:bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-OR-test") + << " foo | bar " + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokOr) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("NOT-test") + << "!foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("NOT-NOT-test") + << "!!foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("quoted-NOT-test") + << "\"!foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("NOT-quoted-test") + << "!\"foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-NOT-test") + << "foo:!bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokNot) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-assignment") + << "foo\nVAR=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokLine) << H(2) + /* 12 */ << H(TokHashLiteral) << HS(L"VAR") + /* 19 */ << H(TokAssign) << H(0) + /* 21 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("test-AND-assignment") + << "foo: VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(11) + /* 13 */ << H(TokHashLiteral) << HS(L"VAR") + /* 20 */ << H(TokAssign) << H(0) + /* 22 */ << H(TokValueTerminator) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-else-test") + << "foo\nelse: bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(0) + /* 13 */ /* else branch */ << I(11) + /* 15 */ << H(TokLine) << H(2) + /* 17 */ << H(TokHashLiteral) << HS(L"bar") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("function-else-test") + << "foo()\nelse: bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(0) + /* 14 */ /* else branch */ << I(11) + /* 16 */ << H(TokLine) << H(2) + /* 18 */ << H(TokHashLiteral) << HS(L"bar") + /* 25 */ << H(TokCondition) + /* 26 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-test-else-test") + << "foo:bar\nelse: baz" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition) + /* 19 */ << H(TokBranch) + /* 20 */ /* then branch */ << I(0) + /* 22 */ /* else branch */ << I(11) + /* 24 */ << H(TokLine) << H(2) + /* 26 */ << H(TokHashLiteral) << HS(L"baz") + /* 33 */ << H(TokCondition) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-test-else-test-else-test-function") + << "foo:bar\nelse: baz\nelse: bak\nbuzz()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition) + /* 19 */ << H(TokBranch) + /* 20 */ /* then branch */ << I(0) + /* 22 */ /* else branch */ << I(27) + /* 24 */ << H(TokLine) << H(2) + /* 26 */ << H(TokHashLiteral) << HS(L"baz") + /* 33 */ << H(TokCondition) + /* 34 */ << H(TokBranch) + /* 35 */ /* then branch */ << I(0) + /* 37 */ /* else branch */ << I(11) + /* 39 */ << H(TokLine) << H(3) + /* 41 */ << H(TokHashLiteral) << HS(L"bak") + /* 48 */ << H(TokCondition) + /* 49 */ << H(TokTerminator) + /* 50 */ << H(TokTerminator) + /* 51 */ << H(TokLine) << H(4) + /* 53 */ << H(TokHashLiteral) << HS(L"buzz") + /* 61 */ << H(TokTestCall) + /* 62 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("test-assignment-else-assignment") + << "foo: VAR =\nelse: VAR=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(11) + /* 13 */ << H(TokHashLiteral) << HS(L"VAR") + /* 20 */ << H(TokAssign) << H(0) + /* 22 */ << H(TokValueTerminator) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(13) + /* 26 */ << H(TokLine) << H(2) + /* 28 */ << H(TokHashLiteral) << HS(L"VAR") + /* 35 */ << H(TokAssign) << H(0) + /* 37 */ << H(TokValueTerminator) + /* 38 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-else-test-assignment") + << "foo\nelse: bar: VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(0) + /* 13 */ /* else branch */ << I(27) + /* 15 */ << H(TokLine) << H(2) + /* 17 */ << H(TokHashLiteral) << HS(L"bar") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokBranch) + /* 26 */ /* then branch */ << I(11) + /* 28 */ << H(TokHashLiteral) << HS(L"VAR") + /* 35 */ << H(TokAssign) << H(0) + /* 37 */ << H(TokValueTerminator) + /* 38 */ << H(TokTerminator) + /* 39 */ /* else branch */ << I(0) + /* 41 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("one function") + << "foo()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("one function (with spaces)") + << " foo( ) " + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("unterminated function call") + << "foo(\nfoo" + << TS() + << "in:1: Missing closing parenthesis in function call" + << false; + + QTest::newRow("function with arguments") + << "foo(blah, hi ho)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah") + /* 16 */ << H(TokArgSeparator) + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"hi") + /* 21 */ << H(TokLiteral | TokNewStr) << S(L"ho") + /* 25 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function with empty arguments") + << "foo(,)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokArgSeparator) + /* 11 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function with funny arguments") + << "foo(blah\\, \"hi , \\ho\" ,uh\\ ,\\oh ,, )" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah\\") + /* 17 */ << H(TokArgSeparator) + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi , \\ho") + /* 29 */ << H(TokArgSeparator) + /* 30 */ << H(TokLiteral | TokNewStr) << S(L"uh\\") + /* 35 */ << H(TokArgSeparator) + /* 36 */ << H(TokLiteral | TokNewStr) << S(L"\\oh") + /* 41 */ << H(TokArgSeparator) + /* 42 */ << H(TokArgSeparator) + /* 43 */ << H(TokFuncTerminator)) + << "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated" + << true; + + QTest::newRow("function with nested call") + << "foo($$blah(hi ho))" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncName | TokNewStr) << HS(L"blah") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ho") + /* 26 */ << H(TokFuncTerminator) + /* 27 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("stand-alone parentheses") + << "()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) + /* 3 */ << H(TokFuncTerminator)) + << "in:1: Opening parenthesis without prior test name." + << false; + + QTest::newRow("bogus test and function") + << "foo bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) + /* 3 */ << H(TokFuncTerminator)) + << "in:1: Extra characters after test expression." + << false; + + // This is a rather questionable "feature" + QTest::newRow("two functions") + << "foo() bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokTestCall) + /* 19 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function-AND-test") + << "foo():bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-function") + << "foo:bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokTestCall) + /* 19 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("NOT-function-AND-test") + << "!foo():bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokTestCall) + /* 11 */ << H(TokFuncTerminator) + /* 12 */ << H(TokAnd) + /* 13 */ << H(TokHashLiteral) << HS(L"bar") + /* 20 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-NOT-function") + << "foo:!bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokNot) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokTestCall) + /* 20 */ << H(TokFuncTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseControlStatements() +{ + QTest::newRow("for(VAR, LIST) loop") + << "for(VAR, LIST)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"VAR") + /* 9 */ /* iterator */ << I(7) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 17 */ << H(TokValueTerminator) + /* 18 */ /* body */ << I(1) + /* 20 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for(ever) loop") + << "for(ever)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("for($$blub) loop") + << "for($$blub)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokVariable | TokNewStr) << HS(L"blub") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-for-test-else-test") + << "true:for(VAR, LIST): true\nelse: true" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(31) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(12) + /* 32 */ << H(TokLine) << H(1) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokTerminator) + /* 44 */ << H(TokTerminator) + /* 45 */ /* else branch */ << I(12) + /* 47 */ << H(TokLine) << H(2) + /* 49 */ << H(TokHashLiteral) << HS(L"true") + /* 57 */ << H(TokCondition) + /* 58 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("next()") + << "for(ever): next()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("break()") + << "for(ever): break()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokBreak) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("top-level return()") + << "return()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokReturn)) + << "" + << true; + + QTest::newRow("else") + << "else" + << TS() + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("test-{else}") + << "test { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("defineTest-{else}") + << "defineTest(fn) { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"fn") + /* 8 */ /* body */ << I(1) + /* 10 */ << H(TokTerminator)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("for-else") + << "for(ever) { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("double-test-else") + << "foo bar\nelse" + << TS( + /* 0 */ << H(TokBranch) + /* 1 */ /* then branch */ << I(0) + /* 3 */ /* else branch */ << I(1) // This seems weird + /* 5 */ << H(TokTerminator)) + << "in:1: Extra characters after test expression." + << false; + + QTest::newRow("test-function-else") + << "foo bar()\nelse" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) // This seems pointless + /* 3 */ << H(TokFuncTerminator) + /* 4 */ << H(TokBranch) + /* 5 */ /* then branch */ << I(0) + /* 7 */ /* else branch */ << I(1) // This seems weird + /* 9 */ << H(TokTerminator)) + << "in:1: Extra characters after test expression." + << false; +} + +void tst_qmakelib::addParseBraces() +{ + QTest::newRow("{}") + << "{ }" + << TS() + << "" + << true; + + QTest::newRow("{}-newlines") + << "\n\n{ }\n\n" + << TS() + << "" + << true; + + QTest::newRow("{") + << "{" + << TS() + << "in:2: Missing closing brace(s)." + << false; + + QTest::newRow("test {") + << "test {" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "in:2: Missing closing brace(s)." + << false; + + QTest::newRow("}") + << "}" + << TS() + << "in:1: Excess closing brace." + << false; + + QTest::newRow("{test}") + << "{ true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("{test-newlines}") + << "{\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(2) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("{assignment-test}-test") + << "{ VAR = { foo } bar } true" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 19 */ << H(TokLiteral | TokNewStr) << S(L"}") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 27 */ << H(TokValueTerminator) + /* 28 */ << H(TokHashLiteral) << HS(L"true") + /* 36 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("assignment with excess opening brace") + << "VAR = { { foo }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"}") + /* 25 */ << H(TokValueTerminator)) + << "WARNING: in:1: Possible braces mismatch" + << true; + + QTest::newRow("test-{}") + << "true {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{newlines}") + << "true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{test}") + << "true { true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test:-{test}") + << "true: { true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-{test-newlines}") + << "true {\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test:-{test-newlines}") + << "true: {\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(0)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-{assignment}") + << "true { VAR = {foo} }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(18) + /* 14 */ << H(TokHashLiteral) << HS(L"VAR") + /* 21 */ << H(TokAssign) << H(0) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 30 */ << H(TokValueTerminator) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{test-assignment}") + << "true { true: VAR = {foo} }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(33) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokBranch) + /* 24 */ /* then branch */ << I(18) + /* 26 */ << H(TokHashLiteral) << HS(L"VAR") + /* 33 */ << H(TokAssign) << H(0) + /* 35 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 42 */ << H(TokValueTerminator) + /* 43 */ << H(TokTerminator) + /* 44 */ /* else branch */ << I(0) + /* 46 */ << H(TokTerminator) + /* 47 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{assignment-newlines}") + << "true {\nVAR = {foo}\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(20) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"VAR") + /* 23 */ << H(TokAssign) << H(0) + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 32 */ << H(TokValueTerminator) + /* 33 */ << H(TokTerminator) + /* 34 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{}-else-test-{}") + << "true {} else: true {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(18) + /* 17 */ << H(TokLine) << H(1) + /* 19 */ << H(TokHashLiteral) << HS(L"true") + /* 27 */ << H(TokCondition) + /* 28 */ << H(TokBranch) + /* 29 */ /* then branch */ << I(1) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-{}-else-test-{}-newlines") + << "true {\n}\nelse: true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(18) + /* 17 */ << H(TokLine) << H(3) + /* 19 */ << H(TokHashLiteral) << HS(L"true") + /* 27 */ << H(TokCondition) + /* 28 */ << H(TokBranch) + /* 29 */ /* then branch */ << I(1) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-{test}-else-test-{}-newlines") + << "true {\ntrue\n}\nelse: true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(18) + /* 28 */ << H(TokLine) << H(4) + /* 30 */ << H(TokHashLiteral) << HS(L"true") + /* 38 */ << H(TokCondition) + /* 39 */ << H(TokBranch) + /* 40 */ /* then branch */ << I(1) + /* 42 */ << H(TokTerminator) + /* 43 */ /* else branch */ << I(0) + /* 45 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for-{next}") + << "for(ever) { next() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for:-{next}") + << "for(ever): { next() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-for-{test-else-test-newlines}") + << "true:for(VAR, LIST) {\ntrue\nelse: true\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(48) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(29) + /* 32 */ << H(TokLine) << H(2) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokBranch) + /* 44 */ /* then branch */ << I(0) + /* 46 */ /* else branch */ << I(12) + /* 48 */ << H(TokLine) << H(3) + /* 50 */ << H(TokHashLiteral) << HS(L"true") + /* 58 */ << H(TokCondition) + /* 59 */ << H(TokTerminator) + /* 60 */ << H(TokTerminator) + /* 61 */ << H(TokTerminator) + /* 62 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-for-{test-else-test}") + << "true:for(VAR, LIST) { true\nelse: true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(48) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(29) + /* 32 */ << H(TokLine) << H(1) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokBranch) + /* 44 */ /* then branch */ << I(0) + /* 46 */ /* else branch */ << I(12) + /* 48 */ << H(TokLine) << H(2) + /* 50 */ << H(TokHashLiteral) << HS(L"true") + /* 58 */ << H(TokCondition) + /* 59 */ << H(TokTerminator) + /* 60 */ << H(TokTerminator) + /* 61 */ << H(TokTerminator) + /* 62 */ /* else branch */ << I(0)) + << "" + << true; +} + +void tst_qmakelib::addParseCustomFunctions() +{ + QTest::newRow("defineTest-{newlines}") + << "defineTest(test) {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(1) + /* 12 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest:-test") + << "defineTest(test): test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(12) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest-{test}") + << "defineTest(test) { test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(12) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest-{return}") + << "defineTest(test) { return() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(4) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokReturn) + /* 15 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineReplace-{return-stuff}") + << "defineReplace(stuff) { return(foo bar) }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokReplaceDef) << HS(L"stuff") + /* 11 */ /* body */ << I(14) + /* 13 */ << H(TokLine) << H(1) + /* 15 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 20 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 25 */ << H(TokReturn) + /* 26 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-defineTest-{}") + << "test: defineTest(test) {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokTestDef) << HS(L"test") + /* 20 */ /* body */ << I(1) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-OR-defineTest-{}") + << "test| defineTest(test) {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokTestDef) << HS(L"test") + /* 20 */ /* body */ << I(1) + /* 22 */ << H(TokTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseAbuse() +{ + QTest::newRow("!") + << "" + << TS() + << "" + << true; + + QTest::newRow("|") + << "" + << TS() + << "" + << true; + + QTest::newRow(":") + << "" + << TS() + << "" + << true; + + QTest::newRow("NOT-assignment") + << "!VAR =" + << TS() + << "in:1: Unexpected NOT operator in front of assignment." + << false; + + QTest::newRow("NOT-{}") + << "!{}" + << TS() + << "in:1: Unexpected NOT operator in front of opening brace." + << false; + + QTest::newRow("NOT-else") + << "test\n!else {}" + << TS() + << "in:2: Unexpected NOT operator in front of else." + << false; + + QTest::newRow("NOT-for-{}") + << "!for(ever) {}" + << TS() + << "in:1: Unexpected NOT operator in front of for()." + << false; + + QTest::newRow("NOT-defineTest-{}") + << "!defineTest(test) {}" + << TS() + << "in:1: Unexpected NOT operator in front of function definition." + << false; + + QTest::newRow("AND-test") + << ":test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: AND operator without prior condition." + << false; + + QTest::newRow("test-AND-else") + << "test:else" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: Unexpected AND operator in front of else." + << false; + + QTest::newRow("test-AND-AND-test") + << "test::test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray AND operator in front of AND operator." + << true; + + QTest::newRow("test-AND-OR-test") + << "test:|test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray AND operator in front of OR operator." + << true; + + QTest::newRow("test-{AND-test}") + << "test { :test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "in:1: AND operator without prior condition." + << false; + + QTest::newRow("test-OR-assignment") + << "foo| VAR =" + << TS() + << "in:1: Unexpected OR operator in front of assignment." + << false; + + QTest::newRow("test-OR-{}") + << "foo|{}" + << TS() + << "in:1: Unexpected OR operator in front of opening brace." + << false; + + QTest::newRow("test-OR-for") + << "foo|for(ever) {}" + << TS() + << "in:1: Unexpected OR operator in front of for()." + << false; + + QTest::newRow("OR-test") + << "|test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: OR operator without prior condition." + << false; + + QTest::newRow("test-OR-else") + << "test|else" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: Unexpected OR operator in front of else." + << false; + + QTest::newRow("test-OR-OR-test") + << "test||test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray OR operator in front of OR operator." + << true; + + QTest::newRow("test-OR-AND-test") + << "test|:test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray OR operator in front of AND operator." + << true; + + QTest::newRow("test-{OR-test}") + << "test { |test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "in:1: OR operator without prior condition." + << false; +} + +void tst_qmakelib::proParser_data() +{ + QTest::addColumn<QString>("in"); + QTest::addColumn<QString>("out"); + QTest::addColumn<QString>("msgs"); + QTest::addColumn<bool>("ok"); + + QTest::newRow("empty") + << "" + << TS() + << "" + << true; + + QTest::newRow("empty (whitespace)") + << " \t \t" + << TS() + << "" + << true; + + addParseOperators(); // Variable operators + + addParseValues(); + + addParseConditions(); // "Tests" + + addParseControlStatements(); + + addParseBraces(); + + addParseCustomFunctions(); + + addParseAbuse(); // Mostly operator abuse + + // option() (these produce no tokens) + + QTest::newRow("option(host_build)") + << "option(host_build)" + << TS() + << "" + << true; + + QTest::newRow("option()") + << "option()" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option(host_build magic)") + << "option(host_build magic)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option(host_build, magic)") + << "option(host_build, magic)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option($$OPTION)") + << "option($$OPTION)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("{option(host_build)}") + << "{option(host_build)}" + << TS() + << "in:1: option() must appear outside any control structures." + << false; +} + +QT_WARNING_POP + +void tst_qmakelib::proParser() +{ + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, msgs); + QFETCH(bool, ok); + + bool verified = true; + QMakeTestHandler handler; + handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &handler); + ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); + if (handler.printedMessages()) { + qWarning("Got unexpected message(s)"); + verified = false; + } + QStringList missingMsgs = handler.expectedMessages(); + if (!missingMsgs.isEmpty()) { + foreach (const QString &msg, missingMsgs) + qWarning("Missing message: %s", qPrintable(msg)); + verified = false; + } + if (pro->isOk() != ok) { + static const char * const lbl[] = { "failure", "success" }; + qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); + verified = false; + } + if (pro->items() != out && (ok || !out.isEmpty())) { + qWarning("Bytecode mismatch.\nActual:%s\nExpected:%s", + qPrintable(QMakeParser::formatProBlock(pro->items())), + qPrintable(QMakeParser::formatProBlock(out))); + verified = false; + } + pro->deref(); + QVERIFY(verified); +} diff --git a/tests/auto/tools/qmakelib/qmakelib.pro b/tests/auto/tools/qmakelib/qmakelib.pro index e7807838aa..f1b8dfef3d 100644 --- a/tests/auto/tools/qmakelib/qmakelib.pro +++ b/tests/auto/tools/qmakelib/qmakelib.pro @@ -6,11 +6,19 @@ QT = core testlib INCLUDEPATH += ../../../../qmake/library VPATH += ../../../../qmake/library +HEADERS += \ + tst_qmakelib.h + SOURCES += \ tst_qmakelib.cpp \ + parsertest.cpp \ + evaltest.cpp \ ioutils.cpp \ proitems.cpp \ qmakevfs.cpp \ - qmakeparser.cpp + qmakeparser.cpp \ + qmakeglobals.cpp \ + qmakebuiltins.cpp \ + qmakeevaluator.cpp -DEFINES += PROPARSER_DEBUG +DEFINES += PROPARSER_DEBUG PROEVALUATOR_FULL PROEVALUATOR_SETENV diff --git a/tests/auto/tools/qmakelib/testdata/cat/file1.txt b/tests/auto/tools/qmakelib/testdata/cat/file1.txt new file mode 100644 index 0000000000..e3e4cd41b6 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/cat/file1.txt @@ -0,0 +1,2 @@ +"Hello, world." +foo bar baz diff --git a/tests/auto/tools/qmakelib/testdata/cat/file2.txt b/tests/auto/tools/qmakelib/testdata/cat/file2.txt new file mode 100644 index 0000000000..18483311e6 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/cat/file2.txt @@ -0,0 +1,5 @@ +foo bar baz +"Hello, ' world." post +'Hello, " world.' post +\" \' \\ \a \ nix +" " diff --git a/tests/auto/tools/qmakelib/testdata/files/dir/file1.txt b/tests/auto/tools/qmakelib/testdata/files/dir/file1.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/files/dir/file1.txt diff --git a/tests/auto/tools/qmakelib/testdata/files/dir/file2.txt b/tests/auto/tools/qmakelib/testdata/files/dir/file2.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/files/dir/file2.txt diff --git a/tests/auto/tools/qmakelib/testdata/files/file1.txt b/tests/auto/tools/qmakelib/testdata/files/file1.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/files/file1.txt diff --git a/tests/auto/tools/qmakelib/testdata/files/file2.txt b/tests/auto/tools/qmakelib/testdata/files/file2.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/files/file2.txt diff --git a/tests/auto/tools/qmakelib/testdata/files/other.txt b/tests/auto/tools/qmakelib/testdata/files/other.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/files/other.txt diff --git a/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx b/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx new file mode 100644 index 0000000000..a916f21587 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx @@ -0,0 +1 @@ +error("fail!") diff --git a/tests/auto/tools/qmake/testdata/functions/infiletest.pro b/tests/auto/tools/qmakelib/testdata/fromfile/infile.prx index 821cb5cb2c..821cb5cb2c 100644 --- a/tests/auto/tools/qmake/testdata/functions/infiletest.pro +++ b/tests/auto/tools/qmakelib/testdata/fromfile/infile.prx diff --git a/tests/auto/tools/qmakelib/testdata/include/inc.pri b/tests/auto/tools/qmakelib/testdata/include/inc.pri new file mode 100644 index 0000000000..1f1b3a287f --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/include/inc.pri @@ -0,0 +1,8 @@ +VAR = val +.VAR = nope + +fake-*: MATCH = 1 + +defineTest(func) { + message("say hi!") +} diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf b/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf new file mode 100644 index 0000000000..57c9a0d783 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf @@ -0,0 +1 @@ +VAR = foo bar diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.cpp b/tests/auto/tools/qmakelib/tst_qmakelib.cpp index 1c6d43338d..3da48815fb 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.cpp +++ b/tests/auto/tools/qmakelib/tst_qmakelib.cpp @@ -31,37 +31,112 @@ ** ****************************************************************************/ -#include <QtTest/QtTest> +#include "tst_qmakelib.h" #include <ioutils.h> -#include <proitems.h> -#include <qmakevfs.h> -#include <qmakeparser.h> - -#include <QObject> using namespace QMakeInternal; -class tst_qmakelib : public QObject +void tst_qmakelib::initTestCase() +{ + m_indir = QFINDTESTDATA("testdata"); + m_outdir = m_indir + QLatin1String("_build"); + m_env.insert(QStringLiteral("E1"), QStringLiteral("env var")); +#ifdef Q_OS_WIN + m_env.insert(QStringLiteral("COMSPEC"), qgetenv("COMSPEC")); +#endif + m_prop.insert(ProKey("P1"), ProString("prop val")); + m_prop.insert(ProKey("QT_HOST_DATA/get"), ProString(m_indir)); + + QVERIFY(!m_indir.isEmpty()); + QVERIFY(QDir(m_outdir).removeRecursively()); + QVERIFY(QDir().mkpath(m_outdir)); +} + +void tst_qmakelib::cleanupTestCase() { - Q_OBJECT + QVERIFY(QDir(m_outdir).removeRecursively()); +} + +void tst_qmakelib::proString() +{ + QString qs1(QStringLiteral("this is a string")); + + ProString s1(qs1); + QCOMPARE(s1.toQString(), QStringLiteral("this is a string")); + + ProString s2(qs1, 5, 8); + QCOMPARE(s2.toQString(), QStringLiteral("is a str")); + + QCOMPARE(s2.hash(), 0x80000000); + qHash(s2); + QCOMPARE(s2.hash(), 90404018U); -public: - tst_qmakelib() {} - virtual ~tst_qmakelib() {} + QCOMPARE(s2.mid(0, 10).toQString(), QStringLiteral("is a str")); + QCOMPARE(s2.mid(1, 5).toQString(), QStringLiteral("s a s")); + QCOMPARE(s2.mid(10, 3).toQString(), QStringLiteral("")); -private slots: - void quoteArgUnix_data(); - void quoteArgUnix(); - void quoteArgWin_data(); - void quoteArgWin(); - void pathUtils(); + QString qs2(QStringLiteral(" spacy string ")); + QCOMPARE(ProString(qs2, 3, 13).trimmed().toQString(), QStringLiteral("spacy string")); + QCOMPARE(ProString(qs2, 1, 17).trimmed().toQString(), QStringLiteral("spacy string")); - void proStringList(); + QVERIFY(s2.toQStringRef().string()->isSharedWith(qs1)); + s2.prepend(ProString("there ")); + QCOMPARE(s2.toQString(), QStringLiteral("there is a str")); + QVERIFY(!s2.toQStringRef().string()->isSharedWith(qs1)); - void proParser_data(); - void proParser(); -}; + ProString s3("this is a longish string with bells and whistles"); + s3 = s3.mid(18, 17); + // Prepend to detached string with lots of spare space in it. + s3.prepend(ProString("another ")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells")); + + // Note: The string still has plenty of spare space. + s3.append(QLatin1Char('.')); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells.")); + s3.append(QLatin1String(" eh?")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh?")); + + s3.append(ProString(" yeah!")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah!")); + + bool pending = false; // Not in string, but joining => add space + s3.append(ProString("..."), &pending); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah! ...")); + QVERIFY(pending); + + ProStringList sl1; + sl1 << ProString("") << ProString("foo") << ProString("barbaz"); + ProString s4a("hallo"); + s4a.append(sl1); + QCOMPARE(s4a.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4b("hallo"); + pending = false; + s4b.append(sl1, &pending); + QCOMPARE(s4b.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4c; + pending = false; + s4c.append(sl1, &pending); + QCOMPARE(s4c.toQString(), QStringLiteral(" foo barbaz")); + // bizarreness + ProString s4d("hallo"); + pending = false; + s4d.append(sl1, &pending, true); + QCOMPARE(s4d.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4e; + pending = false; + s4e.append(sl1, &pending, true); + QCOMPARE(s4e.toQString(), QStringLiteral("foo barbaz")); + + ProStringList sl2; + sl2 << ProString("foo"); + ProString s5; + s5.append(sl2); + QCOMPARE(s5.toQString(), QStringLiteral("foo")); + QVERIFY(s5.toQStringRef().string()->isSharedWith(*sl2.first().toQStringRef().string())); + + QCOMPARE(ProString("one") + ProString(" more"), QStringLiteral("one more")); +} void tst_qmakelib::proStringList() { @@ -171,1940 +246,24 @@ void tst_qmakelib::pathUtils() QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path")); } -class QMakeHandler : public QMakeParserHandler { -public: - QMakeHandler() : QMakeParserHandler(), printed(false) {} - virtual void message(int type, const QString &msg, const QString &fileName, int lineNo) - { print(fileName, lineNo, type, msg); } - - void setExpectedMessages(const QStringList &msgs) { expected = msgs; } - QStringList expectedMessages() const { return expected; } - - bool printedMessages() const { return printed; } - -private: - void print(const QString &fileName, int lineNo, int type, const QString &msg) - { - QString pfx = ((type & QMakeParserHandler::CategoryMask) == QMakeParserHandler::WarningMessage) - ? QString::fromLatin1("WARNING: ") : QString(); - QString out; - if (lineNo) - out = QStringLiteral("%1%2:%3: %4").arg(pfx, fileName, QString::number(lineNo), msg); - else - out = QStringLiteral("%1%2").arg(pfx, msg); - if (!expected.isEmpty() && expected.first() == out) { - expected.removeAt(0); - return; - } - qWarning("%s", qPrintable(out)); - printed = true; - } - - QStringList expected; - bool printed; -}; - -static QMakeHandler qmakeHandler; - -class TokenStream +void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg) { -public: - TokenStream() {} - QString toString() const { return ts; } - - TokenStream &operator<<(ushort n) { ts += QChar(n); return *this; } - TokenStream &operator<<(uint n) { ts += QChar(n & 0xffff); ts += QChar(n >> 16); return *this; } - TokenStream &operator<<(const QStringRef &s) { ts += s; return *this; } - TokenStream &operator<<(const ProString &s) { return *this << ushort(s.length()) << s.toQStringRef(); } - TokenStream &operator<<(const ProKey &s) { return *this << s.hash() << s.toString(); } - -private: - QString ts; -}; - -#define TS(s) (TokenStream() s).toString() -#define H(n) ushort(n) -#define I(n) uint(n) -#define S(s) ProString(QString::fromWCharArray(s)) -#define HS(s) ProKey(QString::fromWCharArray(s)) - -void tst_qmakelib::proParser_data() -{ - QTest::addColumn<QString>("in"); - QTest::addColumn<QString>("out"); - QTest::addColumn<QString>("msgs"); - QTest::addColumn<bool>("ok"); - - QTest::newRow("empty") - << "" - << TS() - << "" - << true; - - QTest::newRow("empty (whitespace)") - << " \t \t" - << TS() - << "" - << true; - - // Variable operators - - QTest::newRow("assign none") - << "VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("append none") - << "VAR +=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAppend) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("unique append none") - << "VAR *=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAppendUnique) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("remove none") - << "VAR -=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokRemove) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("replace empty") - << "VAR ~=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokReplace) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("assignment without variable") - << "=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokAssign) << H(0) - /* 4 */ << H(TokValueTerminator)) - << "in:1: Assignment needs exactly one word on the left hand side." - << false; - - QTest::newRow("assignment with multiple variables") - << "VAR VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokAssign) << H(0) - /* 4 */ << H(TokValueTerminator)) - << "in:1: Assignment needs exactly one word on the left hand side." - << false; - - // Values - -#define ASSIGN_VAR(h) \ - H(TokLine) << H(1) \ - << H(TokHashLiteral) << HS(L"VAR") \ - << H(TokAssign) << H(h) - - QTest::newRow("one literal") - << "VAR = val" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("one literal (squeezed)") - << "VAR=val" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many literals") - << "VAR = foo barbaz bak hello" - << TS( - /* 0 */ << ASSIGN_VAR(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") - /* 36 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many literals (tab-separated") - << "VAR\t=\tfoo\tbarbaz\tbak\thello" - << TS( - /* 0 */ << ASSIGN_VAR(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") - /* 36 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("one quoted literal") - << "VAR = \"val ue\"" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue") - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted literal with missing quote") - << "VAR = val \"ue" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "in:1: Missing closing \" quote" - << false; - - QTest::newRow("many quoted literals") - << "VAR = \"foo\" barbaz 'bak hello' \"\"" - << TS( - /* 0 */ << ASSIGN_VAR(3) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak hello") - /* 35 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many quoted literals (with tabs)") - << "VAR\t=\t\"foo\"\tbarbaz\t'bak\thello'" - << TS( - /* 0 */ << ASSIGN_VAR(3) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak\thello") - /* 35 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted and unquoted spaces") - << " VAR = \"val ue \" " - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue ") - /* 22 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("funny literals") - << "VAR = foo:bar|!baz(blam!, ${foo})" - << TS( - /* 0 */ << ASSIGN_VAR(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo:bar|!baz(blam!,") - /* 32 */ << H(TokLiteral | TokNewStr) << S(L"${foo})") - /* 41 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("literals with escapes") - << "VAR = \\{hi\\} \\[ho\\] \\)uh\\( \"\\\\oh\\$\"\\' \\$\\${FOO}" - << TS( - /* 0 */ << ASSIGN_VAR(5) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{hi}") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"[ho]") - /* 23 */ << H(TokLiteral | TokNewStr) << S(L")uh(") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"\\oh$'") - /* 36 */ << H(TokLiteral | TokNewStr) << S(L"$${FOO}") - /* 45 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("magic variables") - << "VAR = $$LITERAL_HASH $$LITERAL_DOLLAR $$LITERAL_WHITESPACE $$_FILE_ $$_LINE_" - << TS( - /* 0 */ << ASSIGN_VAR(5) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"#") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"$") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"\t") - /* 20 */ << H(TokLiteral | TokNewStr) << S(L"in") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"1") - /* 27 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("continuations and comments") - << "VAR = foo \\\n bar\n \n" - "GAR = foo \\ # comment\n bar \\\n # comment\n baz \\\n" - "\"quoted \\ #comment\n escape\" \\\n right\\\n after \\\n gorilla!\n \n\n" - "MOO = \\\n kuh # comment\nLOO =\n\n" - "FOO = bar \\\n# comment\n baz \\\n \n# comment\n" - "GAZ=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 21 */ << H(TokValueTerminator) - /* 22 */ << H(TokLine) << H(4) - /* 24 */ << H(TokHashLiteral) << HS(L"GAR") - /* 31 */ << H(TokAssign) << H(7) - /* 33 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 38 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 43 */ << H(TokLiteral | TokNewStr) << S(L"baz") - /* 48 */ << H(TokLiteral | TokNewStr) << S(L"quoted escape") - /* 64 */ << H(TokLiteral | TokNewStr) << S(L"right") - /* 71 */ << H(TokLiteral | TokNewStr) << S(L"after") - /* 78 */ << H(TokLiteral | TokNewStr) << S(L"gorilla!") - /* 88 */ << H(TokValueTerminator) - /* 89 */ << H(TokLine) << H(15) - /* 91 */ << H(TokHashLiteral) << HS(L"MOO") - /* 98 */ << H(TokAssign) << H(0) - /* 100 */ << H(TokLiteral | TokNewStr) << S(L"kuh") - /* 105 */ << H(TokValueTerminator) - /* 106 */ << H(TokLine) << H(17) - /* 108 */ << H(TokHashLiteral) << HS(L"LOO") - /* 115 */ << H(TokAssign) << H(0) - /* 117 */ << H(TokValueTerminator) - /* 118 */ << H(TokLine) << H(19) - /* 120 */ << H(TokHashLiteral) << HS(L"FOO") - /* 127 */ << H(TokAssign) << H(2) - /* 129 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 134 */ << H(TokLiteral | TokNewStr) << S(L"baz") - /* 139 */ << H(TokValueTerminator) - /* 140 */ << H(TokLine) << H(24) - /* 142 */ << H(TokHashLiteral) << HS(L"GAZ") - /* 149 */ << H(TokAssign) << H(0) - /* 151 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("accidental continuation") - << "VAR0 = \\\n this \\\n is \\\n ok\n" - "VAR1 = \\\n this \\\n is=still \\\n ok\n" - "VAR2 = \\\n this \\\n is \\\n" - "VAR3 = \\\n not ok\n" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR0") - /* 10 */ << H(TokAssign) << H(3) - /* 12 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"is") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 26 */ << H(TokValueTerminator) - /* 27 */ << H(TokLine) << H(5) - /* 29 */ << H(TokHashLiteral) << HS(L"VAR1") - /* 37 */ << H(TokAssign) << H(3) - /* 39 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 45 */ << H(TokLiteral | TokNewStr) << S(L"is=still") - /* 55 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 59 */ << H(TokValueTerminator) - /* 60 */ << H(TokLine) << H(9) - /* 62 */ << H(TokHashLiteral) << HS(L"VAR2") - /* 70 */ << H(TokAssign) << H(6) - /* 72 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 78 */ << H(TokLiteral | TokNewStr) << S(L"is") - /* 82 */ << H(TokLiteral | TokNewStr) << S(L"VAR3") - /* 88 */ << H(TokLiteral | TokNewStr) << S(L"=") - /* 91 */ << H(TokLiteral | TokNewStr) << S(L"not") - /* 96 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 100 */ << H(TokValueTerminator)) - << "WARNING: in:12: Possible accidental line continuation" - << true; - - QTest::newRow("plain variable expansion") - << "VAR = $$bar" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced variable expansion") - << "VAR = $${foo/bar}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"foo/bar") - /* 22 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("bogus variable expansion") - << "VAR = $$ " - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") - /* 15 */ << H(TokValueTerminator)) - << "WARNING: in:1: Missing name in expansion" - << true; - - QTest::newRow("bogus braced variable expansion") - << "VAR = $${}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") - /* 15 */ << H(TokValueTerminator)) - << "WARNING: in:1: Missing name in expansion" - << true; - - QTest::newRow("unterminated braced variable expansion") - << "VAR = $${FOO" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO") - /* 18 */ << H(TokValueTerminator)) - << "in:1: Missing } terminator [found end-of-line]" - << false; - - QTest::newRow("invalid identifier in braced variable expansion") - << "VAR = $${FOO/BAR+BAZ}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO/BAR") - /* 22 */ << H(TokLiteral) << S(L"+BAZ") - /* 28 */ << H(TokValueTerminator)) - << "in:1: Missing } terminator [found +]" - << false; - - QTest::newRow("property expansion") - << "VAR = $$[bar]" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokProperty | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("environment expansion") - << "VAR = $$(bar)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokEnvVar | TokNewStr) << S(L"bar") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("plain function call") - << "VAR = $$bar()" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokFuncTerminator) - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced function call") - << "VAR = $${bar()}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokFuncTerminator) - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("function call with one argument") - << "VAR = $$bar(blubb)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokFuncTerminator) - /* 26 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("function call with multiple arguments") - << "VAR = $$bar( blubb blubb, hey ,$$you)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 32 */ << H(TokArgSeparator) - /* 33 */ << H(TokLiteral | TokNewStr) << S(L"hey") - /* 38 */ << H(TokArgSeparator) - /* 39 */ << H(TokVariable | TokNewStr) << HS(L"you") - /* 46 */ << H(TokFuncTerminator) - /* 47 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("nested function call") - << "VAR = $$foo(yo, $$bar(blubb))" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"foo") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"yo") - /* 22 */ << H(TokArgSeparator) - /* 23 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 30 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 37 */ << H(TokFuncTerminator) - /* 38 */ << H(TokFuncTerminator) - /* 39 */ << H(TokValueTerminator)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("function call with parenthesized argument") - << "VAR = $$bar(blubb (yo, man) blabb, nope)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"(yo,") - /* 31 */ << H(TokLiteral | TokNewStr) << S(L"man)") - /* 37 */ << H(TokLiteral | TokNewStr) << S(L"blabb") - /* 44 */ << H(TokArgSeparator) - /* 45 */ << H(TokLiteral | TokNewStr) << S(L"nope") - /* 51 */ << H(TokFuncTerminator) - /* 52 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("separate literal and expansion") - << "VAR = foo $$bar" - << TS( - /* 0 */ << ASSIGN_VAR(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("separate expansion and literal") - << "VAR = $$bar foo" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("joined literal and expansion") - << "VAR = foo$$bar" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("joined expansion and literal") - << "VAR = $${bar}foo" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral) << S(L"foo") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("plain variable expansion with funny name and literal") - << "VAR = $$az_AZ_09.dot/nix" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot") - /* 27 */ << H(TokLiteral) << S(L"/nix") - /* 33 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced variable expansion with funny name") - << "VAR = $${az_AZ_09.dot/nix}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot/nix") - /* 31 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted joined literal and expansion") - << "VAR = 'foo$$bar'" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable | TokQuoted) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("assignment with expansion in variable name") - << "VAR$$EXTRA =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokVariable) << HS(L"EXTRA") - /* 18 */ << H(TokAssign) << H(0) - /* 20 */ << H(TokValueTerminator)) - << "" - << true; - - // Conditionals ("Tests") - - QTest::newRow("one test") - << "foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("wildcard-test") - << "foo-*" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo-*") - /* 11 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("one quoted test") - << "\"foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("two tests") - << "foo\nbar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokLine) << H(2) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("bogus two tests") - << "foo bar\nbaz" - << TS() - << "in:1: Extra characters after test expression." - << false; - - QTest::newRow("test-AND-test") - << "foo:bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-OR-test") - << " foo | bar " - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokOr) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("NOT-test") - << "!foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("NOT-NOT-test") - << "!!foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("quoted-NOT-test") - << "\"!foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("NOT-quoted-test") - << "!\"foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-NOT-test") - << "foo:!bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokNot) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-assignment") - << "foo\nVAR=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokLine) << H(2) - /* 12 */ << H(TokHashLiteral) << HS(L"VAR") - /* 19 */ << H(TokAssign) << H(0) - /* 21 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("test-AND-assignment") - << "foo: VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(11) - /* 13 */ << H(TokHashLiteral) << HS(L"VAR") - /* 20 */ << H(TokAssign) << H(0) - /* 22 */ << H(TokValueTerminator) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-else-test") - << "foo\nelse: bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(0) - /* 13 */ /* else branch */ << I(11) - /* 15 */ << H(TokLine) << H(2) - /* 17 */ << H(TokHashLiteral) << HS(L"bar") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("function-else-test") - << "foo()\nelse: bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(0) - /* 14 */ /* else branch */ << I(11) - /* 16 */ << H(TokLine) << H(2) - /* 18 */ << H(TokHashLiteral) << HS(L"bar") - /* 25 */ << H(TokCondition) - /* 26 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-test-else-test") - << "foo:bar\nelse: baz" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition) - /* 19 */ << H(TokBranch) - /* 20 */ /* then branch */ << I(0) - /* 22 */ /* else branch */ << I(11) - /* 24 */ << H(TokLine) << H(2) - /* 26 */ << H(TokHashLiteral) << HS(L"baz") - /* 33 */ << H(TokCondition) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-test-else-test-else-test-function") - << "foo:bar\nelse: baz\nelse: bak\nbuzz()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition) - /* 19 */ << H(TokBranch) - /* 20 */ /* then branch */ << I(0) - /* 22 */ /* else branch */ << I(27) - /* 24 */ << H(TokLine) << H(2) - /* 26 */ << H(TokHashLiteral) << HS(L"baz") - /* 33 */ << H(TokCondition) - /* 34 */ << H(TokBranch) - /* 35 */ /* then branch */ << I(0) - /* 37 */ /* else branch */ << I(11) - /* 39 */ << H(TokLine) << H(3) - /* 41 */ << H(TokHashLiteral) << HS(L"bak") - /* 48 */ << H(TokCondition) - /* 49 */ << H(TokTerminator) - /* 50 */ << H(TokTerminator) - /* 51 */ << H(TokLine) << H(4) - /* 53 */ << H(TokHashLiteral) << HS(L"buzz") - /* 61 */ << H(TokTestCall) - /* 62 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("test-assignment-else-assignment") - << "foo: VAR =\nelse: VAR=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(11) - /* 13 */ << H(TokHashLiteral) << HS(L"VAR") - /* 20 */ << H(TokAssign) << H(0) - /* 22 */ << H(TokValueTerminator) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(13) - /* 26 */ << H(TokLine) << H(2) - /* 28 */ << H(TokHashLiteral) << HS(L"VAR") - /* 35 */ << H(TokAssign) << H(0) - /* 37 */ << H(TokValueTerminator) - /* 38 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-else-test-assignment") - << "foo\nelse: bar: VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(0) - /* 13 */ /* else branch */ << I(27) - /* 15 */ << H(TokLine) << H(2) - /* 17 */ << H(TokHashLiteral) << HS(L"bar") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokBranch) - /* 26 */ /* then branch */ << I(11) - /* 28 */ << H(TokHashLiteral) << HS(L"VAR") - /* 35 */ << H(TokAssign) << H(0) - /* 37 */ << H(TokValueTerminator) - /* 38 */ << H(TokTerminator) - /* 39 */ /* else branch */ << I(0) - /* 41 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("one function") - << "foo()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("one function (with spaces)") - << " foo( ) " - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("unterminated function call") - << "foo(\nfoo" - << TS() - << "in:1: Missing closing parenthesis in function call" - << false; - - QTest::newRow("function with arguments") - << "foo(blah, hi ho)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah") - /* 16 */ << H(TokArgSeparator) - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"hi") - /* 21 */ << H(TokLiteral | TokNewStr) << S(L"ho") - /* 25 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function with empty arguments") - << "foo(,)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokArgSeparator) - /* 11 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function with funny arguments") - << "foo(blah\\, \"hi , \\ho\" ,uh\\ ,\\oh ,, )" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah\\") - /* 17 */ << H(TokArgSeparator) - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi , \\ho") - /* 29 */ << H(TokArgSeparator) - /* 30 */ << H(TokLiteral | TokNewStr) << S(L"uh\\") - /* 35 */ << H(TokArgSeparator) - /* 36 */ << H(TokLiteral | TokNewStr) << S(L"\\oh") - /* 41 */ << H(TokArgSeparator) - /* 42 */ << H(TokArgSeparator) - /* 43 */ << H(TokFuncTerminator)) - << "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated" - << true; - - QTest::newRow("function with nested call") - << "foo($$blah(hi ho))" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncName | TokNewStr) << HS(L"blah") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ho") - /* 26 */ << H(TokFuncTerminator) - /* 27 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("stand-alone parentheses") - << "()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestCall) - /* 3 */ << H(TokFuncTerminator)) - << "in:1: Opening parenthesis without prior test name." - << false; - - QTest::newRow("bogus test and function") - << "foo bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestCall) - /* 3 */ << H(TokFuncTerminator)) - << "in:1: Extra characters after test expression." - << false; - - // This is a rather questionable "feature" - QTest::newRow("two functions") - << "foo() bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokTestCall) - /* 19 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function-AND-test") - << "foo():bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-function") - << "foo:bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokTestCall) - /* 19 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("NOT-function-AND-test") - << "!foo():bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokTestCall) - /* 11 */ << H(TokFuncTerminator) - /* 12 */ << H(TokAnd) - /* 13 */ << H(TokHashLiteral) << HS(L"bar") - /* 20 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-NOT-function") - << "foo:!bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokNot) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokTestCall) - /* 20 */ << H(TokFuncTerminator)) - << "" - << true; - - // Control statements - - QTest::newRow("for(VAR, LIST) loop") - << "for(VAR, LIST)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"VAR") - /* 9 */ /* iterator */ << I(7) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 17 */ << H(TokValueTerminator) - /* 18 */ /* body */ << I(1) - /* 20 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for(ever) loop") - << "for(ever)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("for($$blub) loop") - << "for($$blub)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokVariable | TokNewStr) << HS(L"blub") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-for-test-else-test") - << "true:for(VAR, LIST): true\nelse: true" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(31) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(12) - /* 32 */ << H(TokLine) << H(1) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokTerminator) - /* 44 */ << H(TokTerminator) - /* 45 */ /* else branch */ << I(12) - /* 47 */ << H(TokLine) << H(2) - /* 49 */ << H(TokHashLiteral) << HS(L"true") - /* 57 */ << H(TokCondition) - /* 58 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("next()") - << "for(ever): next()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("break()") - << "for(ever): break()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokBreak) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("top-level return()") - << "return()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokReturn)) - << "" - << true; - - QTest::newRow("else") - << "else" - << TS() - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("test-{else}") - << "test { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("defineTest-{else}") - << "defineTest(fn) { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"fn") - /* 8 */ /* body */ << I(1) - /* 10 */ << H(TokTerminator)) - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("for-else") - << "for(ever) { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "in:1: Unexpected 'else'." - << false; - - // Braces - - QTest::newRow("{}") - << "{ }" - << TS() - << "" - << true; - - QTest::newRow("{}-newlines") - << "\n\n{ }\n\n" - << TS() - << "" - << true; - - QTest::newRow("{") - << "{" - << TS() - << "in:2: Missing closing brace(s)." - << false; - - QTest::newRow("test {") - << "test {" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "in:2: Missing closing brace(s)." - << false; - - QTest::newRow("}") - << "}" - << TS() - << "in:1: Excess closing brace." - << false; - - QTest::newRow("{test}") - << "{ true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("{test-newlines}") - << "{\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(2) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("{assignment-test}-test") - << "{ VAR = { foo } bar } true" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 19 */ << H(TokLiteral | TokNewStr) << S(L"}") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 27 */ << H(TokValueTerminator) - /* 28 */ << H(TokHashLiteral) << HS(L"true") - /* 36 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("assignment with excess opening brace") - << "VAR = { { foo }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"}") - /* 25 */ << H(TokValueTerminator)) - << "WARNING: in:1: Possible braces mismatch" - << true; - - QTest::newRow("test-{}") - << "true {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{newlines}") - << "true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{test}") - << "true { true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test:-{test}") - << "true: { true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-{test-newlines}") - << "true {\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test:-{test-newlines}") - << "true: {\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(0)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-{assignment}") - << "true { VAR = {foo} }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(18) - /* 14 */ << H(TokHashLiteral) << HS(L"VAR") - /* 21 */ << H(TokAssign) << H(0) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 30 */ << H(TokValueTerminator) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{test-assignment}") - << "true { true: VAR = {foo} }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(33) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokBranch) - /* 24 */ /* then branch */ << I(18) - /* 26 */ << H(TokHashLiteral) << HS(L"VAR") - /* 33 */ << H(TokAssign) << H(0) - /* 35 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 42 */ << H(TokValueTerminator) - /* 43 */ << H(TokTerminator) - /* 44 */ /* else branch */ << I(0) - /* 46 */ << H(TokTerminator) - /* 47 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{assignment-newlines}") - << "true {\nVAR = {foo}\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(20) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"VAR") - /* 23 */ << H(TokAssign) << H(0) - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 32 */ << H(TokValueTerminator) - /* 33 */ << H(TokTerminator) - /* 34 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{}-else-test-{}") - << "true {} else: true {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(18) - /* 17 */ << H(TokLine) << H(1) - /* 19 */ << H(TokHashLiteral) << HS(L"true") - /* 27 */ << H(TokCondition) - /* 28 */ << H(TokBranch) - /* 29 */ /* then branch */ << I(1) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-{}-else-test-{}-newlines") - << "true {\n}\nelse: true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(18) - /* 17 */ << H(TokLine) << H(3) - /* 19 */ << H(TokHashLiteral) << HS(L"true") - /* 27 */ << H(TokCondition) - /* 28 */ << H(TokBranch) - /* 29 */ /* then branch */ << I(1) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-{test}-else-test-{}-newlines") - << "true {\ntrue\n}\nelse: true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(18) - /* 28 */ << H(TokLine) << H(4) - /* 30 */ << H(TokHashLiteral) << HS(L"true") - /* 38 */ << H(TokCondition) - /* 39 */ << H(TokBranch) - /* 40 */ /* then branch */ << I(1) - /* 42 */ << H(TokTerminator) - /* 43 */ /* else branch */ << I(0) - /* 45 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for-{next}") - << "for(ever) { next() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for:-{next}") - << "for(ever): { next() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-for-{test-else-test-newlines}") - << "true:for(VAR, LIST) {\ntrue\nelse: true\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(48) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(29) - /* 32 */ << H(TokLine) << H(2) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokBranch) - /* 44 */ /* then branch */ << I(0) - /* 46 */ /* else branch */ << I(12) - /* 48 */ << H(TokLine) << H(3) - /* 50 */ << H(TokHashLiteral) << HS(L"true") - /* 58 */ << H(TokCondition) - /* 59 */ << H(TokTerminator) - /* 60 */ << H(TokTerminator) - /* 61 */ << H(TokTerminator) - /* 62 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-for-{test-else-test}") - << "true:for(VAR, LIST) { true\nelse: true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(48) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(29) - /* 32 */ << H(TokLine) << H(1) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokBranch) - /* 44 */ /* then branch */ << I(0) - /* 46 */ /* else branch */ << I(12) - /* 48 */ << H(TokLine) << H(2) - /* 50 */ << H(TokHashLiteral) << HS(L"true") - /* 58 */ << H(TokCondition) - /* 59 */ << H(TokTerminator) - /* 60 */ << H(TokTerminator) - /* 61 */ << H(TokTerminator) - /* 62 */ /* else branch */ << I(0)) - << "" - << true; - - // Custom functions - - QTest::newRow("defineTest-{newlines}") - << "defineTest(test) {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(1) - /* 12 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest:-test") - << "defineTest(test): test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(12) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest-{test}") - << "defineTest(test) { test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(12) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest-{return}") - << "defineTest(test) { return() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(4) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokReturn) - /* 15 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineReplace-{return-stuff}") - << "defineReplace(stuff) { return(foo bar) }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokReplaceDef) << HS(L"stuff") - /* 11 */ /* body */ << I(14) - /* 13 */ << H(TokLine) << H(1) - /* 15 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 20 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 25 */ << H(TokReturn) - /* 26 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-defineTest-{}") - << "test: defineTest(test) {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokTestDef) << HS(L"test") - /* 20 */ /* body */ << I(1) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-OR-defineTest-{}") - << "test| defineTest(test) {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokTestDef) << HS(L"test") - /* 20 */ /* body */ << I(1) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - // Operator abuse - - QTest::newRow("!") - << "" - << TS() - << "" - << true; - - QTest::newRow("|") - << "" - << TS() - << "" - << true; - - QTest::newRow(":") - << "" - << TS() - << "" - << true; - - QTest::newRow("NOT-assignment") - << "!VAR =" - << TS() - << "in:1: Unexpected NOT operator in front of assignment." - << false; - - QTest::newRow("NOT-{}") - << "!{}" - << TS() - << "in:1: Unexpected NOT operator in front of opening brace." - << false; - - QTest::newRow("NOT-else") - << "test\n!else {}" - << TS() - << "in:2: Unexpected NOT operator in front of else." - << false; - - QTest::newRow("NOT-for-{}") - << "!for(ever) {}" - << TS() - << "in:1: Unexpected NOT operator in front of for()." - << false; - - QTest::newRow("NOT-defineTest-{}") - << "!defineTest(test) {}" - << TS() - << "in:1: Unexpected NOT operator in front of function definition." - << false; - - QTest::newRow("AND-test") - << ":test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: AND operator without prior condition." - << false; - - QTest::newRow("test-AND-else") - << "test:else" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: Unexpected AND operator in front of else." - << false; - - QTest::newRow("test-AND-AND-test") - << "test::test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray AND operator in front of AND operator." - << true; - - QTest::newRow("test-AND-OR-test") - << "test:|test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray AND operator in front of OR operator." - << true; - - QTest::newRow("test-{AND-test}") - << "test { :test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "in:1: AND operator without prior condition." - << false; - - QTest::newRow("test-OR-assignment") - << "foo| VAR =" - << TS() - << "in:1: Unexpected OR operator in front of assignment." - << false; - - QTest::newRow("test-OR-{}") - << "foo|{}" - << TS() - << "in:1: Unexpected OR operator in front of opening brace." - << false; - - QTest::newRow("test-OR-for") - << "foo|for(ever) {}" - << TS() - << "in:1: Unexpected OR operator in front of for()." - << false; - - QTest::newRow("OR-test") - << "|test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: OR operator without prior condition." - << false; - - QTest::newRow("test-OR-else") - << "test|else" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: Unexpected OR operator in front of else." - << false; - - QTest::newRow("test-OR-OR-test") - << "test||test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray OR operator in front of OR operator." - << true; - - QTest::newRow("test-OR-AND-test") - << "test|:test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray OR operator in front of AND operator." - << true; - - QTest::newRow("test-{OR-test}") - << "test { |test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "in:1: OR operator without prior condition." - << false; - - // option() (these produce no tokens) - - QTest::newRow("option(host_build)") - << "option(host_build)" - << TS() - << "" - << true; - - QTest::newRow("option()") - << "option()" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option(host_build magic)") - << "option(host_build magic)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option(host_build, magic)") - << "option(host_build, magic)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option($$OPTION)") - << "option($$OPTION)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("{option(host_build)}") - << "{option(host_build)}" - << TS() - << "in:1: option() must appear outside any control structures." - << false; + QString pfx = ((type & QMakeParserHandler::CategoryMask) == QMakeParserHandler::WarningMessage) + ? QString::fromLatin1("WARNING: ") : QString(); + if (lineNo) + doPrint(QStringLiteral("%1%2:%3: %4").arg(pfx, fileName, QString::number(lineNo), msg)); + else + doPrint(QStringLiteral("%1%2").arg(pfx, msg)); } -void tst_qmakelib::proParser() +void QMakeTestHandler::doPrint(const QString &msg) { - QFETCH(QString, in); - QFETCH(QString, out); - QFETCH(QString, msgs); - QFETCH(bool, ok); - - bool verified = true; - QMakeHandler handler; - handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); - QMakeVfs vfs; - QMakeParser parser(0, &vfs, &handler); - ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); - if (handler.printedMessages()) { - qWarning("Got unexpected message(s)"); - verified = false; - } - QStringList missingMsgs = handler.expectedMessages(); - if (!missingMsgs.isEmpty()) { - foreach (const QString &msg, missingMsgs) - qWarning("Missing message: %s", qPrintable(msg)); - verified = false; - } - if (pro->isOk() != ok) { - static const char * const lbl[] = { "failure", "success" }; - qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); - verified = false; - } - if (pro->items() != out && (ok || !out.isEmpty())) { - qWarning("Bytecode mismatch.\nActual:%s\nExpected:%s", - qPrintable(QMakeParser::formatProBlock(pro->items())), - qPrintable(QMakeParser::formatProBlock(out))); - verified = false; + if (!expected.isEmpty() && expected.first() == msg) { + expected.removeAt(0); + } else { + qWarning("%s", qPrintable(msg)); + printed = true; } - pro->deref(); - QVERIFY(verified); } QTEST_MAIN(tst_qmakelib) -#include "tst_qmakelib.moc" diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.h b/tests/auto/tools/qmakelib/tst_qmakelib.h new file mode 100644 index 0000000000..c4716ca65e --- /dev/null +++ b/tests/auto/tools/qmakelib/tst_qmakelib.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmakeevaluator.h> + +#include <QObject> +#include <QProcessEnvironment> +#include <QtTest/QtTest> + +class tst_qmakelib : public QObject +{ + Q_OBJECT + +public: + tst_qmakelib() {} + virtual ~tst_qmakelib() {} + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void quoteArgUnix_data(); + void quoteArgUnix(); + void quoteArgWin_data(); + void quoteArgWin(); + void pathUtils(); + + void proString(); + void proStringList(); + + void proParser_data(); + void proParser(); + + void proEval_data(); + void proEval(); + +private: + void addParseOperators(); + void addParseValues(); + void addParseConditions(); + void addParseControlStatements(); + void addParseBraces(); + void addParseCustomFunctions(); + void addParseAbuse(); + + void addAssignments(); + void addExpansions(); + void addControlStructs(); + void addReplaceFunctions(const QString &qindir); + void addTestFunctions(const QString &qindir); + + QProcessEnvironment m_env; + QHash<ProKey, ProString> m_prop; + QString m_indir, m_outdir; +}; + +class QMakeTestHandler : public QMakeHandler { +public: + QMakeTestHandler() : QMakeHandler(), printed(false) {} + virtual void message(int type, const QString &msg, const QString &fileName, int lineNo) + { print(fileName, lineNo, type, msg); } + + virtual void fileMessage(const QString &msg) + { doPrint(msg); } + + virtual void aboutToEval(ProFile *, ProFile *, EvalFileType) {} + virtual void doneWithEval(ProFile *) {} + + void setExpectedMessages(const QStringList &msgs) { expected = msgs; } + QStringList expectedMessages() const { return expected; } + + bool printedMessages() const { return printed; } + +private: + void print(const QString &fileName, int lineNo, int type, const QString &msg); + void doPrint(const QString &msg); + + QStringList expected; + bool printed; +}; + diff --git a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp index fecc14f541..e62ce3ceb5 100644 --- a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp +++ b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp @@ -564,6 +564,11 @@ void tst_QDialog::snapToDefaultButton() topLeftPos = QPoint(topLeftPos.x() + 100, topLeftPos.y() + 100); QPoint startingPos(topLeftPos.x() + 250, topLeftPos.y() + 250); QCursor::setPos(startingPos); +#ifdef Q_OS_OSX + // On OS X we use CGEventPost to move the cursor, it needs at least + // some time before the event handled and the position really set. + QTest::qWait(100); +#endif QCOMPARE(QCursor::pos(), startingPos); QDialog dialog; QPushButton *button = new QPushButton(&dialog); diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp index da0c5532a5..9b92c34fb5 100644 --- a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp @@ -179,6 +179,7 @@ private slots: void task250119_shortcutContext(); void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems(); void QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems(); + void QTBUG_45867_send_itemChildAddedChange_to_parent(); }; @@ -3490,5 +3491,36 @@ void tst_QGraphicsWidget::QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems() //This should not crash } +void tst_QGraphicsWidget::QTBUG_45867_send_itemChildAddedChange_to_parent() +{ + class GraphicsItem : public QGraphicsItem + { + public: + int m_itemChildAddedChangeNotificationsCount; + + GraphicsItem() + : QGraphicsItem(), + m_itemChildAddedChangeNotificationsCount(0) + { + } + + QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(); } + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE {} + + protected: + QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) Q_DECL_OVERRIDE + { + if (change == QGraphicsItem::ItemChildAddedChange) + ++m_itemChildAddedChangeNotificationsCount; + return QGraphicsItem::itemChange(change, value); + } + }; + + GraphicsItem item; + QGraphicsWidget widget(&item); + QCOMPARE(item.m_itemChildAddedChangeNotificationsCount, 1); +} + QTEST_MAIN(tst_QGraphicsWidget) #include "tst_qgraphicswidget.moc" diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp index 22245707cc..9b8b306e00 100644 --- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp +++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp @@ -48,6 +48,7 @@ #include <QtWidgets/QScrollBar> #include <QtWidgets/QDialog> #include <QtWidgets/QStyledItemDelegate> +#include <QtWidgets/QStyleFactory> #if defined(Q_OS_WIN) || defined(Q_OS_WINCE) # include <windows.h> @@ -2350,11 +2351,34 @@ void tst_QListView::testViewOptions() QCOMPARE(options.decorationPosition, QStyleOptionViewItem::Top); } +// make sure we have no transient scroll bars +class TempStyleSetter +{ +public: + TempStyleSetter() + : m_oldStyle(qApp->style()) + { + m_oldStyle->setParent(0); + QListView tempView; + if (QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, tempView.horizontalScrollBar())) + QApplication::setStyle(QStyleFactory::create("Fusion")); + } + + ~TempStyleSetter() + { + QApplication::setStyle(m_oldStyle); + } +private: + QStyle* m_oldStyle; +}; + void tst_QListView::taskQTBUG_39902_mutualScrollBars() { QWidget window; window.resize(400, 300); QListView *view = new QListView(&window); + // make sure we have no transient scroll bars + TempStyleSetter styleSetter; QStandardItemModel model(200, 1); const QSize itemSize(100, 20); for (int i = 0; i < model.rowCount(); ++i) @@ -2372,6 +2396,44 @@ void tst_QListView::taskQTBUG_39902_mutualScrollBars() view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); // this will end up in a stack overflow, if QTBUG-39902 is not fixed QTest::qWait(100); + + // these tests do not apply with transient scroll bars enabled + QVERIFY (!view->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, view->horizontalScrollBar())); + + // make it double as large, no scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) * 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // make it half the size, both scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) / 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) / 2); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // make it double as large, no scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) * 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // now, coming from the double size, resize it to the exactly matching size, still no scroll bars should be visible again + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // now remove just one single pixel in height -> both scroll bars will show up since they depend on each other + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2 - 1); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // now remove just one single pixel in with -> both scroll bars will show up since they depend on each other + view->resize(itemSize.width() + view->frameWidth() * 2 - 1, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // finally, coming from a size being to small, resize back to the exactly matching size -> both scroll bars should disappear again + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); } void tst_QListView::horizontalScrollingByVerticalWheelEvents() diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 6786ae9aa2..dcbdbe824a 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -605,21 +605,21 @@ void tst_QListWidget::insertItems() void tst_QListWidget::itemAssignment() { QListWidgetItem itemInWidget("inWidget", testWidget); - itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate); + itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate); QListWidgetItem itemOutsideWidget("outsideWidget"); QVERIFY(itemInWidget.listWidget()); QCOMPARE(itemInWidget.text(), QString("inWidget")); - QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate); QVERIFY(!itemOutsideWidget.listWidget()); QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget")); - QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate)); + QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate)); itemOutsideWidget = itemInWidget; QVERIFY(!itemOutsideWidget.listWidget()); QCOMPARE(itemOutsideWidget.text(), QString("inWidget")); - QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate); } void tst_QListWidget::item_data() diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index a4c6e13979..36bc23910c 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -281,21 +281,21 @@ void tst_QTableWidget::itemAssignment() { QTableWidgetItem itemInWidget("inWidget"); testWidget->setItem(0, 0, &itemInWidget); - itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate); + itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate); QTableWidgetItem itemOutsideWidget("outsideWidget"); QVERIFY(itemInWidget.tableWidget()); QCOMPARE(itemInWidget.text(), QString("inWidget")); - QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate); QVERIFY(!itemOutsideWidget.tableWidget()); QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget")); - QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate)); + QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate)); itemOutsideWidget = itemInWidget; QVERIFY(!itemOutsideWidget.tableWidget()); QCOMPARE(itemOutsideWidget.text(), QString("inWidget")); - QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate); } void tst_QTableWidget::item_data() diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 3ead172d82..1324027af6 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -255,6 +255,7 @@ private slots: void taskQTBUG_8176_emitOnExpandAll(); void taskQTBUG_34717_collapseAtBottom(); void taskQTBUG_37813_crash(); + void taskQTBUG_45697_crash(); void testInitialFocus(); }; @@ -4385,5 +4386,82 @@ void tst_QTreeView::taskQTBUG_37813_crash() #endif // QT_BUILD_INTERNAL } +// QTBUG-45697: Using a QTreeView with a multi-column model filtered by QSortFilterProxyModel, +// when sorting the source model while the widget is not yet visible and showing the widget +// later on, corruption occurs in QTreeView. +class Qtbug45697TestWidget : public QWidget +{ + Q_OBJECT +public: + static const int columnCount = 3; + + explicit Qtbug45697TestWidget(); + int timerTick() const { return m_timerTick; } + +public slots: + void slotTimer(); + +private: + QTreeView *m_treeView; + QStandardItemModel *m_model; + QSortFilterProxyModel *m_sortFilterProxyModel; + int m_timerTick; +}; + +Qtbug45697TestWidget::Qtbug45697TestWidget() + : m_treeView(new QTreeView(this)) + , m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this)) + , m_sortFilterProxyModel(new QSortFilterProxyModel(this)) + , m_timerTick(0) + { + QVBoxLayout *vBoxLayout = new QVBoxLayout(this); + vBoxLayout->addWidget(m_treeView); + + for (char sortChar = 'z'; sortChar >= 'a' ; --sortChar) { + QList<QStandardItem *> items; + for (int column = 0; column < Qtbug45697TestWidget::columnCount; ++column) { + const QString text = QLatin1Char(sortChar) + QLatin1String(" ") + QString::number(column); + items.append(new QStandardItem(text)); + } + m_model->appendRow(items); + } + + m_sortFilterProxyModel->setSourceModel(m_model); + m_treeView->setModel(m_sortFilterProxyModel); + + QHeaderView *headerView = m_treeView->header(); + for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s ) + headerView->setSectionResizeMode(s, QHeaderView::ResizeToContents); + + QTimer *timer = new QTimer(this); + timer->setInterval(50); + connect(timer, &QTimer::timeout, this, &Qtbug45697TestWidget::slotTimer); + timer->start(); +} + +void Qtbug45697TestWidget::slotTimer() +{ + switch (m_timerTick++) { + case 0: + m_model->sort(0); + break; + case 1: + show(); + break; + default: + close(); + break; + } +} + +void tst_QTreeView::taskQTBUG_45697_crash() +{ + Qtbug45697TestWidget testWidget; + testWidget.setWindowTitle(QTest::currentTestFunction()); + testWidget.resize(400, 400); + testWidget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(100, 100)); + QTRY_VERIFY(testWidget.timerTick() >= 2); +} + QTEST_MAIN(tst_QTreeView) #include "tst_qtreeview.moc" diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index c9a1a64135..c33fd5a951 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -178,6 +178,12 @@ private slots: void settableStyleHints_data(); void settableStyleHints(); // Needs to run last as it changes style hints. + +protected slots: + void quitApplication(); + +private: + bool quitApplicationTriggered; }; class EventSpy : public QObject @@ -235,6 +241,7 @@ public: static char *argv0; tst_QApplication::tst_QApplication() + : quitApplicationTriggered(false) { #ifdef Q_OS_WINCE // Clean up environment previously to launching test @@ -719,11 +726,8 @@ void tst_QApplication::quitOnLastWindowClosed() { int argc = 0; QApplication app(argc, 0); - QTimer timer; - timer.setInterval(100); QSignalSpy spy(&app, SIGNAL(aboutToQuit())); - QSignalSpy spy2(&timer, SIGNAL(timeout())); CloseEventTestWindow mainWindow; @@ -733,14 +737,14 @@ void tst_QApplication::quitOnLastWindowClosed() mainWindow.show(); QVERIFY(QTest::qWaitForWindowExposed(&mainWindow)); - timer.start(); - QTimer::singleShot(1000, &mainWindow, SLOT(close())); // This should quit the application - QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + QTimer::singleShot(1000, &mainWindow, SLOT(close())); // This should NOT quit the application (see CloseEventTestWindow) + quitApplicationTriggered = false; + QTimer::singleShot(2000, this, SLOT(quitApplication())); // This actually quits the application. app.exec(); QCOMPARE(spy.count(), 1); - QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit + QVERIFY(quitApplicationTriggered); } { int argc = 0; @@ -768,24 +772,20 @@ void tst_QApplication::quitOnLastWindowClosed() QApplication app(argc, 0); QVERIFY(app.quitOnLastWindowClosed()); - QTimer timer; - timer.setInterval(100); - QSignalSpy timerSpy(&timer, SIGNAL(timeout())); - QWindow w; w.show(); QWidget wid; wid.show(); - timer.start(); QTimer::singleShot(1000, &wid, SLOT(close())); // This should NOT quit the application because the // QWindow is still there. - QTimer::singleShot(2000, &app, SLOT(quit())); // This causes the quit. + quitApplicationTriggered = false; + QTimer::singleShot(2000, this, SLOT(quitApplication())); // This causes the quit. app.exec(); - QVERIFY(timerSpy.count() > 15); // Should be around 20 if closing did not caused the quit + QVERIFY(quitApplicationTriggered); // Should be around 20 if closing did not caused the quit } { // QTBUG-31569: If the last widget with Qt::WA_QuitOnClose set is closed, other // widgets that don't have the attribute set should be closed automatically. @@ -2406,6 +2406,12 @@ void tst_QApplication::globalStaticObjectDestruction() #endif } +void tst_QApplication::quitApplication() +{ + quitApplicationTriggered = true; + qApp->quit(); +} + //QTEST_APPLESS_MAIN(tst_QApplication) int main(int argc, char *argv[]) { diff --git a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp index ebd99be786..0de9e188a0 100644 --- a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp +++ b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp @@ -34,30 +34,32 @@ #include <QtTest/QtTest> #include <qtooltip.h> +#include <qwhatsthis.h> +#include <qscreen.h> class tst_QToolTip : public QObject { Q_OBJECT -public: - tst_QToolTip() {} - virtual ~tst_QToolTip() {} - -public slots: - void initTestCase() {} - void cleanupTestCase() {} - void init() {} - void cleanup() {} - private slots: - - // task-specific tests below me + void init(); + void cleanup(); void task183679_data(); void task183679(); void whatsThis(); void setPalette(); }; +void tst_QToolTip::init() +{ + QVERIFY(!QToolTip::isVisible()); +} + +void tst_QToolTip::cleanup() +{ + QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); +} + class Widget_task183679 : public QWidget { Q_OBJECT @@ -100,12 +102,14 @@ void tst_QToolTip::task183679() #endif Widget_task183679 widget; + widget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(50, 50)); + widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag())); widget.show(); QApplication::setActiveWindow(&widget); QVERIFY(QTest::qWaitForWindowActive(&widget)); widget.showDelayedToolTip(100); - QTest::qWait(300); QTRY_VERIFY(QToolTip::isVisible()); QTest::keyPress(&widget, key); @@ -116,26 +120,31 @@ void tst_QToolTip::task183679() QTest::qWait(1500); QCOMPARE(QToolTip::isVisible(), visible); + if (visible) + QToolTip::hideText(); } -#include <QWhatsThis> +static QWidget *findWhatsThat() +{ + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->inherits("QWhatsThat")) + return widget; + } + return Q_NULLPTR; +} void tst_QToolTip::whatsThis() { qApp->setStyleSheet( "QWidget { font-size: 72px; }" ); - QWhatsThis::showText(QPoint(0,0), "THis is text"); - QTest::qWait(400); - QWidget *whatsthis = 0; - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - if (widget->inherits("QWhatsThat")) { - whatsthis = widget; - break; - } - } - QVERIFY(whatsthis); + QWhatsThis::showText(QPoint(0, 0), "This is text"); + + QWidget *whatsthis = Q_NULLPTR; + QTRY_VERIFY( (whatsthis = findWhatsThat()) ); QVERIFY(whatsthis->isVisible()); - QVERIFY(whatsthis->height() > 100); // Test QTBUG-2416 - qApp->setStyleSheet(""); + const int whatsThisHeight = whatsthis->height(); + qApp->setStyleSheet(QString()); + QWhatsThis::hideText(); + QVERIFY2(whatsThisHeight > 100, QByteArray::number(whatsThisHeight)); // Test QTBUG-2416 } @@ -167,6 +176,7 @@ void tst_QToolTip::setPalette() newPalette.setColor(QPalette::ToolTipText, Qt::blue); QToolTip::setPalette(newPalette); QCOMPARE(toolTip->palette(), newPalette); + QToolTip::hideText(); } QTEST_MAIN(tst_QToolTip) diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index ed40f98051..591aa9e40f 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -1,11 +1,16 @@ +# OSX QTBUG-25300 QTBUG-45502 [normalGeometry] ubuntu-14.04 +osx [saveRestoreGeometry] ubuntu-14.04 +osx [restoreVersion1Geometry] ubuntu-14.04 +osx [updateWhileMinimized] ubuntu-14.04 +osx [focusProxyAndInputMethods] ubuntu-14.04 [touchEventSynthesizedMouseEvent] @@ -14,3 +19,119 @@ ubuntu-14.04 ubuntu-14.04 [largerThanScreen_QTBUG30142] ubuntu-14.04 +[windowState] +osx +[showMaximized] +osx +[setGeometry] +osx +[stackUnder] +osx +[raise] +osx-10.9 +[widgetAt] +osx +[sheetOpacity] +osx +[resizeEvent] +osx +[setWindowGeometry:100,123 200x200, flags 0] +osx-10.10 +[windowMoveResize:100,123 200x200, flags 0] +osx-10.10 +[setWindowGeometry:100,122 200x200, flags 0] +osx-10.9 +[windowMoveResize:100,122 200x200, flags 0] +osx-10.9 +[setWindowGeometry:100,100 824x564, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x564, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x516, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x516, flags 0] +osx-10.10 +[setWindowGeometry:100,73 200x0, flags 0] +osx-10.10 +[windowMoveResize:100,73 200x0, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x519, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x519, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x518, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x518, flags 0] +osx-10.10 +[setWindowGeometry:100,72 200x0, flags 0] +osx-10.9 +[windowMoveResize:100,72 200x0, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x574, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x574, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x578, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x578, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x576, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x576, flags 0] +osx-10.9 +[setWindowGeometry:100,100 824x521, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x521, flags 0] +osx-10.10 +[setWindowGeometry:100,122 952x577, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x577, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x580, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x580, flags 0] +osx-10.9 +[windowMoveResize:130,72 0x0, flags 0] +osx-10.9 +[windowMoveResize:130,122 0x200, flags 0] +osx-10.9 +[childEvents] +osx +[renderInvisible] +osx +[optimizedResizeMove] +osx +[optimizedResize_topLevel] +osx +[render_systemClip] +osx +[update] +osx +[doubleRepaint] +osx +[childAt_unifiedToolBar] +osx +[showMinimizedKeepsFocus] +osx-10.10 +[moveWindowInShowEvent:1] +osx-10.9 +[moveWindowInShowEvent:2] +osx-10.9 +[taskQTBUG_4055_sendSyntheticEnterLeave] +osx +[syntheticEnterLeave] +osx +[maskedUpdate] +osx +[hideWhenFocusWidgetIsChild] +osx-10.10 +[hideOpaqueChildWhileHidden] +osx +[resizeStaticContentsChildWidget_QTBUG35282] +osx-10.9 +[lower] +osx +[setClearAndResizeMask] +osx +[setToolTip] +osx-10.9 diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.pro b/tests/auto/widgets/kernel/qwidget/qwidget.pro index 30e1048247..aae083d45e 100644 --- a/tests/auto/widgets/kernel/qwidget/qwidget.pro +++ b/tests/auto/widgets/kernel/qwidget/qwidget.pro @@ -21,5 +21,3 @@ x11 { } !wince*:win32:!winrt: LIBS += -luser32 -lgdi32 - -mac:CONFIG+=insignificant_test # QTBUG-25300, QTBUG-23695 diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 10c553bd3e..68ccaef43f 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -436,6 +436,7 @@ private slots: void grabKeyboard(); void touchEventSynthesizedMouseEvent(); + void touchUpdateOnNewTouch(); void styleSheetPropagation(); @@ -3335,8 +3336,6 @@ void tst_QWidget::widgetAt() #if defined(Q_OS_WINCE) QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 #endif - if (!QGuiApplication::platformName().compare(QLatin1String("cocoa"), Qt::CaseInsensitive)) - QEXPECT_FAIL("", "Window mask not implemented on Mac QTBUG-22326", Continue); QTRY_VERIFY((wr = QApplication::widgetAt(testPos))); QTRY_COMPARE(wr->objectName(), w1->objectName()); @@ -3355,8 +3354,6 @@ void tst_QWidget::widgetAt() #if defined(Q_OS_WINCE) QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 #endif - if (!QGuiApplication::platformName().compare(QLatin1String("cocoa"), Qt::CaseInsensitive)) - QEXPECT_FAIL("", "Window mask not implemented on Mac QTBUG-22326", Continue); QTRY_VERIFY(QApplication::widgetAt(testPos) == w1.data()); QTRY_VERIFY(QApplication::widgetAt(testPos + QPoint(1, 1)) == w2.data()); } @@ -9757,6 +9754,9 @@ class TouchMouseWidget : public QWidget { public: explicit TouchMouseWidget(QWidget *parent = 0) : QWidget(parent), + m_touchBeginCount(0), + m_touchUpdateCount(0), + m_touchEndCount(0), m_touchEventCount(0), m_acceptTouch(false), m_mouseEventCount(0), @@ -9783,6 +9783,12 @@ protected: case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: + if (e->type() == QEvent::TouchBegin) + ++m_touchBeginCount; + else if (e->type() == QEvent::TouchUpdate) + ++m_touchUpdateCount; + else if (e->type() == QEvent::TouchEnd) + ++m_touchEndCount; ++m_touchEventCount; if (m_acceptTouch) e->accept(); @@ -9807,6 +9813,9 @@ protected: } public: + int m_touchBeginCount; + int m_touchUpdateCount; + int m_touchEndCount; int m_touchEventCount; bool m_acceptTouch; int m_mouseEventCount; @@ -9923,6 +9932,46 @@ void tst_QWidget::touchEventSynthesizedMouseEvent() } } +void tst_QWidget::touchUpdateOnNewTouch() +{ + QTouchDevice *device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + + TouchMouseWidget widget; + widget.setAcceptTouch(true); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(new QWidget); + widget.setLayout(layout); + widget.show(); + + QWindow* window = widget.windowHandle(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QCOMPARE(widget.m_touchBeginCount, 0); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).press(0, QPoint(20, 20), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).move(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 1); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(0).press(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 2); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(1).release(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).release(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 1); +} + void tst_QWidget::styleSheetPropagation() { QTableView tw; diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp index 9c549365ff..38b473e5ae 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp @@ -90,6 +90,7 @@ private slots: // void buttons(); void testDelete(); + void testSignalEmissionAfterDelete_QTBUG_45835(); void testRemove(); void testMultipleAdd(); void testStandardButtonMapping_data(); @@ -111,6 +112,7 @@ private: tst_QDialogButtonBox::tst_QDialogButtonBox() { + qRegisterMetaType<QAbstractButton *>(); } tst_QDialogButtonBox::~tst_QDialogButtonBox() @@ -414,6 +416,70 @@ void tst_QDialogButtonBox::testDelete() QCOMPARE(buttonBox.buttons().count(), 0); } +class ObjectDeleter : public QObject +{ + Q_OBJECT +public slots: + void deleteButton(QAbstractButton *button) + { + delete button; + } + + void deleteSender() + { + delete sender(); + } +}; + +void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() +{ + { + QDialogButtonBox buttonBox; + QCOMPARE(buttonBox.buttons().count(), 0); + + QSignalSpy buttonClickedSpy(&buttonBox, &QDialogButtonBox::clicked); + QVERIFY(buttonClickedSpy.isValid()); + + QSignalSpy buttonBoxAcceptedSpy(&buttonBox, &QDialogButtonBox::accepted); + QVERIFY(buttonBoxAcceptedSpy.isValid()); + + QPushButton *button = buttonBox.addButton("Test", QDialogButtonBox::AcceptRole); + QCOMPARE(buttonBox.buttons().count(), 1); + + ObjectDeleter objectDeleter; + connect(&buttonBox, &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteButton); + + button->click(); + + QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonClickedSpy.count(), 1); + QCOMPARE(buttonBoxAcceptedSpy.count(), 1); + } + + { + QPointer<QDialogButtonBox> buttonBox(new QDialogButtonBox); + QCOMPARE(buttonBox->buttons().count(), 0); + + QSignalSpy buttonClickedSpy(buttonBox.data(), &QDialogButtonBox::clicked); + QVERIFY(buttonClickedSpy.isValid()); + + QSignalSpy buttonBoxAcceptedSpy(buttonBox.data(), &QDialogButtonBox::accepted); + QVERIFY(buttonBoxAcceptedSpy.isValid()); + + QPushButton *button = buttonBox->addButton("Test", QDialogButtonBox::AcceptRole); + QCOMPARE(buttonBox->buttons().count(), 1); + + ObjectDeleter objectDeleter; + connect(buttonBox.data(), &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteSender); + + button->click(); + + QVERIFY(buttonBox.isNull()); + QCOMPARE(buttonClickedSpy.count(), 1); + QCOMPARE(buttonBoxAcceptedSpy.count(), 0); + } +} + void tst_QDialogButtonBox::testMultipleAdd() { // Add a button into the thing multiple times. diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index ade9f72543..2bbc2e05b7 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -764,6 +764,8 @@ void tst_QDockWidget::restoreDockWidget() restoreWindow.show(); QVERIFY(QTest::qWaitForWindowExposed(&restoreWindow)); QTRY_VERIFY(dock->isFloating()); + if (!QGuiApplication::platformName().compare("xcb", Qt::CaseInsensitive)) + QSKIP("Skip due to Window manager positioning issues", Abort); QTRY_COMPARE(dock->pos(), dockPos); } } diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 9417541040..adedc601a9 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -304,6 +304,7 @@ private slots: void undoRedoAndEchoModes(); void clearButton(); + void clearButtonVisibleAfterSettingText_QTBUG_45518(); void sideWidgets(); void shouldShowPlaceholderText_data(); @@ -4273,6 +4274,50 @@ void tst_QLineEdit::clearButton() QVERIFY(!clearButton->isEnabled()); } +void tst_QLineEdit::clearButtonVisibleAfterSettingText_QTBUG_45518() +{ +#ifndef QT_BUILD_INTERNAL + QSKIP("This test requires a developer build"); +#else + QLineEdit edit; + edit.setMinimumWidth(200); + centerOnScreen(&edit); + QLineEditIconButton *clearButton; + clearButton = edit.findChild<QLineEditIconButton *>(); + QVERIFY(!clearButton); + + edit.setText(QStringLiteral("some text")); + edit.show(); + QVERIFY(QTest::qWaitForWindowActive(&edit)); + + QVERIFY(!edit.isClearButtonEnabled()); + + clearButton = edit.findChild<QLineEditIconButton *>(); + QVERIFY(!clearButton); + + edit.setClearButtonEnabled(true); + QVERIFY(edit.isClearButtonEnabled()); + + clearButton = edit.findChild<QLineEditIconButton *>(); + QVERIFY(clearButton); + QVERIFY(clearButton->isVisible()); + + QTRY_VERIFY(clearButton->opacity() > 0); + QTRY_COMPARE(clearButton->cursor().shape(), Qt::ArrowCursor); + + QTest::mouseClick(clearButton, Qt::LeftButton, 0, clearButton->rect().center()); + QTRY_COMPARE(edit.text(), QString()); + + QTRY_COMPARE(clearButton->opacity(), qreal(0)); + QTRY_COMPARE(clearButton->cursor().shape(), clearButton->parentWidget()->cursor().shape()); + + edit.setClearButtonEnabled(false); + QVERIFY(!edit.isClearButtonEnabled()); + clearButton = edit.findChild<QLineEditIconButton *>(); + QVERIFY(!clearButton); +#endif // QT_BUILD_INTERNAL +} + void tst_QLineEdit::sideWidgets() { QWidget testWidget; diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST new file mode 100644 index 0000000000..de49d5ff45 --- /dev/null +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -0,0 +1,2 @@ +[task258920_mouseBorder] +osx diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST index 53ea4a9148..424ab2ceed 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -2,3 +2,5 @@ ubuntu-14.04 [taskQTBUG4965_escapeEaten] ubuntu-14.04 +[task256322_highlight] +osx |