summaryrefslogtreecommitdiff
path: root/tests/baseline/mapitems/tst_baseline_mapitems.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/baseline/mapitems/tst_baseline_mapitems.cpp')
-rw-r--r--tests/baseline/mapitems/tst_baseline_mapitems.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/tests/baseline/mapitems/tst_baseline_mapitems.cpp b/tests/baseline/mapitems/tst_baseline_mapitems.cpp
new file mode 100644
index 00000000..3ee8f90d
--- /dev/null
+++ b/tests/baseline/mapitems/tst_baseline_mapitems.cpp
@@ -0,0 +1,240 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <qbaselinetest.h>
+
+#include <QtCore/QDirIterator>
+#include <QtCore/QDebug>
+#include <QtCore/QProcess>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QImage>
+#include <QtGui/QPalette>
+#include <QtGui/QFont>
+
+#include <algorithm>
+
+QString blockify(const QByteArray& s)
+{
+ const char* indent = "\n | ";
+ QByteArray block = s.trimmed();
+ block.replace('\n', indent);
+ block.prepend(indent);
+ block.append('\n');
+ return block;
+}
+
+class tst_Baseline_MapItems : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Baseline_MapItems();
+
+private Q_SLOTS:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void circle_data() { setupTestSuite(); }
+ void circle() { runTest(); }
+
+private:
+ void test();
+
+ void setupTestSuite();
+ void runTest(const QString& style = QString());
+ bool renderAndGrab(const QString& qmlFile, const QStringList& extraArgs, QImage *screenshot, QString *errMsg);
+
+ QString testSuitePath;
+ QString grabberPath;
+ QStringList testFiles;
+ int consecutiveErrors; // Not test failures (image mismatches), but system failures (so no image at all)
+ bool aborted; // This run given up because of too many system failures
+};
+
+
+tst_Baseline_MapItems::tst_Baseline_MapItems()
+ : consecutiveErrors(0), aborted(false)
+{
+}
+
+
+void tst_Baseline_MapItems::initTestCase()
+{
+ QString dataDir = QFINDTESTDATA("./data/.");
+ if (dataDir.isEmpty())
+ dataDir = QStringLiteral("data");
+ QFileInfo fi(dataDir);
+ if (!fi.exists() || !fi.isDir() || !fi.isReadable())
+ QSKIP("Test suite data directory missing or unreadable: " + fi.canonicalFilePath().toLatin1());
+ testSuitePath = fi.canonicalFilePath();
+
+#if defined(Q_OS_WIN)
+ grabberPath = QFINDTESTDATA("../../../../qtdeclarative/tests/baseline/scenegraph/qmlscenegrabber.exe");
+#elif defined(Q_OS_DARWIN)
+ grabberPath = QFINDTESTDATA("../../../../qtdeclarative/tests/baseline/scenegraph/qmlscenegrabber.app/Contents/MacOS/qmlscenegrabber");
+#else
+ grabberPath = QFINDTESTDATA("../../../../qtdeclarative/tests/baseline/scenegraph/qmlscenegrabber");
+#endif
+ if (grabberPath.isEmpty())
+ grabberPath = QCoreApplication::applicationDirPath() + "../../../../qtdeclarative/tests/baseline/scenegraph/qmlscenegrabber.exe";
+
+ QBaselineTest::setProject("MapItems");
+ // Set key platform properties that are relevant for the appearance of controls
+ const QString platformName = QGuiApplication::platformName() + "-" + QSysInfo::productType();
+ QBaselineTest::addClientProperty("PlatformName", platformName);
+ QBaselineTest::addClientProperty("OSVersion", QSysInfo::productVersion());
+
+ const char *backendVarName = "QT_QUICK_BACKEND";
+ const QString backend = qEnvironmentVariable(backendVarName, QString::fromLatin1("default"));
+ QBaselineTest::addClientProperty(QString::fromLatin1(backendVarName), backend);
+
+ QString stack = backend;
+ if (stack != QLatin1String("software")) {
+#if defined(Q_OS_WIN)
+ const char *defaultRhiBackend = "d3d11";
+#elif defined(Q_OS_DARWIN)
+ const char *defaultRhiBackend = "metal";
+#else
+ const char *defaultRhiBackend = "opengl";
+#endif
+ const QString rhiBackend = qEnvironmentVariable("QSG_RHI_BACKEND", QString::fromLatin1(defaultRhiBackend));
+ stack = QString::fromLatin1("RHI_%1").arg(rhiBackend);
+ }
+
+ QBaselineTest::addClientProperty(QString::fromLatin1("GraphicsStack"), stack);
+
+ // Assume that text that's darker than the background means we run in light mode
+ // See also qwidgetbaselinetest.cpp
+ QPalette palette;
+ QFont font;
+ QByteArray appearanceBytes;
+ {
+ QDataStream appearanceStream(&appearanceBytes, QIODevice::WriteOnly);
+ appearanceStream << palette << font;
+ const qreal screenDpr = QGuiApplication::primaryScreen()->devicePixelRatio();
+ if (screenDpr != 1.0) {
+ qWarning() << "DPR is" << screenDpr << "- images will not be compared to 1.0 baseline!";
+ appearanceStream << screenDpr;
+ }
+ }
+ const quint16 appearanceId = qChecksum(appearanceBytes);
+
+ const QColor windowColor = palette.window().color();
+ const QColor textColor = palette.text().color();
+ const QString appearanceIdString = (windowColor.value() > textColor.value()
+ ? QString("light-%1") : QString("dark-%1"))
+ .arg(appearanceId, 0, 16);
+ QBaselineTest::addClientProperty("AppearanceID", appearanceIdString);
+
+ QByteArray msg;
+ if (!QBaselineTest::connectToBaselineServer(&msg))
+ QSKIP(msg);
+}
+
+void tst_Baseline_MapItems::init()
+{
+ consecutiveErrors = 0;
+ aborted = false;
+}
+
+void tst_Baseline_MapItems::cleanup()
+{
+ // Allow subsystems time to settle
+ if (!aborted)
+ QTest::qWait(20);
+}
+
+void tst_Baseline_MapItems::setupTestSuite()
+{
+ QTest::addColumn<QString>("qmlFile");
+
+ const QStringView qmlExt(u".qml");
+ if (testFiles.isEmpty()) {
+ QDirIterator it(testSuitePath, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ const QString fp = it.next().toLatin1();
+ if (fp.endsWith(qmlExt))
+ testFiles.append(it.filePath());
+ }
+ std::sort(testFiles.begin(), testFiles.end());
+ }
+
+ if (testFiles.isEmpty())
+ QSKIP("No .qml test files found in " + testSuitePath.toLatin1());
+
+ for (const auto &filePath : std::as_const(testFiles)) {
+ QString itemName = filePath.sliced(testSuitePath.size() + 1);
+ itemName = itemName.left(itemName.size() - qmlExt.size());
+ QBaselineTest::newRow(itemName.toLatin1()) << filePath;
+ }
+}
+
+
+void tst_Baseline_MapItems::runTest(const QString& style)
+{
+ if (aborted)
+ QSKIP("System too unstable.");
+
+ QFETCH(QString, qmlFile);
+
+ QImage screenShot;
+ QString errorMessage;
+ QStringList args;
+ if (!style.isEmpty())
+ args.append({"-style", style});
+ if (renderAndGrab(qmlFile, args, &screenShot, &errorMessage)) {
+ consecutiveErrors = 0;
+ } else {
+ if (++consecutiveErrors >= 3)
+ aborted = true; // Just give up if screen grabbing fails 3 times in a row
+ QFAIL(qPrintable("QuickView grabbing failed: " + errorMessage));
+ }
+
+ QBASELINE_TEST(screenShot);
+}
+
+
+bool tst_Baseline_MapItems::renderAndGrab(const QString& qmlFile, const QStringList& extraArgs, QImage *screenshot, QString *errMsg)
+{
+ bool usePipe = true; // Whether to transport the grabbed image using temp. file or pipe. TBD: cmdline option
+ QProcess grabber;
+ grabber.setProcessChannelMode(QProcess::ForwardedErrorChannel);
+ QStringList args = extraArgs;
+ QString tmpfile = usePipe ? QString("-") : QString("/tmp/qmlscenegrabber-%1-out.ppm").arg(QCoreApplication::applicationPid());
+ args << qmlFile << "-o" << tmpfile;
+ grabber.start(grabberPath, args, QIODevice::ReadOnly);
+ grabber.waitForFinished(17000); //### hardcoded, must be larger than the scene timeout in qmlscenegrabber
+ if (grabber.state() != QProcess::NotRunning) {
+ grabber.terminate();
+ grabber.waitForFinished(3000);
+ }
+ QImage img;
+ bool res = usePipe ? img.load(&grabber, "ppm") : img.load(tmpfile);
+ if (!res || img.isNull()) {
+ if (errMsg) {
+ QString s("Failed to grab screen. qmlscenegrabber exitcode: %1. Process error: %2. Stderr:%3");
+ *errMsg = s.arg(grabber.exitCode()).arg(grabber.errorString()).arg(blockify(grabber.readAllStandardError()));
+ }
+ if (!usePipe)
+ QFile::remove(tmpfile);
+ return false;
+ }
+ if (screenshot)
+ *screenshot = img;
+ if (!usePipe)
+ QFile::remove(tmpfile);
+ return true;
+}
+
+#define main _realmain
+QTEST_MAIN(tst_Baseline_MapItems)
+#undef main
+
+int main(int argc, char *argv[])
+{
+ QBaselineTest::handleCmdLineArgs(&argc, &argv);
+ return _realmain(argc, argv);
+}
+
+#include "tst_baseline_mapitems.moc"