File indexing completed on 2024-05-12 05:38:09

0001 /*
0002     SPDX-FileCopyrightText: 2023 Fushan Wen <qydwhotmail@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #define QT_FORCE_ASSERTS 1
0008 
0009 #include <QProcess>
0010 #include <qpa/qplatformnativeinterface.h>
0011 
0012 #include <wayland-client-core.h>
0013 
0014 #include "common.h"
0015 #include "waylandtasksmodel.h"
0016 
0017 using namespace TaskManager;
0018 using namespace Qt::StringLiterals;
0019 
0020 class WaylandTasksModelTest : public QObject
0021 {
0022     Q_OBJECT
0023 
0024 private Q_SLOTS:
0025     void initTestCase();
0026     void cleanupTestCase();
0027 
0028     void test_openCloseWindow();
0029     void test_modelData();
0030     void test_fullscreen();
0031     void test_geometry();
0032     void test_stackingOrder();
0033     void test_modelDataFromDesktopFile();
0034 
0035     void test_request();
0036 
0037     // plasmashell runs out of file descriptors when emacs visits lots of files
0038     void test_bug478831();
0039 
0040 private:
0041     WaylandTasksModel m_model;
0042 };
0043 
0044 void WaylandTasksModelTest::initTestCase()
0045 {
0046     TestUtils::initTestCase();
0047 
0048     if (!KWindowSystem::isPlatformWayland()) {
0049         QSKIP("Test is not running on Wayland.");
0050     }
0051 
0052     QGuiApplication::setQuitOnLastWindowClosed(false);
0053 
0054     QStandardPaths::setTestModeEnabled(true);
0055 
0056     const QString applicationDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + QStringLiteral("applications");
0057     QDir dir;
0058     if (!dir.exists(applicationDir)) {
0059         dir.mkpath(applicationDir);
0060     }
0061 
0062     QPlatformNativeInterface *const native = qGuiApp->platformNativeInterface();
0063     wl_display_roundtrip(static_cast<struct wl_display *>(native->nativeResourceForIntegration("wl_display")));
0064 }
0065 
0066 void WaylandTasksModelTest::cleanupTestCase()
0067 {
0068     TestUtils::cleanupTestCase();
0069 }
0070 
0071 void WaylandTasksModelTest::test_openCloseWindow()
0072 {
0073     TestUtils::testOpenCloseWindow(m_model);
0074 }
0075 
0076 void WaylandTasksModelTest::test_modelData()
0077 {
0078     const QString title = QStringLiteral("__testwindow__%1").arg(QDateTime::currentDateTime().toString());
0079     QModelIndex index;
0080     auto window = TestUtils::createSingleWindow(m_model, title, index);
0081 
0082     // See WaylandTasksModel::data for available roles
0083     // Icon is unavailable on Wayland
0084 
0085     QTRY_COMPARE(index.data(AbstractTasksModel::WinIdList).toList().size(), 1);
0086     QVERIFY(index.data(AbstractTasksModel::MimeType).toString().startsWith(QLatin1String("windowsystem/winid")));
0087 
0088     QTRY_VERIFY(index.data(AbstractTasksModel::IsWindow).toBool());
0089     QTRY_VERIFY(index.data(AbstractTasksModel::IsActive).toBool());
0090 
0091     QTRY_VERIFY(index.data(AbstractTasksModel::IsClosable).toBool());
0092     QTRY_VERIFY(index.data(AbstractTasksModel::IsMovable).toBool());
0093     QTRY_VERIFY(index.data(AbstractTasksModel::IsResizable).toBool());
0094     QTRY_VERIFY(index.data(AbstractTasksModel::IsMaximizable).toBool());
0095     QTRY_VERIFY(!index.data(AbstractTasksModel::IsMaximized).toBool());
0096     QTRY_VERIFY(index.data(AbstractTasksModel::IsMinimizable).toBool());
0097     QTRY_VERIFY(!index.data(AbstractTasksModel::IsKeepAbove).toBool());
0098     QTRY_VERIFY(!index.data(AbstractTasksModel::IsKeepBelow).toBool());
0099     QTRY_VERIFY(index.data(AbstractTasksModel::IsFullScreenable).toBool());
0100     QTRY_VERIFY(!index.data(AbstractTasksModel::IsFullScreen).toBool());
0101     QTRY_VERIFY(!index.data(AbstractTasksModel::IsShadeable).toBool()); // It's intentionally not implemented on wayland
0102     QTRY_VERIFY(!index.data(AbstractTasksModel::IsShaded).toBool());
0103     QTRY_VERIFY(index.data(AbstractTasksModel::IsVirtualDesktopsChangeable).toBool());
0104     QTRY_VERIFY(!index.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool());
0105 
0106     // Due to window decoration, the size of a window can't be determined accurately
0107     const QRect screenGeometry = index.data(AbstractTasksModel::ScreenGeometry).toRect();
0108     QVERIFY(screenGeometry.width() > 0 && screenGeometry.height() > 0);
0109 
0110     QTRY_VERIFY(!index.data(AbstractTasksModel::IsDemandingAttention).toBool());
0111     QTRY_VERIFY(!index.data(AbstractTasksModel::SkipTaskbar).toBool());
0112     QTRY_VERIFY(!index.data(AbstractTasksModel::SkipPager).toBool());
0113     // AbstractTasksModel::AppPid
0114 
0115     QVERIFY(index.data(AbstractTasksModel::CanLaunchNewInstance).toBool());
0116 }
0117 
0118 void WaylandTasksModelTest::test_fullscreen()
0119 {
0120     TestUtils::testFullscreen(m_model);
0121 }
0122 
0123 void WaylandTasksModelTest::test_geometry()
0124 {
0125     TestUtils::testGeometry(m_model);
0126 }
0127 
0128 void WaylandTasksModelTest::test_stackingOrder()
0129 {
0130     TestUtils::testStackingOrder(m_model);
0131 }
0132 
0133 void WaylandTasksModelTest::test_modelDataFromDesktopFile()
0134 {
0135     TestUtils::testModelDataFromDesktopFile(m_model);
0136 }
0137 
0138 void WaylandTasksModelTest::test_request()
0139 {
0140     TestUtils::testRequest(m_model);
0141 }
0142 
0143 void WaylandTasksModelTest::test_bug478831()
0144 {
0145     QProcess lsof;
0146     lsof.setProgram(u"lsof"_s);
0147     lsof.setArguments({u"-p"_s, QString::number(getpid())});
0148     lsof.setReadChannel(QProcess::StandardOutput);
0149     lsof.start(QIODeviceBase::ReadOnly);
0150     lsof.waitForFinished();
0151     const QByteArray fdCountBeforeBA = lsof.readAllStandardOutput();
0152     const int fdCountBefore = fdCountBeforeBA.count('\n');
0153 
0154     QSignalSpy rowsInsertedSpy(&m_model, &AbstractWindowTasksModel::rowsInserted);
0155 
0156     QProcess gtkWindow;
0157     gtkWindow.setProgram(u"python3"_s);
0158     QProcessEnvironment newEnv = QProcessEnvironment::systemEnvironment();
0159     newEnv.insert(u"GDK_BACKEND"_s, u"x11"_s);
0160     newEnv.insert(u"NO_AT_BRIDGE"_s, u"1"_s); // Otherwise following tests will fail
0161     gtkWindow.setProcessEnvironment(newEnv);
0162     gtkWindow.setArguments({QFINDTESTDATA(u"data/windows/bug478831.py"_s)});
0163     gtkWindow.start(QIODeviceBase::ReadOnly);
0164 
0165     if (rowsInsertedSpy.empty()) {
0166         QVERIFY(rowsInsertedSpy.wait());
0167     }
0168     const auto results = m_model.match(m_model.index(0, 0), Qt::DisplayRole, u"flash"_s);
0169     QCOMPARE(results.size(), 1);
0170     QTest::qWait(10000);
0171 
0172     lsof.start(QIODeviceBase::ReadOnly);
0173     lsof.waitForFinished();
0174     const QByteArray fdCountAfterBA = lsof.readAllStandardOutput();
0175     const int fdCountAfter = fdCountAfterBA.count('\n');
0176 
0177     gtkWindow.terminate();
0178     gtkWindow.waitForFinished();
0179     qDebug() << fdCountBefore << fdCountAfter << getpid();
0180     QVERIFY(fdCountBefore > 10);
0181     QVERIFY(fdCountAfter > 10);
0182     QVERIFY(fdCountAfter - fdCountBefore < 10);
0183 }
0184 
0185 QTEST_MAIN(WaylandTasksModelTest)
0186 
0187 #include "waylandtasksmodeltest.moc"