aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmltest/quicktest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmltest/quicktest.cpp')
-rw-r--r--src/qmltest/quicktest.cpp129
1 files changed, 80 insertions, 49 deletions
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index 1fd36edd62..1a580f8c69 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -4,6 +4,7 @@
#include "quicktest_p.h"
#include "quicktestresult_p.h"
#include <QtTest/qtestsystem.h>
+#include <QtTest/private/qtestcrashhandler_p.h>
#include "qtestoptions_p.h"
#include <QtQml/qqml.h>
#include <QtQml/qqmlengine.h>
@@ -31,6 +32,8 @@
#include <QtGui/qtextdocument.h>
#include <stdio.h>
#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
#include <QtCore/QTranslator>
#include <QtTest/QSignalSpy>
#include <QtQml/QQmlFileSelector>
@@ -223,22 +226,45 @@ static void handleCompileErrors(
results.stopLogging();
}
-bool qWaitForSignal(QObject *obj, const char* signal, int timeout = 5000)
+class SimpleReceiver : public QObject {
+ Q_OBJECT
+public:
+ bool signalReceived = false;
+public slots:
+ void slotFun() { signalReceived = true; }
+};
+
+bool qWaitForSignal(QObject *obj, const char* signal, int timeout)
{
- QSignalSpy spy(obj, signal);
- QElapsedTimer timer;
- timer.start();
-
- while (!spy.size()) {
- int remaining = timeout - int(timer.elapsed());
- if (remaining <= 0)
- break;
- QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
- QTest::qSleep(10);
+ if (!obj || !signal) {
+ qWarning("qWaitForSignal: invalid arguments");
+ return false;
+ }
+ if (((signal[0] - '0') & 0x03) != QSIGNAL_CODE) {
+ qWarning("qWaitForSignal: not a valid signal, use the SIGNAL macro");
+ return false;
}
- return spy.size();
+ int sig = obj->metaObject()->indexOfSignal(signal + 1);
+ if (sig == -1) {
+ const QByteArray ba = QMetaObject::normalizedSignature(signal + 1);
+ sig = obj->metaObject()->indexOfSignal(ba.constData());
+ if (sig == -1) {
+ qWarning("qWaitForSignal: no such signal %s::%s", obj->metaObject()->className(),
+ signal);
+ return false;
+ }
+ }
+
+ SimpleReceiver receiver;
+ static int slot = receiver.metaObject()->indexOfSlot("slotFun()");
+ if (!QMetaObject::connect(obj, sig, &receiver, slot)) {
+ qWarning("qWaitForSignal: failed to connect to signal %s::%s",
+ obj->metaObject()->className(), signal);
+ return false;
+ }
+
+ return QTest::qWaitFor([&]() { return receiver.signalReceived; }, timeout);
}
template <typename... Args>
@@ -264,7 +290,7 @@ class TestCaseCollector
public:
typedef QList<QString> TestCaseList;
- TestCaseCollector(const QFileInfo &fileInfo, QQmlEngine *engine)
+ TestCaseCollector(const QFileInfo &fileInfo, QQmlEngine *engine) : m_engine(engine)
{
QString path = fileInfo.absoluteFilePath();
if (path.startsWith(QLatin1String(":/")))
@@ -276,7 +302,8 @@ public:
if (component.isReady()) {
QQmlRefPointer<QV4::ExecutableCompilationUnit> rootCompilationUnit
= QQmlComponentPrivate::get(&component)->compilationUnit;
- TestCaseEnumerationResult result = enumerateTestCases(rootCompilationUnit.data());
+ TestCaseEnumerationResult result = enumerateTestCases(
+ rootCompilationUnit->baseCompilationUnit().data());
m_testCases = result.testCases + result.finalizedPartialTestCases();
m_errors += result.errors;
}
@@ -288,6 +315,7 @@ public:
private:
TestCaseList m_testCases;
QList<QQmlError> m_errors;
+ QQmlEngine *m_engine = nullptr;
struct TestCaseEnumerationResult
{
@@ -316,8 +344,8 @@ private:
};
TestCaseEnumerationResult enumerateTestCases(
- const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
- const Object *object = nullptr)
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Object *object = nullptr)
{
QQmlType testCaseType;
for (quint32 i = 0, count = compilationUnit->importCount(); i < count; ++i) {
@@ -330,7 +358,8 @@ private:
if (!typeQualifier.isEmpty())
testCaseTypeName = typeQualifier % QLatin1Char('.') % testCaseTypeName;
- testCaseType = compilationUnit->typeNameCache->query(testCaseTypeName).type;
+ testCaseType = compilationUnit->typeNameCache->query(
+ testCaseTypeName, QQmlTypeLoader::get(m_engine)).type;
if (testCaseType.isValid())
break;
}
@@ -339,11 +368,11 @@ private:
if (!object) // Start at root of compilation unit if not enumerating a specific child
object = compilationUnit->objectAt(0);
- if (object->hasFlag(Object::IsInlineComponentRoot))
+ if (object->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot))
return result;
- if (const auto superTypeUnit = compilationUnit->resolvedTypes.value(
- object->inheritedTypeNameIndex)->compilationUnit()) {
+ if (const auto superTypeUnit = compilationUnit->resolvedType(object->inheritedTypeNameIndex)
+ ->compilationUnit()) {
// We have a non-C++ super type, which could indicate we're a subtype of a TestCase
if (testCaseType.isValid() && superTypeUnit->url() == testCaseType.sourceUrl())
result.isTestCase = true;
@@ -386,7 +415,7 @@ private:
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
if (binding->type() == QV4::CompiledData::Binding::Type_Object) {
- const Object *child = compilationUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Object *child = compilationUnit->objectAt(binding->value.objectIndex);
result << enumerateTestCases(compilationUnit, child);
}
}
@@ -541,6 +570,11 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
return 1;
}
+ std::optional<QTest::CrashHandler::FatalSignalHandler> handler;
+ QTest::CrashHandler::prepareStackTrace();
+ if (!QTest::Internal::noCrashHandler)
+ handler.emplace();
+
qputenv("QT_QTESTLIB_RUNNING", "1");
QSet<QString> commandLineTestFunctions(QTest::testFunctions.cbegin(), QTest::testFunctions.cend());
@@ -616,39 +650,35 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
handleCompileErrors(fi, view.errors(), view.engine(), &view);
continue;
}
- if (!QTestRootObject::instance()->hasQuit) {
- // If the test already quit, then it was performed
- // synchronously during setSource(). Otherwise it is
- // an asynchronous test and we need to show the window
- // and wait for the first frame to be rendered
- // and then wait for quit indication.
- view.setFramePosition(QPoint(50, 50));
- if (view.size().isEmpty()) { // Avoid hangs with empty windows.
- view.resize(200, 200);
- }
- view.show();
- if (!QTest::qWaitForWindowExposed(&view)) {
- qWarning().nospace()
- << "Test '" << QDir::toNativeSeparators(path) << "' window not exposed after show().";
- }
+
+ view.setFramePosition(QPoint(50, 50));
+ if (view.size().isEmpty()) { // Avoid hangs with empty windows.
+ view.resize(200, 200);
+ }
+ view.show();
+ if (!QTest::qWaitForWindowExposed(&view)) {
+ qWarning().nospace()
+ << "Test '" << QDir::toNativeSeparators(path) << "' window not exposed after show().";
+ }
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) {
view.requestActivate();
if (!QTest::qWaitForWindowActive(&view)) {
qWarning().nospace()
<< "Test '" << QDir::toNativeSeparators(path) << "' window not active after requestActivate().";
}
- if (view.isExposed()) {
- // Defer property update until event loop has started
- QTimer::singleShot(0, []() {
- QTestRootObject::instance()->setWindowShown(true);
- });
- } else {
- qWarning().nospace()
- << "Test '" << QDir::toNativeSeparators(path) << "' window was never exposed! "
- << "If the test case was expecting windowShown, it will hang.";
- }
- if (!QTestRootObject::instance()->hasQuit && QTestRootObject::instance()->hasTestCase())
- eventLoop.exec();
}
+ if (view.isExposed()) {
+ // Defer property update until event loop has started
+ QTimer::singleShot(0, []() {
+ QTestRootObject::instance()->setWindowShown(true);
+ });
+ } else {
+ qWarning().nospace()
+ << "Test '" << QDir::toNativeSeparators(path) << "' window was never exposed! "
+ << "If the test case was expecting windowShown, it will hang.";
+ }
+ if (!QTestRootObject::instance()->hasQuit && QTestRootObject::instance()->hasTestCase())
+ eventLoop.exec();
}
if (setup)
@@ -673,3 +703,4 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
QT_END_NAMESPACE
#include "moc_quicktest_p.cpp"
+#include "quicktest.moc"