// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(lcQml, "qt.qml.tests"); class tst_qml : public QQmlDataTest { Q_OBJECT public: tst_qml() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; void nonWindow(); void itemAndWindowGeometry_data(); void itemAndWindowGeometry(); private: QString qmlPath; }; void tst_qml::initTestCase() { QQmlDataTest::initTestCase(); qmlPath = QLibraryInfo::path(QLibraryInfo::BinariesPath); #if defined(Q_OS_WIN) qmlPath += QLatin1String("/qml.exe"); #else qmlPath += QLatin1String("/qml"); #endif QVERIFY(QFileInfo(qmlPath).exists()); } void tst_qml::nonWindow() { QProcess qml; qml.start(qmlPath, { testFile("nonWindow.qml") }); QVERIFY(qml.waitForFinished()); QCOMPARE(qml.exitCode(), 0); // Should not exit with code 2 } void tst_qml::itemAndWindowGeometry_data() { QTest::addColumn("config"); QTest::addColumn("geometry"); QTest::addColumn("qmlfile"); QTest::addColumn("expectedWindowSize"); QTest::addColumn("expectedContentSize"); const QString none; // empty string auto sizeOrInvalid = [](int w, int h) { static const bool wm = QGuiApplicationPrivate::platformIntegration()-> hasCapability(QPlatformIntegration::WindowManagement); return wm ? QSize(w, h) : QSize(); }; QTest::newRow("default: unsized") << none << none << "unsizedItem.qml" << QSize() << QSize(); // default size depends on window system QTest::newRow("default: unsized with geometry") << none << "100x100+50+50" << "unsizedItem.qml" << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100); QTest::newRow("resizeToItem: unsized") << "resizeToItem" << none << "unsizedItem.qml" << QSize() << QSize(0, 0); QTest::newRow("resizeToItem: unsized with geometry") << "resizeToItem" << "100x100+50+50" << "unsizedItem.qml" << sizeOrInvalid(100, 100) << QSize(0, 0); QTest::newRow("default: sized") << none << none << "sizedItem.qml" << QSize() << QSize(); QTest::newRow("default: sized with geometry") << none << "100x100+50+50" << "sizedItem.qml" << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100); QTest::newRow("resizeToItem: sized") << "resizeToItem" << none << "sizedItem.qml" << sizeOrInvalid(200, 150) << sizeOrInvalid(200, 150); QTest::newRow("resizeToItem: sized with geometry") << "resizeToItem" << "320x240+50+50" << "sizedItem.qml" << sizeOrInvalid(320, 240) << QSize(200, 150); QTest::newRow("default: resizing") << none << none << "resizeItem.qml" << QSize() << QSize(); QTest::newRow("default: resizing with geometry") << none << "100x100+50+50" << "resizeItem.qml" << sizeOrInvalid(100, 100) << sizeOrInvalid(100, 100); QTest::newRow("resizeToItem: resizing") << "resizeToItem" << none << "resizeItem.qml" << sizeOrInvalid(100, 50) << sizeOrInvalid(100, 50); QTest::newRow("resizeToItem: resizing with geometry") << "resizeToItem" << "320x240+50+50" << "resizeItem.qml" << sizeOrInvalid(100, 50) << sizeOrInvalid(100, 50); } /* - A root Item will get put into a Window depending on config (implementations in tools/qml/ResizeItemToWindow.qml and ResizeWindowToItem.qml). - The window system will enforce a minimum size. - In the default configuration, the root Item should then get resized to fit (QTBUG-114068 / QTBUG-116753). - In resizeToItem configuration, if the item width/height are not set, the window would try to be 0x0, but the window system won't allow it. - This also tests the `--qwindowgeometry` argument: with the default config, the item should be resized to fit, but not with `-c resizeToItem`. */ void tst_qml::itemAndWindowGeometry() { #ifdef Q_OS_WIN QSKIP("console.info does not go to stderr on Windows."); #endif QFETCH(QString, config); QFETCH(QString, geometry); QFETCH(QString, qmlfile); QFETCH(QSize, expectedWindowSize); QFETCH(QSize, expectedContentSize); QStringList args; if (!config.isEmpty()) args << "-c" << config; if (!geometry.isEmpty()) args << "--qwindowgeometry" << geometry; args << testFile(qmlfile); QProcess qml; qml.start(qmlPath, args); QVERIFY(qml.waitForFinished()); QCOMPARE(qml.exitStatus(), QProcess::NormalExit); const QByteArray output = qml.readAllStandardError(); const auto sizeLineIndex = output.lastIndexOf("window"); QCOMPARE_GE(sizeLineIndex, 0); const auto newlineIndex = output.indexOf('\n', sizeLineIndex); QCOMPARE_GT(newlineIndex, sizeLineIndex); // expect a line like "window 120 120 content 120 120" const auto sizes = output.sliced(sizeLineIndex, newlineIndex - sizeLineIndex).split(' '); QCOMPARE_GE(sizes.size(), 6); QCOMPARE(sizes[0], "window"); QCOMPARE(sizes[3], "content"); const QSize windowSize(sizes[1].toInt(), sizes[2].toInt()); const QSize contentSize(sizes[4].toInt(), sizes[5].toInt()); qCDebug(lcQml) << sizes << "window" << windowSize << "expect" << expectedWindowSize << "content" << contentSize << "expect" << expectedContentSize; QVERIFY(!windowSize.isEmpty()); if (config != "resizeToItem") { // default config: // ResizeItemToWindow.qml should have resized the item to its window QCOMPARE(contentSize, windowSize); } // windowSize can be off-by-one on hidpi (e.g. QT_SCALE_FACTOR=2 on xcb); // perhaps that's a bug somewhere, but so far we aren't testing hidpi on CI if (expectedWindowSize.isValid()) QCOMPARE(windowSize, expectedWindowSize); if (expectedContentSize.isValid()) QCOMPARE(contentSize, expectedContentSize); } QTEST_MAIN(tst_qml) #include