File indexing completed on 2024-06-23 10:37:24

0001 /*
0002     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0003     SPDX-FileCopyrightText: 2007, 2009 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #undef QT_USE_FAST_OPERATOR_PLUS
0009 
0010 #include "krununittest.h"
0011 
0012 #include <QSignalSpy>
0013 #include <QTest>
0014 
0015 QTEST_GUILESS_MAIN(KRunUnitTest)
0016 
0017 #include <QStandardPaths>
0018 
0019 #include "kiotesthelper.h" // createTestFile etc.
0020 #include "krun.h"
0021 #include <KApplicationTrader>
0022 #include <KConfigGroup>
0023 #include <KDesktopFile>
0024 #include <KProcess>
0025 #include <KService>
0026 #include <KSharedConfig>
0027 #include <KShell>
0028 #include <desktopexecparser.h>
0029 #include <global.h>
0030 #include <kprotocolinfo.h>
0031 #ifdef Q_OS_UNIX
0032 #include <signal.h> // kill
0033 #endif
0034 
0035 void KRunUnitTest::initTestCase()
0036 {
0037     QStandardPaths::setTestModeEnabled(true);
0038 
0039     qputenv("PATH", QByteArray(qgetenv("PATH") + QFile::encodeName(QDir::listSeparator() + QCoreApplication::applicationDirPath())));
0040 
0041     // testProcessDesktopExec works only if your terminal application is set to "xterm"
0042     KConfigGroup cg(KSharedConfig::openConfig(), "General");
0043     cg.writeEntry("TerminalApplication", "true");
0044 
0045     // We just want to test if the command is properly constructed
0046     m_pseudoTerminalProgram = QStandardPaths::findExecutable(QStringLiteral("true"));
0047     QVERIFY(!m_pseudoTerminalProgram.isEmpty());
0048 
0049     // Determine the full path of sh - this is needed to make testProcessDesktopExecNoFile()
0050     // pass on systems where QStandardPaths::findExecutable("sh") is not "/bin/sh".
0051     m_sh = QStandardPaths::findExecutable(QStringLiteral("sh"));
0052     if (m_sh.isEmpty()) {
0053         m_sh = QStringLiteral("/bin/sh");
0054     }
0055 }
0056 
0057 void KRunUnitTest::cleanupTestCase()
0058 {
0059     std::for_each(m_filesToRemove.begin(), m_filesToRemove.end(), [](const QString &f) {
0060         QFile::remove(f);
0061     });
0062 }
0063 
0064 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 71)
0065 class KRunImpl : public KRun
0066 {
0067 public:
0068     KRunImpl(const QUrl &url)
0069         : KRun(url, nullptr, false)
0070         , m_errCode(-1)
0071     {
0072     }
0073 
0074     void foundMimeType(const QString &type) override
0075     {
0076         m_mimeType = type;
0077         // don't call KRun::foundMimeType, we don't want to start an app ;-)
0078         setFinished(true);
0079     }
0080 
0081     void handleInitError(int kioErrorCode, const QString &err) override
0082     {
0083         m_errCode = kioErrorCode;
0084         m_errText = err;
0085     }
0086 
0087     QString mimeTypeFound() const
0088     {
0089         return m_mimeType;
0090     }
0091     int errorCode() const
0092     {
0093         return m_errCode;
0094     }
0095     QString errorText() const
0096     {
0097         return m_errText;
0098     }
0099 
0100 private:
0101     int m_errCode;
0102     QString m_errText;
0103     QString m_mimeType;
0104 };
0105 
0106 void KRunUnitTest::testMimeTypeFile()
0107 {
0108     const QString filePath = homeTmpDir() + "file";
0109     createTestFile(filePath, true);
0110     KRunImpl *krun = new KRunImpl(QUrl::fromLocalFile(filePath));
0111     krun->setAutoDelete(false);
0112     QSignalSpy spyFinished(krun, &KRun::finished);
0113     QVERIFY(spyFinished.wait(1000));
0114     QCOMPARE(krun->mimeTypeFound(), QString::fromLatin1("text/plain"));
0115     delete krun;
0116 }
0117 
0118 void KRunUnitTest::testMimeTypeDirectory()
0119 {
0120     const QString dir = homeTmpDir() + "dir";
0121     createTestDirectory(dir);
0122     KRunImpl *krun = new KRunImpl(QUrl::fromLocalFile(dir));
0123     QSignalSpy spyFinished(krun, &KRun::finished);
0124     QVERIFY(spyFinished.wait(1000));
0125     QCOMPARE(krun->mimeTypeFound(), QString::fromLatin1("inode/directory"));
0126 }
0127 
0128 void KRunUnitTest::testMimeTypeBrokenLink()
0129 {
0130     const QString dir = homeTmpDir() + "dir";
0131     createTestDirectory(dir);
0132     KRunImpl *krun = new KRunImpl(QUrl::fromLocalFile(dir + "/testlink"));
0133     QSignalSpy spyError(krun, &KRun::error);
0134     QSignalSpy spyFinished(krun, &KRun::finished);
0135     QVERIFY(spyFinished.wait(1000));
0136     QVERIFY(krun->mimeTypeFound().isEmpty());
0137     QCOMPARE(spyError.count(), 1);
0138     QCOMPARE(krun->errorCode(), int(KIO::ERR_DOES_NOT_EXIST));
0139     QVERIFY(krun->errorText().contains("does not exist"));
0140     QTest::qWait(100); // let auto-deletion proceed.
0141 }
0142 
0143 void KRunUnitTest::testMimeTypeDoesNotExist() // ported to OpenUrlJobTest::nonExistingFile()
0144 {
0145     KRunImpl *krun = new KRunImpl(QUrl::fromLocalFile(QStringLiteral("/does/not/exist")));
0146     QSignalSpy spyError(krun, &KRun::error);
0147     QSignalSpy spyFinished(krun, &KRun::finished);
0148     QVERIFY(spyFinished.wait(1000));
0149     QVERIFY(krun->mimeTypeFound().isEmpty());
0150     QCOMPARE(spyError.count(), 1);
0151     QTest::qWait(100); // let auto-deletion proceed.
0152 }
0153 
0154 #endif
0155 
0156 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 71)
0157 static const char s_tempServiceName[] = "krununittest_service.desktop";
0158 
0159 static void createSrcFile(const QString path)
0160 {
0161     QFile srcFile(path);
0162     QVERIFY2(srcFile.open(QFile::WriteOnly), qPrintable(srcFile.errorString()));
0163     srcFile.write("Hello world\n");
0164 }
0165 #endif
0166 
0167 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 71)
0168 void KRunUnitTest::KRunRunService_data()
0169 {
0170     QTest::addColumn<bool>("tempFile");
0171     QTest::addColumn<bool>("useRunApplication");
0172 
0173     QTest::newRow("standard") << false << false;
0174     QTest::newRow("tempfile") << true << false;
0175     QTest::newRow("runApp") << false << true;
0176     QTest::newRow("runApp_tempfile") << true << true;
0177 }
0178 #endif
0179 
0180 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 71)
0181 void KRunUnitTest::KRunRunService()
0182 {
0183     QFETCH(bool, tempFile);
0184     QFETCH(bool, useRunApplication);
0185 
0186     // Given a service desktop file and a source file
0187     const QString path = createTempService();
0188     // KService::Ptr service = KService::serviceByDesktopPath(s_tempServiceName);
0189     // QVERIFY(service);
0190     KService service(path);
0191     QTemporaryDir tempDir;
0192     const QString srcDir = tempDir.path();
0193     const QString srcFile = srcDir + "/srcfile";
0194     createSrcFile(srcFile);
0195     QVERIFY(QFile::exists(srcFile));
0196     QList<QUrl> urls;
0197     urls.append(QUrl::fromLocalFile(srcFile));
0198 
0199     // When calling KRun::runService or KRun::runApplication
0200     qint64 pid = useRunApplication ? KRun::runApplication(service, urls, nullptr, tempFile ? KRun::RunFlags(KRun::DeleteTemporaryFiles) : KRun::RunFlags())
0201                                    : KRun::runService(service, urls, nullptr, tempFile); // DEPRECATED
0202 
0203     // Then the service should be executed (which copies the source file to "dest")
0204     QVERIFY(pid != 0);
0205     const QString dest = srcDir + "/dest";
0206     QTRY_VERIFY(QFile::exists(dest));
0207     QVERIFY(QFile::exists(srcFile)); // if tempfile is true, kioexec will delete it... in 3 minutes.
0208 
0209     // All done, clean up.
0210     QVERIFY(QFile::remove(dest));
0211 #ifdef Q_OS_UNIX
0212     ::kill(pid, SIGTERM);
0213 #endif
0214 }
0215 
0216 QString KRunUnitTest::createTempService()
0217 {
0218     // fakeservice: deleted and recreated by testKSycocaUpdate, don't use in other tests
0219     const QString fileName = s_tempServiceName;
0220     // bool mustUpdateKSycoca = !KService::serviceByDesktopPath(fileName);
0221     const QString fakeService = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + fileName;
0222     if (!QFile::exists(fakeService)) {
0223         // mustUpdateKSycoca = true;
0224         KDesktopFile file(fakeService);
0225         KConfigGroup group = file.desktopGroup();
0226         group.writeEntry("Name", "KRunUnittestService");
0227         group.writeEntry("Type", "Service");
0228 #ifdef Q_OS_WIN
0229         group.writeEntry("Exec", "copy.exe %f %d/dest");
0230 #else
0231         group.writeEntry("Exec", "cp %f %d/dest");
0232 #endif
0233         file.sync();
0234         QFile f(fakeService);
0235         f.setPermissions(f.permissions() | QFile::ExeOwner | QFile::ExeUser);
0236     }
0237     m_filesToRemove.append(fakeService);
0238     return fakeService;
0239 }
0240 
0241 #endif
0242 
0243 #include "moc_krununittest.cpp"