summaryrefslogtreecommitdiffstats
path: root/tests/auto/integration/qwindowcapturebackend/fixture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/integration/qwindowcapturebackend/fixture.cpp')
-rw-r--r--tests/auto/integration/qwindowcapturebackend/fixture.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/tests/auto/integration/qwindowcapturebackend/fixture.cpp b/tests/auto/integration/qwindowcapturebackend/fixture.cpp
new file mode 100644
index 000000000..ee130e294
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/fixture.cpp
@@ -0,0 +1,234 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "fixture.h"
+
+#include <qmediaplayer.h>
+#include <qvideowidget.h>
+#include <qsystemsemaphore.h>
+#include <quuid.h>
+
+DisableCursor::DisableCursor()
+{
+ QCursor cursor(Qt::BlankCursor);
+ QApplication::setOverrideCursor(cursor);
+}
+
+DisableCursor::~DisableCursor()
+{
+ QGuiApplication::restoreOverrideCursor();
+}
+
+WindowCaptureFixture::WindowCaptureFixture()
+{
+ m_session.setWindowCapture(&m_capture);
+ m_session.setVideoSink(&m_grabber);
+}
+
+QString WindowCaptureFixture::getResultsPath(const QString &fileName)
+{
+ const QString sep = QStringLiteral("--");
+
+ QString stem = QCoreApplication::applicationName();
+ if (const char *currentTest = QTest::currentTestFunction())
+ stem += sep + QString::fromLatin1(currentTest);
+
+ if (const char *currentTag = QTest::currentDataTag())
+ stem += sep + QString::fromLatin1(currentTag);
+
+ stem += sep + fileName;
+
+ const QDir resultsDir = qEnvironmentVariable("COIN_CTEST_RESULTSDIR", QDir::tempPath());
+
+ return resultsDir.filePath(stem);
+}
+
+bool WindowCaptureFixture::compareImages(QImage actual, const QImage &expected,
+ const QString &fileSuffix)
+{
+ // Convert to same format so that we can compare images
+ actual = actual.convertToFormat(expected.format());
+
+ if (actual == expected)
+ return true;
+
+ qWarning() << "Image comparison failed.";
+ qWarning() << "Actual image:";
+ qWarning() << actual;
+ qWarning() << "Expected image:";
+ qWarning() << expected;
+
+ const QString actualName = getResultsPath(QStringLiteral("actual%1.png").arg(fileSuffix));
+ if (!actual.save(actualName))
+ qWarning() << "Failed to save actual file to " << actualName;
+
+ const QString expectedName = getResultsPath(QStringLiteral("expected%1.png").arg(fileSuffix));
+ if (!expected.save(expectedName))
+ qWarning() << "Failed to save expected file to " << expectedName;
+
+ return false;
+}
+
+bool WindowCaptureWithWidgetFixture::start(QSize size)
+{
+ // In case of window capture failure, signal the grabber so we can stop
+ // waiting for frames that will never come.
+ connect(&m_capture, &QWindowCapture::errorOccurred, &m_grabber, &FrameGrabber::stop);
+
+ m_widget.setSize(size);
+
+ m_widget.show();
+
+ // Make sure window is in a state that allows it to be found by QWindowCapture.
+ // Not necessary on Windows, but seems to be necessary on some platforms.
+ if (!QTest::qWaitForWindowExposed(&m_widget, static_cast<int>(s_testTimeout.count()))) {
+ qWarning() << "Failed to display widget within timeout";
+ return false;
+ }
+
+ m_captureWindow = findCaptureWindow(m_widget.windowTitle());
+
+ if (!m_captureWindow.isValid())
+ return false;
+
+ m_capture.setWindow(m_captureWindow);
+ m_capture.setActive(true);
+
+ return true;
+}
+
+QVideoFrame WindowCaptureWithWidgetFixture::waitForFrame(qint64 noOlderThanTime)
+{
+ const std::vector<QVideoFrame> frames = m_grabber.waitAndTakeFrames(1u, noOlderThanTime);
+ if (frames.empty())
+ return QVideoFrame{};
+
+ return frames.back();
+}
+
+QCapturableWindow WindowCaptureWithWidgetFixture::findCaptureWindow(const QString &windowTitle)
+{
+ QList<QCapturableWindow> allWindows = QWindowCapture::capturableWindows();
+
+ const auto window = std::find_if(allWindows.begin(), allWindows.end(),
+ [windowTitle](const QCapturableWindow &win) {
+ return win.description() == windowTitle;
+ });
+
+ // Extra debug output to help understanding if test widget window could not be found
+ if (window == allWindows.end()) {
+ qDebug() << "Could not find window" << windowTitle << ". Existing capturable windows:";
+ std::for_each(allWindows.begin(), allWindows.end(), [](const QCapturableWindow &win) {
+ qDebug() << " " << win.description();
+ });
+ return QCapturableWindow{};
+ }
+
+ return *window;
+}
+
+void WindowCaptureWithWidgetAndRecorderFixture::start(QSize size, bool togglePattern)
+{
+ if (togglePattern) {
+ // Drive animation
+ connect(&m_grabber, &FrameGrabber::videoFrameChanged, &m_widget,
+ &TestWidget::togglePattern);
+ }
+
+ connect(&m_recorder, &QMediaRecorder::recorderStateChanged, this,
+ &WindowCaptureWithWidgetAndRecorderFixture::recorderStateChanged);
+
+ m_session.setRecorder(&m_recorder);
+ m_recorder.setQuality(QMediaRecorder::HighQuality);
+ m_recorder.setOutputLocation(QUrl::fromLocalFile(m_mediaFile));
+ m_recorder.setVideoResolution(size);
+
+ WindowCaptureWithWidgetFixture::start(size);
+
+ m_recorder.record();
+}
+
+bool WindowCaptureWithWidgetAndRecorderFixture::stop()
+{
+ m_recorder.stop();
+
+ const auto recorderStopped = [this] { return m_recorderState == QMediaRecorder::StoppedState; };
+
+ return QTest::qWaitFor(recorderStopped, s_testTimeout);
+}
+
+bool WindowCaptureWithWidgetAndRecorderFixture::testVideoFilePlayback(const QString &fileName)
+{
+ QVideoWidget widget;
+
+ QMediaPlayer player;
+
+ bool playing = true;
+ connect(&player, &QMediaPlayer::playbackStateChanged, this,
+ [&](QMediaPlayer::PlaybackState state) {
+ if (state == QMediaPlayer::StoppedState)
+ playing = false;
+ });
+
+ QMediaPlayer::Error error = QMediaPlayer::NoError;
+ connect(&player, &QMediaPlayer::errorOccurred, this,
+ [&](QMediaPlayer::Error e, const QString &errorString) {
+ error = e;
+ qWarning() << errorString;
+ });
+
+ player.setSource(QUrl{ fileName });
+ player.setVideoOutput(&widget);
+ widget.show();
+ player.play();
+
+ const bool completed = QTest::qWaitFor(
+ [&] { return !playing || error != QMediaPlayer::NoError; }, s_testTimeout);
+
+ return completed && error == QMediaPlayer::NoError;
+}
+
+void WindowCaptureWithWidgetAndRecorderFixture::recorderStateChanged(
+ QMediaRecorder::RecorderState state)
+{
+ m_recorderState = state;
+}
+
+bool WindowCaptureWithWidgetInOtherProcessFixture::start()
+{
+ // In case of window capture failure, signal the grabber so we can stop
+ // waiting for frames that will never come.
+ connect(&m_capture, &QWindowCapture::errorOccurred, &m_grabber, &FrameGrabber::stop);
+
+ // Create a new window title that is also used as a semaphore key with less than 30 characters
+ const QString windowTitle = QString::number(qHash(QUuid::createUuid().toString()));
+
+ QSystemSemaphore windowVisible{ QNativeIpcKey{ windowTitle } };
+
+ // Start another instance of the test executable and ask it to show a
+ // its test widget.
+ m_windowProcess.setArguments({ "--show", windowTitle });
+ m_windowProcess.setProgram(QApplication::applicationFilePath());
+ m_windowProcess.start();
+
+ // Make sure window is in a state that allows it to be found by QWindowCapture.
+ // We do this by waiting for the process to release the semaphore once its window is visible
+ windowVisible.acquire();
+
+ m_captureWindow = findCaptureWindow(windowTitle);
+
+ if (!m_captureWindow.isValid())
+ return false;
+
+ // Start capturing the out-of-process window
+ m_capture.setWindow(m_captureWindow);
+ m_capture.setActive(true);
+
+ // Show in-process widget used to create a reference image
+ m_widget.show();
+
+ return true;
+}
+
+
+#include "moc_fixture.cpp"