File indexing completed on 2025-01-19 12:48:39
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "openurljobtest.h" 0009 #include "openurljob.h" 0010 #include <KApplicationTrader> 0011 #include <kprocessrunner_p.h> 0012 0013 #include "kiotesthelper.h" // createTestFile etc. 0014 #include "mockcoredelegateextensions.h" 0015 #include "mockguidelegateextensions.h" 0016 0017 #include <KConfigGroup> 0018 #include <KDesktopFile> 0019 #include <KJobUiDelegate> 0020 #include <KService> 0021 0022 #ifdef Q_OS_UNIX 0023 #include <signal.h> // kill 0024 #endif 0025 0026 #include <KSharedConfig> 0027 #include <QStandardPaths> 0028 #include <QTemporaryFile> 0029 #include <QTest> 0030 0031 QTEST_GUILESS_MAIN(OpenUrlJobTest) 0032 0033 extern KSERVICE_EXPORT int ksycoca_ms_between_checks; 0034 extern bool openurljob_force_use_browserapp_kdeglobals; // From openurljob.cpp 0035 0036 static const char s_tempServiceName[] = "openurljobtest_service.desktop"; 0037 0038 void OpenUrlJobTest::initTestCase() 0039 { 0040 QStandardPaths::setTestModeEnabled(true); 0041 0042 // Ensure no leftovers from other tests 0043 QDir(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)).removeRecursively(); 0044 // (including a mimeapps.list file) 0045 // Don't remove ConfigLocation completely, it's useful when enabling debug output with kdebugsettings --test-mode 0046 const QString mimeApps = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/mimeapps.list"); 0047 QFile::remove(mimeApps); 0048 0049 ksycoca_ms_between_checks = 0; // need it to check the ksycoca mtime 0050 m_fakeService = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1Char('/') + s_tempServiceName; 0051 // not using %d because of remote urls 0052 const QByteArray cmd = QByteArray("echo %u > " + QFile::encodeName(m_tempDir.path()) + "/dest"); 0053 writeApplicationDesktopFile(m_fakeService, cmd); 0054 m_fakeService = QFileInfo(m_fakeService).canonicalFilePath(); 0055 m_filesToRemove.append(m_fakeService); 0056 0057 // Ensure our service is the preferred one 0058 KConfig mimeAppsCfg(mimeApps); 0059 KConfigGroup grp = mimeAppsCfg.group("Default Applications"); 0060 grp.writeEntry("text/plain", s_tempServiceName); 0061 grp.writeEntry("text/html", s_tempServiceName); 0062 grp.sync(); 0063 0064 // "text/plain" encompasses all scripts (shell, python, perl) 0065 KService::Ptr preferredTextEditor = KApplicationTrader::preferredService(QStringLiteral("text/plain")); 0066 QVERIFY(preferredTextEditor); 0067 QCOMPARE(preferredTextEditor->entryPath(), m_fakeService); 0068 0069 // As used for preferredService 0070 QVERIFY(KService::serviceByDesktopName("openurljobtest_service")); 0071 0072 ksycoca_ms_between_checks = 5000; // all done, speed up again 0073 } 0074 0075 void OpenUrlJobTest::cleanupTestCase() 0076 { 0077 for (const QString &file : std::as_const(m_filesToRemove)) { 0078 QFile::remove(file); 0079 }; 0080 } 0081 0082 void OpenUrlJobTest::init() 0083 { 0084 QFile::remove(m_tempDir.path() + "/dest"); 0085 } 0086 0087 static void createSrcFile(const QString &path) 0088 { 0089 QFile srcFile(path); 0090 QVERIFY2(srcFile.open(QFile::WriteOnly), qPrintable(srcFile.errorString())); 0091 srcFile.write("Hello world\n"); 0092 } 0093 0094 static QString readFile(const QString &path) 0095 { 0096 QFile file(path); 0097 file.open(QIODevice::ReadOnly); 0098 return QString::fromLocal8Bit(file.readAll()).trimmed(); 0099 } 0100 0101 void OpenUrlJobTest::startProcess_data() 0102 { 0103 QTest::addColumn<QString>("mimeType"); 0104 QTest::addColumn<QString>("fileName"); 0105 0106 // Known MIME type 0107 QTest::newRow("text_file") << "text/plain" 0108 << "srcfile.txt"; 0109 QTest::newRow("directory_file") << "application/x-desktop" 0110 << ".directory"; 0111 QTest::newRow("desktop_file_link") << "application/x-desktop" 0112 << "srcfile.txt"; 0113 QTest::newRow("desktop_file_link_preferred_service") << "application/x-desktop" 0114 << "srcfile.html"; 0115 QTest::newRow("non_executable_script_running_not_allowed") << "application/x-shellscript" 0116 << "srcfile.sh"; 0117 QTest::newRow("executable_script_running_not_allowed") << "application/x-shellscript" 0118 << "srcfile.sh"; 0119 0120 // Require MIME type determination 0121 QTest::newRow("text_file_no_mimetype") << QString() << "srcfile.txt"; 0122 QTest::newRow("directory_file_no_mimetype") << QString() << ".directory"; 0123 } 0124 0125 void OpenUrlJobTest::startProcess() 0126 { 0127 QFETCH(QString, mimeType); 0128 QFETCH(QString, fileName); 0129 0130 // Given a file to open 0131 QTemporaryDir tempDir; 0132 const QString srcDir = tempDir.path(); 0133 const QString srcFile = srcDir + QLatin1Char('/') + fileName; 0134 createSrcFile(srcFile); 0135 QVERIFY(QFile::exists(srcFile)); 0136 const bool isLink = QByteArray(QTest::currentDataTag()).startsWith("desktop_file_link"); 0137 QUrl url = QUrl::fromLocalFile(srcFile); 0138 if (isLink) { 0139 const QString desktopFilePath = srcDir + QLatin1String("/link.desktop"); 0140 KDesktopFile linkDesktopFile(desktopFilePath); 0141 linkDesktopFile.desktopGroup().writeEntry("Type", "Link"); 0142 linkDesktopFile.desktopGroup().writeEntry("URL", url); 0143 const bool linkHasPreferredService = QByteArray(QTest::currentDataTag()) == "desktop_file_link_preferred_service"; 0144 if (linkHasPreferredService) { 0145 linkDesktopFile.desktopGroup().writeEntry("X-KDE-LastOpenedWith", "openurljobtest_service"); 0146 } 0147 url = QUrl::fromLocalFile(desktopFilePath); 0148 } 0149 if (QByteArray(QTest::currentDataTag()).startsWith("executable")) { 0150 QFile file(srcFile); 0151 QVERIFY(file.setPermissions(QFile::ExeUser | file.permissions())); 0152 // Note however that running executables is not allowed by the OpenUrlJob below 0153 // so this will end up opening it as a text file anyway. 0154 } 0155 0156 // When running a OpenUrlJob 0157 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, mimeType, this); 0158 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0159 0160 // Then m_fakeService should be executed, since it's associated with text/plain 0161 // We can find out that it was executed because it writes to "dest". 0162 const QString dest = m_tempDir.path() + "/dest"; 0163 QTRY_VERIFY2(QFile::exists(dest), qPrintable(dest)); 0164 QCOMPARE(readFile(dest), srcFile); 0165 } 0166 0167 void OpenUrlJobTest::noServiceNoHandler() 0168 { 0169 QTemporaryFile tempFile; 0170 QVERIFY(tempFile.open()); 0171 const QUrl url = QUrl::fromLocalFile(tempFile.fileName()); 0172 const QString mimeType = QStringLiteral("application/x-zerosize"); 0173 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, mimeType, this); 0174 // This is going to try QDesktopServices::openUrl which will fail because we are no QGuiApplication, good. 0175 QTest::ignoreMessage(QtWarningMsg, "QDesktopServices::openUrl: Application is not a GUI application"); 0176 QVERIFY(!job->exec()); 0177 QCOMPARE(job->error(), KJob::UserDefinedError); 0178 QCOMPARE(job->errorString(), QStringLiteral("Failed to open the file.")); 0179 } 0180 0181 void OpenUrlJobTest::invalidUrl() 0182 { 0183 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl(":/"), QStringLiteral("text/plain"), this); 0184 QVERIFY(!job->exec()); 0185 QCOMPARE(job->error(), KIO::ERR_MALFORMED_URL); 0186 QCOMPARE(job->errorString(), QStringLiteral("Malformed URL\nRelative URL's path component contains ':' before any '/'; source was \":/\"; path = \":/\"")); 0187 0188 QUrl u; 0189 u.setPath(QStringLiteral("/pathonly")); 0190 KIO::OpenUrlJob *job2 = new KIO::OpenUrlJob(u, QStringLiteral("text/plain"), this); 0191 QVERIFY(!job2->exec()); 0192 QCOMPARE(job2->error(), KIO::ERR_MALFORMED_URL); 0193 QCOMPARE(job2->errorString(), QStringLiteral("Malformed URL\n/pathonly")); 0194 } 0195 0196 void OpenUrlJobTest::refuseRunningLocalBinaries_data() 0197 { 0198 QTest::addColumn<QString>("mimeType"); 0199 0200 // Executables under e.g. /usr/bin/ can be either of these two MIME types 0201 // see https://gitlab.freedesktop.org/xdg/shared-mime-info/-/issues/11 0202 QTest::newRow("x-sharedlib") << "application/x-sharedlib"; 0203 QTest::newRow("x-executable") << "application/x-executable"; 0204 0205 QTest::newRow("msdos_executable") << "application/x-ms-dos-executable"; 0206 } 0207 0208 void OpenUrlJobTest::refuseRunningLocalBinaries() 0209 { 0210 QFETCH(QString, mimeType); 0211 0212 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()), mimeType, this); 0213 QVERIFY(!job->exec()); 0214 QCOMPARE(job->error(), KJob::UserDefinedError); 0215 QVERIFY2(job->errorString().contains("For security reasons, launching executables is not allowed in this context."), qPrintable(job->errorString())); 0216 } 0217 0218 void OpenUrlJobTest::refuseRunningRemoteNativeExecutables_data() 0219 { 0220 QTest::addColumn<QString>("mimeType"); 0221 QTest::newRow("x-sharedlib") << "application/x-sharedlib"; 0222 QTest::newRow("x-executable") << "application/x-executable"; 0223 } 0224 0225 void OpenUrlJobTest::refuseRunningRemoteNativeExecutables() 0226 { 0227 QFETCH(QString, mimeType); 0228 0229 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl("protocol://host/path/exe"), mimeType, this); 0230 job->setRunExecutables(true); // even with this enabled, an error will occur 0231 QVERIFY(!job->exec()); 0232 QCOMPARE(job->error(), KJob::UserDefinedError); 0233 QVERIFY2(job->errorString().contains("is located on a remote filesystem. For safety reasons it will not be started"), qPrintable(job->errorString())); 0234 } 0235 0236 KCONFIGCORE_EXPORT void loadUrlActionRestrictions(const KConfigGroup &cg); 0237 0238 void OpenUrlJobTest::notAuthorized() 0239 { 0240 KConfigGroup cg(KSharedConfig::openConfig(), "KDE URL Restrictions"); 0241 cg.writeEntry("rule_count", 1); 0242 cg.writeEntry("rule_1", QStringList{"open", {}, {}, {}, "file", "", "", "false"}); 0243 cg.sync(); 0244 loadUrlActionRestrictions(cg); 0245 0246 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl("file:///"), QStringLiteral("text/plain"), this); 0247 QVERIFY(!job->exec()); 0248 QCOMPARE(job->error(), KIO::ERR_ACCESS_DENIED); 0249 QCOMPARE(job->errorString(), QStringLiteral("Access denied to file:///.")); 0250 0251 cg.deleteEntry("rule_1"); 0252 cg.deleteEntry("rule_count"); 0253 cg.sync(); 0254 loadUrlActionRestrictions(cg); 0255 } 0256 0257 void OpenUrlJobTest::runScript_data() 0258 { 0259 QTest::addColumn<QString>("mimeType"); 0260 0261 // All text-based scripts inherit text/plain and application/x-executable, no need to test 0262 // all flavours (python, perl, lua, awk ...etc), this sample should be enough 0263 QTest::newRow("shellscript") << "application/x-shellscript"; 0264 QTest::newRow("pythonscript") << "text/x-python"; 0265 QTest::newRow("javascript") << "application/javascript"; 0266 } 0267 0268 void OpenUrlJobTest::runScript() 0269 { 0270 #ifdef Q_OS_UNIX 0271 QFETCH(QString, mimeType); 0272 0273 // Given an executable shell script that copies "src" to "dest" 0274 QTemporaryDir tempDir; 0275 const QString dir = tempDir.path(); 0276 createSrcFile(dir + QLatin1String("/src")); 0277 const QString scriptFile = dir + QLatin1String("/script.sh"); 0278 QFile file(scriptFile); 0279 QVERIFY(file.open(QIODevice::WriteOnly)); 0280 file.write("#!/bin/sh\ncp src dest"); 0281 file.close(); 0282 QVERIFY(file.setPermissions(QFile::ExeUser | file.permissions())); 0283 0284 // When using OpenUrlJob to run the script 0285 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(scriptFile), mimeType, this); 0286 job->setRunExecutables(true); // startProcess and refuseRunningLocalBinaries test the case where this isn't set 0287 0288 // Then it works :-) 0289 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0290 QTRY_VERIFY(QFileInfo::exists(dir + QLatin1String("/dest"))); // TRY because CommandLineLauncherJob finishes immediately 0291 #endif 0292 } 0293 0294 void OpenUrlJobTest::runNativeExecutable_data() 0295 { 0296 QTest::addColumn<QString>("mimeType"); 0297 QTest::addColumn<bool>("withHandler"); 0298 QTest::addColumn<bool>("handlerRetVal"); 0299 0300 QTest::newRow("no_handler_x-sharedlib") << "application/x-sharedlib" << false << false; 0301 QTest::newRow("handler_false_x-sharedlib") << "application/x-sharedlib" << true << false; 0302 QTest::newRow("handler_true_x-sharedlib") << "application/x-sharedlib" << true << true; 0303 0304 QTest::newRow("no_handler_x-executable") << "application/x-executable" << false << false; 0305 QTest::newRow("handler_false_x-executable") << "application/x-executable" << true << false; 0306 QTest::newRow("handler_true_x-executable") << "application/x-executable" << true << true; 0307 } 0308 0309 void OpenUrlJobTest::runNativeExecutable() 0310 { 0311 QFETCH(QString, mimeType); 0312 QFETCH(bool, withHandler); 0313 QFETCH(bool, handlerRetVal); 0314 0315 #ifdef Q_OS_UNIX 0316 // Given an executable shell script that copies "src" to "dest" (we'll cheat with the MIME type to treat it like a native binary) 0317 QTemporaryDir tempDir; 0318 const QString dir = tempDir.path(); 0319 createSrcFile(dir + QLatin1String("/src")); 0320 const QString scriptFile = dir + QLatin1String("/script.sh"); 0321 QFile file(scriptFile); 0322 QVERIFY(file.open(QIODevice::WriteOnly)); 0323 file.write("#!/bin/sh\ncp src dest"); 0324 file.close(); 0325 // Note that it's missing executable permissions 0326 0327 // When using OpenUrlJob to run the executable 0328 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(scriptFile), mimeType, this); 0329 job->setRunExecutables(true); // startProcess tests the case where this isn't set 0330 job->setUiDelegate(new KJobUiDelegate); 0331 0332 // Then --- it depends on what the user says via the handler 0333 if (!withHandler) { 0334 QVERIFY(!job->exec()); 0335 QCOMPARE((int)job->error(), (int)KJob::UserDefinedError); 0336 QCOMPARE(job->errorString(), QStringLiteral("The program \"%1\" needs to have executable permission before it can be launched.").arg(scriptFile)); 0337 } else { 0338 auto *handler = new MockUntrustedProgramHandler(job->uiDelegate()); 0339 handler->setRetVal(handlerRetVal); 0340 0341 const bool success = job->exec(); 0342 if (handlerRetVal) { 0343 QVERIFY(success); 0344 QTRY_VERIFY(QFileInfo::exists(dir + QLatin1String("/dest"))); // TRY because CommandLineLauncherJob finishes immediately 0345 } else { 0346 QVERIFY(!success); 0347 QCOMPARE((int)job->error(), (int)KIO::ERR_USER_CANCELED); 0348 } 0349 } 0350 #endif 0351 } 0352 0353 void OpenUrlJobTest::openOrExecuteScript_data() 0354 { 0355 QTest::addColumn<QString>("dialogResult"); 0356 0357 QTest::newRow("execute_true") << "execute_true"; 0358 QTest::newRow("execute_false") << "execute_false"; 0359 QTest::newRow("canceled") << "canceled"; 0360 } 0361 0362 void OpenUrlJobTest::openOrExecuteScript() 0363 { 0364 #ifdef Q_OS_UNIX 0365 QFETCH(QString, dialogResult); 0366 0367 // Given an executable shell script that copies "src" to "dest" 0368 QTemporaryDir tempDir; 0369 const QString dir = tempDir.path(); 0370 createSrcFile(dir + QLatin1String("/src")); 0371 const QString scriptFile = dir + QLatin1String("/script.sh"); 0372 QFile file(scriptFile); 0373 QVERIFY(file.open(QIODevice::WriteOnly)); 0374 file.write("#!/bin/sh\ncp src dest"); 0375 file.close(); 0376 // Set the executable bit, because OpenUrlJob will always open shell 0377 // scripts that are not executable as text files 0378 QVERIFY(file.setPermissions(QFile::ExeUser | file.permissions())); 0379 0380 // When using OpenUrlJob to open the script 0381 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(scriptFile), QStringLiteral("application/x-shellscript"), this); 0382 job->setShowOpenOrExecuteDialog(true); 0383 job->setUiDelegate(new KJobUiDelegate); 0384 auto *openOrExecuteFileHandler = new MockOpenOrExecuteHandler(job->uiDelegate()); 0385 0386 // Then --- it depends on what the user says via the handler 0387 if (dialogResult == QLatin1String("execute_true")) { 0388 job->setRunExecutables(false); // Overridden by the user's choice 0389 openOrExecuteFileHandler->setExecuteFile(true); 0390 QVERIFY(job->exec()); 0391 // TRY because CommandLineLauncherJob finishes immediately, and tempDir 0392 // will go out of scope and get deleted before the copy operation actually finishes 0393 QTRY_VERIFY(QFileInfo::exists(dir + QLatin1String("/dest"))); 0394 } else if (dialogResult == QLatin1String("execute_false")) { 0395 job->setRunExecutables(true); // Overridden by the user's choice 0396 openOrExecuteFileHandler->setExecuteFile(false); 0397 QVERIFY(job->exec()); 0398 const QString testOpen = m_tempDir.path() + QLatin1String("/dest"); // see the .desktop file in writeApplicationDesktopFile 0399 QTRY_VERIFY(QFileInfo::exists(testOpen)); 0400 } else if (dialogResult == QLatin1String("canceled")) { 0401 openOrExecuteFileHandler->setCanceled(); 0402 QVERIFY(!job->exec()); 0403 QCOMPARE(job->error(), KIO::ERR_USER_CANCELED); 0404 } 0405 #endif 0406 } 0407 0408 void OpenUrlJobTest::openOrExecuteDesktop_data() 0409 { 0410 QTest::addColumn<QString>("dialogResult"); 0411 0412 QTest::newRow("execute_true") << "execute_true"; 0413 QTest::newRow("execute_false") << "execute_false"; 0414 QTest::newRow("canceled") << "canceled"; 0415 } 0416 0417 void OpenUrlJobTest::openOrExecuteDesktop() 0418 { 0419 #ifdef Q_OS_UNIX 0420 QFETCH(QString, dialogResult); 0421 0422 // Given a .desktop file, with an Exec line that copies "src" to "dest" 0423 QTemporaryDir tempDir; 0424 const QString dir = tempDir.path(); 0425 const QString desktopFile = dir + QLatin1String("/testopenorexecute.desktop"); 0426 createSrcFile(dir + QLatin1String("/src")); 0427 const QByteArray cmd("cp " + QFile::encodeName(dir) + "/src " + QFile::encodeName(dir) + "/dest-open-or-execute-desktop"); 0428 writeApplicationDesktopFile(desktopFile, cmd); 0429 QFile file(desktopFile); 0430 QVERIFY(file.setPermissions(QFile::ExeUser | file.permissions())); // otherwise we'll get the untrusted program warning 0431 0432 // When using OpenUrlJob to open the .desktop file 0433 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(desktopFile), QStringLiteral("application/x-desktop"), this); 0434 job->setShowOpenOrExecuteDialog(true); 0435 job->setUiDelegate(new KJobUiDelegate); 0436 auto *openOrExecuteFileHandler = new MockOpenOrExecuteHandler(job->uiDelegate()); 0437 0438 // Then --- it depends on what the user says via the handler 0439 if (dialogResult == QLatin1String("execute_true")) { 0440 job->setRunExecutables(false); // Overridden by the user's choice 0441 openOrExecuteFileHandler->setExecuteFile(true); 0442 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0443 // TRY because CommandLineLauncherJob finishes immediately, and tempDir 0444 // will go out of scope and get deleted before the copy operation actually finishes 0445 QTRY_VERIFY(QFileInfo::exists(dir + QLatin1String("/dest-open-or-execute-desktop"))); 0446 } 0447 if (dialogResult == QLatin1String("execute_false")) { 0448 job->setRunExecutables(true); // Overridden by the user's choice 0449 openOrExecuteFileHandler->setExecuteFile(false); 0450 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0451 const QString testOpen = m_tempDir.path() + QLatin1String("/dest"); // see the .desktop file in writeApplicationDesktopFile 0452 QTRY_VERIFY(QFileInfo::exists(testOpen)); 0453 } else if (dialogResult == QLatin1String("canceled")) { 0454 openOrExecuteFileHandler->setCanceled(); 0455 QVERIFY(!job->exec()); 0456 QCOMPARE(job->error(), KIO::ERR_USER_CANCELED); 0457 } 0458 #endif 0459 } 0460 0461 void OpenUrlJobTest::launchExternalBrowser_data() 0462 { 0463 QTest::addColumn<bool>("useBrowserApp"); 0464 QTest::addColumn<bool>("useSchemeHandler"); 0465 0466 QTest::newRow("browserapp") << true << false; 0467 QTest::newRow("scheme_handler") << false << true; 0468 } 0469 0470 void OpenUrlJobTest::launchExternalBrowser() 0471 { 0472 #ifdef Q_OS_UNIX 0473 QFETCH(bool, useBrowserApp); 0474 QFETCH(bool, useSchemeHandler); 0475 0476 QTemporaryDir tempDir; 0477 const QString dir = tempDir.path(); 0478 createSrcFile(dir + QLatin1String("/src")); 0479 const QString scriptFile = dir + QLatin1String("/browser.sh"); 0480 QFile file(scriptFile); 0481 QVERIFY(file.open(QIODevice::WriteOnly)); 0482 file.write("#!/bin/sh\necho $1 > `dirname $0`/destbrowser"); 0483 file.close(); 0484 QVERIFY(file.setPermissions(QFile::ExeUser | file.permissions())); 0485 0486 QUrl remoteImage("http://example.org/image.jpg"); 0487 if (useBrowserApp) { 0488 openurljob_force_use_browserapp_kdeglobals = true; 0489 KConfigGroup(KSharedConfig::openConfig(), "General").writeEntry("BrowserApplication", QString(QLatin1Char('!') + scriptFile)); 0490 } else if (useSchemeHandler) { 0491 openurljob_force_use_browserapp_kdeglobals = false; 0492 remoteImage.setScheme("scheme"); 0493 } 0494 0495 // When using OpenUrlJob to run the script 0496 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(remoteImage, this); 0497 0498 // Then it works :-) 0499 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0500 QString dest; 0501 if (useBrowserApp) { 0502 dest = dir + QLatin1String("/destbrowser"); 0503 } else if (useSchemeHandler) { 0504 dest = m_tempDir.path() + QLatin1String("/dest"); // see the .desktop file in writeApplicationDesktopFile 0505 } 0506 QTRY_VERIFY(QFileInfo::exists(dest)); // TRY because CommandLineLauncherJob finishes immediately 0507 QCOMPARE(readFile(dest), remoteImage.toString()); 0508 0509 // Restore settings 0510 KConfigGroup(KSharedConfig::openConfig(), "General").deleteEntry("BrowserApplication"); 0511 #endif 0512 } 0513 0514 void OpenUrlJobTest::nonExistingFile() 0515 { 0516 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(QStringLiteral("/does/not/exist")), this); 0517 QVERIFY(!job->exec()); 0518 QCOMPARE(job->error(), KIO::ERR_DOES_NOT_EXIST); 0519 QCOMPARE(job->errorString(), "The file or folder /does/not/exist does not exist."); 0520 } 0521 0522 void OpenUrlJobTest::httpUrlWithKIO() 0523 { 0524 // This tests the scanFileWithGet() code path 0525 const QUrl url(QStringLiteral("http://www.google.com/")); 0526 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, this); 0527 job->setEnableExternalBrowser(false); 0528 job->setFollowRedirections(false); 0529 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0530 0531 // Then the service should be executed (which writes to "dest") 0532 const QString dest = m_tempDir.path() + "/dest"; 0533 QTRY_VERIFY2(QFile::exists(dest), qPrintable(dest)); 0534 QCOMPARE(readFile(dest), url.toString()); 0535 } 0536 0537 void OpenUrlJobTest::ftpUrlWithKIO() 0538 { 0539 // This is just to test the statFile() code at least a bit 0540 const QUrl url(QStringLiteral("ftp://localhost:2")); // unlikely that anything is running on that port 0541 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, this); 0542 QVERIFY(!job->exec()); 0543 QVERIFY(job->errorString() == QLatin1String("Could not connect to host localhost: Connection refused.") 0544 || job->errorString() == QLatin1String("Could not connect to host localhost: Network unreachable.")); 0545 } 0546 0547 void OpenUrlJobTest::takeOverAfterMimeTypeFound() 0548 { 0549 // Given a local image file 0550 QTemporaryDir tempDir; 0551 const QString srcDir = tempDir.path(); 0552 const QString srcFile = srcDir + QLatin1String("/image.jpg"); 0553 createSrcFile(srcFile); 0554 0555 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(srcFile), this); 0556 QString foundMime = QStringLiteral("NONE"); 0557 connect(job, &KIO::OpenUrlJob::mimeTypeFound, this, [&](const QString &mimeType) { 0558 foundMime = mimeType; 0559 job->kill(); 0560 }); 0561 QVERIFY(!job->exec()); 0562 QCOMPARE(job->error(), KJob::KilledJobError); 0563 QCOMPARE(foundMime, "image/jpeg"); 0564 } 0565 0566 void OpenUrlJobTest::runDesktopFileDirectly() 0567 { 0568 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(m_fakeService), this); 0569 job->setRunExecutables(true); 0570 QVERIFY(job->exec()); 0571 0572 const QString dest = m_tempDir.path() + "/dest"; 0573 QTRY_VERIFY2(QFile::exists(dest), qPrintable(dest)); 0574 QCOMPARE(readFile(dest), QString{}); 0575 } 0576 0577 void OpenUrlJobTest::writeApplicationDesktopFile(const QString &filePath, const QByteArray &command) 0578 { 0579 KDesktopFile file(filePath); 0580 KConfigGroup group = file.desktopGroup(); 0581 group.writeEntry("Name", "KRunUnittestService"); 0582 group.writeEntry("MimeType", "text/plain;application/x-shellscript;x-scheme-handler/scheme"); 0583 group.writeEntry("Type", "Application"); 0584 group.writeEntry("Exec", command); 0585 QVERIFY(file.sync()); 0586 } 0587 0588 #include "moc_openurljobtest.cpp"