File indexing completed on 2024-04-28 05:50:34

0001 /*
0002     SPDX-FileCopyrightText: 2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "PartTest.h"
0009 
0010 // Qt
0011 #include <QDialog>
0012 #include <QFileInfo>
0013 #include <QLabel>
0014 #include <QTimer>
0015 #include <QVBoxLayout>
0016 // KDE
0017 #include <KPluginFactory>
0018 #include <KPtyDevice>
0019 #include <KPtyProcess>
0020 #include <QTest>
0021 
0022 // Konsole
0023 #include "../Pty.h"
0024 
0025 using namespace Konsole;
0026 
0027 void PartTest::initTestCase()
0028 {
0029     /* Try to test against build konsolepart, so move directory containing
0030       executable to front of libraryPaths.  KPluginLoader should find the
0031       part first in the build dir over the system installed ones.
0032       I believe the CI installs first and then runs the test so the other
0033       paths can not be removed.
0034     */
0035     const auto libraryPaths = QCoreApplication::libraryPaths();
0036     auto buildPath = libraryPaths.last();
0037     QCoreApplication::removeLibraryPath(buildPath);
0038     // konsolepart.so is in ../autotests/
0039     if (buildPath.endsWith(QStringLiteral("/autotests"))) {
0040         buildPath.chop(10);
0041     }
0042     QCoreApplication::addLibraryPath(buildPath);
0043 }
0044 
0045 void PartTest::testFdShell()
0046 {
0047     // Maybe https://bugreports.qt.io/browse/QTBUG-82351 ???
0048     QSKIP("Skipping on CI suse_tumbelweed_qt64", SkipSingle);
0049     return;
0050 
0051     testFd(true);
0052 }
0053 
0054 void PartTest::testFdStandalone()
0055 {
0056     testFd(false);
0057 }
0058 
0059 void PartTest::testFd(bool runShell)
0060 {
0061     // find ping
0062     QStringList pingList;
0063     QFileInfo info;
0064     QString pingExe;
0065     pingList << QStringLiteral("/bin/ping") << QStringLiteral("/sbin/ping");
0066     for (int i = 0; i < pingList.size(); ++i) {
0067         info.setFile(pingList.at(i));
0068         if (info.exists() && info.isExecutable()) {
0069             pingExe = pingList.at(i);
0070         }
0071     }
0072 
0073     if (pingExe.isEmpty()) {
0074         QSKIP("ping command not found.");
0075         return;
0076     }
0077 
0078     // create a Konsole part and attempt to connect to it
0079     KParts::Part *terminalPart = createPart();
0080     if (terminalPart == nullptr) { // not found
0081         QFAIL("konsolepart not found.");
0082         return;
0083     }
0084 
0085     // start a pty process
0086     KPtyProcess ptyProcess;
0087     ptyProcess.setProgram(pingExe, QStringList() << QStringLiteral("localhost"));
0088     ptyProcess.setPtyChannels(KPtyProcess::AllChannels);
0089     ptyProcess.start();
0090     QVERIFY(ptyProcess.waitForStarted());
0091 
0092     int fd = ptyProcess.pty()->masterFd();
0093 
0094     // test that the 2nd argument of openTeletype is optional,
0095     // to run without shell
0096     if (runShell) {
0097         // connect to an existing pty
0098         bool result = QMetaObject::invokeMethod(terminalPart, "openTeletype", Qt::DirectConnection, Q_ARG(int, fd));
0099         QVERIFY(result);
0100     } else {
0101         // test the optional 2nd argument of openTeletype, to run without shell
0102         bool result = QMetaObject::invokeMethod(terminalPart, "openTeletype", Qt::DirectConnection, Q_ARG(int, fd), Q_ARG(bool, false));
0103         QVERIFY(result);
0104     }
0105 
0106     // suspend the KPtyDevice so that the embedded terminal gets a chance to
0107     // read from the pty.  Otherwise the KPtyDevice will simply read everything
0108     // as soon as it becomes available and the terminal will not display any output
0109     ptyProcess.pty()->setSuspended(true);
0110 
0111     QPointer<QDialog> dialog = new QDialog();
0112     auto layout = new QVBoxLayout(dialog.data());
0113     auto explanation = runShell ? QStringLiteral("Output of 'ping localhost' should appear in a terminal below for 5 seconds")
0114                                 : QStringLiteral("Output of 'ping localhost' should appear standalone below for 5 seconds");
0115     layout->addWidget(new QLabel(explanation));
0116     layout->addWidget(terminalPart->widget());
0117     QTimer::singleShot(5000, dialog.data(), &QDialog::close);
0118     dialog.data()->exec();
0119 
0120     delete terminalPart;
0121     delete dialog.data();
0122     ptyProcess.kill();
0123     ptyProcess.waitForFinished(1000);
0124 }
0125 
0126 KParts::Part *PartTest::createPart()
0127 {
0128     const KPluginMetaData metaData(QStringLiteral("konsolepart"));
0129     Q_ASSERT(metaData.isValid());
0130 
0131     KPluginFactory::Result<KParts::Part> result = KPluginFactory::instantiatePlugin<KParts::Part>(metaData, this);
0132     Q_ASSERT(result);
0133 
0134     return result.plugin;
0135 }
0136 
0137 QTEST_MAIN(PartTest)
0138 
0139 #include "moc_PartTest.cpp"