From 97dcbd4019456b9a1c567faddb0521b7505d80fc Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 11 Feb 2021 10:03:24 +0100 Subject: Add tests to the cmake build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use QT_TESTCASE_SOURCEDIR instead of TESTS_SOURCE_DIR. Introduce Test::HttpServer and Test::Util targets. Query shared data location from server. Clean up "shared" resources. Note QT_TESTCASE_SOURCEDIR must be turned into the canonical form since the user can call on windows: "cmake \path\to\foo" instead of "cmake c:\path\to\foo" which will break all file:// urls. Note this patch breaks qmake builds. Task-number: QTBUG-91760 Change-Id: Ibc1f904ac9acd375d1ff70ff80f0c533497e3f20 Reviewed-by: Michael BrĂ¼ning --- tests/auto/util/util.h | 238 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 tests/auto/util/util.h (limited to 'tests/auto/util/util.h') diff --git a/tests/auto/util/util.h b/tests/auto/util/util.h new file mode 100644 index 000000000..537b9212b --- /dev/null +++ b/tests/auto/util/util.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Functions and macros that really need to be in QTestLib + +#if 0 +#pragma qt_no_master_include +#endif + +#include +#include +#include +#include +#include + +// Disconnect signal on destruction. +class ScopedConnection +{ +public: + ScopedConnection(QMetaObject::Connection connection) : m_connection(std::move(connection)) { } + ~ScopedConnection() { QObject::disconnect(m_connection); } + +private: + QMetaObject::Connection m_connection; +}; + +/** + * Just like QSignalSpy but facilitates sync and async + * signal emission. For example if you want to verify that + * page->foo() emitted a signal, it could be that the + * implementation decides to emit the signal asynchronously + * - in which case we want to spin a local event loop until + * emission - or that the call to foo() emits it right away. + */ +class SignalBarrier : private QSignalSpy +{ +public: + SignalBarrier(const QObject* obj, const char* aSignal) + : QSignalSpy(obj, aSignal) + { } + + bool ensureSignalEmitted() + { + bool result = count() > 0; + if (!result) + result = wait(); + clear(); + return result; + } +}; + +template +struct CallbackWrapper { + QPointer p; + void operator()(const T& result) { + if (p) + (*p)(result); + } +}; + +template +class CallbackSpy: public QObject { +public: + CallbackSpy() : called(false) { + timeoutTimer.setSingleShot(true); + QObject::connect(&timeoutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + } + + T waitForResult(int timeout = 20000) { + const int step = 1000; + int elapsed = 0; + while (elapsed < timeout && !called) { + timeoutTimer.start(step); + eventLoop.exec(); + elapsed += step; + } + return result; + } + + bool wasCalled() const { + return called; + } + + void operator()(const T &result) { + this->result = result; + called = true; + eventLoop.quit(); + } + + CallbackWrapper > ref() + { + CallbackWrapper > wrapper = {this}; + return wrapper; + } + +private: + Q_DISABLE_COPY(CallbackSpy) + bool called; + QTimer timeoutTimer; + QEventLoop eventLoop; + T result; +}; + +static inline QString toPlainTextSync(QWebEnginePage *page) +{ + CallbackSpy spy; + page->toPlainText(spy.ref()); + return spy.waitForResult(); +} + +static inline QString toHtmlSync(QWebEnginePage *page) +{ + CallbackSpy spy; + page->toHtml(spy.ref()); + return spy.waitForResult(); +} + +static inline bool findTextSync(QWebEnginePage *page, const QString &subString) +{ + CallbackSpy spy; + page->findText(subString, {}, spy.ref()); + return spy.waitForResult(); +} + +static inline QVariant evaluateJavaScriptSync(QWebEnginePage *page, const QString &script) +{ + CallbackSpy spy; + page->runJavaScript(script, spy.ref()); + return spy.waitForResult(); +} + +static inline QVariant evaluateJavaScriptSyncInWorld(QWebEnginePage *page, const QString &script, int worldId) +{ + CallbackSpy spy; + page->runJavaScript(script, worldId, spy.ref()); + return spy.waitForResult(); +} + +static inline QUrl baseUrlSync(QWebEnginePage *page) +{ + CallbackSpy spy; + page->runJavaScript("document.baseURI", spy.ref()); + return spy.waitForResult().toUrl(); +} + +static inline bool loadSync(QWebEnginePage *page, const QUrl &url, bool ok = true) +{ + QSignalSpy spy(page, &QWebEnginePage::loadFinished); + page->load(url); + return (!spy.empty() || spy.wait(20000)) && (spy.front().value(0).toBool() == ok); +} + +static inline bool loadSync(QWebEngineView *view, const QUrl &url, bool ok = true) +{ + return loadSync(view->page(), url, ok); +} + +static inline QPoint elementCenter(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function(){" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" + "})()"); + QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList(); + + if (rectList.count() != 2) { + qWarning("elementCenter failed."); + return QPoint(); + } + + return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); +} + +static inline QRect elementGeometry(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function() {" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [rect.left, rect.top, rect.right, rect.bottom];" + "})()"); + QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList(); + + if (coords.count() != 4) { + qWarning("elementGeometry faield."); + return QRect(); + } + + return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt()); +} + + +#define W_QSKIP(a, b) QSKIP(a) + +#define W_QTEST_MAIN(TestObject, params) \ +int main(int argc, char *argv[]) \ +{ \ + QList w_argv(argc); \ + for (int i = 0; i < argc; ++i) \ + w_argv[i] = argv[i]; \ + for (int i = 0; i < params.size(); ++i) \ + w_argv.append(params[i].data()); \ + int w_argc = w_argv.size(); \ + \ + QApplication app(w_argc, const_cast(w_argv.data())); \ + app.setAttribute(Qt::AA_Use96Dpi, true); \ + QTEST_DISABLE_KEYPAD_NAVIGATION \ + TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ + return QTest::qExec(&tc, argc, argv); \ +} -- cgit v1.2.3