File indexing completed on 2024-12-22 05:16:05
0001 /* 0002 SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <chrono> 0008 0009 #include <KDirNotify> 0010 #include <KIO/CopyJob> 0011 #include <KIO/FileCopyJob> 0012 #include <KIO/FileUndoManager> 0013 #include <KIO/StatJob> 0014 #include <QDesktopServices> 0015 #include <QProcess> 0016 #include <QSignalSpy> 0017 #include <QStandardPaths> 0018 #include <QTemporaryFile> 0019 #include <QTest> 0020 #include <kdirlister.h> 0021 #include <kio/copyjob.h> 0022 #include <kio/job.h> 0023 0024 using namespace Qt::StringLiterals; 0025 using namespace std::chrono_literals; 0026 0027 static void doUndo() // see FileUndoManagerTest::doUndo() 0028 { 0029 QEventLoop eventLoop; 0030 QObject::connect(KIO::FileUndoManager::self(), &KIO::FileUndoManager::undoJobFinished, &eventLoop, &QEventLoop::quit); 0031 KIO::FileUndoManager::self()->undo(); 0032 eventLoop.exec(QEventLoop::ExcludeUserInputEvents); // wait for undo job to finish 0033 } 0034 0035 class TestDesktop : public QObject 0036 { 0037 Q_OBJECT 0038 0039 public: 0040 TestDesktop() 0041 { 0042 } 0043 0044 private Q_SLOTS: 0045 void initTestCase() 0046 { 0047 // make KIOs use test mode too 0048 setenv("KIOSLAVE_ENABLE_TESTMODE", "1", 1); 0049 QStandardPaths::setTestModeEnabled(true); 0050 0051 // Warning: even with test mode enabled, this is the real user's Desktop directory 0052 m_desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); 0053 m_testFileName = QLatin1String("kio_desktop_test_file"); 0054 qWarning() << "We will write in the desktop folder" << m_desktopPath; 0055 // NOTE: we must shut down kded if we started it in the CI! Do not detach! 0056 m_kded.setProgram("kded6"_L1); 0057 m_kded.start(); 0058 const auto started = m_kded.waitForStarted((1000ms).count()); 0059 qWarning() << "Starting kded" << started; 0060 cleanupTestCase(); 0061 } 0062 void cleanupTestCase() 0063 { 0064 QFile::remove(m_desktopPath + '/' + m_testFileName); 0065 QFile::remove(m_desktopPath + '/' + m_testFileName + ".part"); 0066 QFile::remove(m_desktopPath + '/' + m_testFileName + "_link"); 0067 m_kded.kill(); 0068 } 0069 0070 void testCopyToDesktop() 0071 { 0072 QTemporaryFile tempFile; 0073 QVERIFY(tempFile.open()); 0074 tempFile.write("Hello world\n", 12); 0075 QString fileName = tempFile.fileName(); 0076 tempFile.close(); 0077 KIO::Job *job = KIO::file_copy(QUrl::fromLocalFile(fileName), QUrl("desktop:/" + m_testFileName), -1, KIO::HideProgressInfo); 0078 job->setUiDelegate(nullptr); 0079 QVERIFY(job->exec()); 0080 QVERIFY(QFile::exists(m_desktopPath + '/' + m_testFileName)); 0081 } 0082 0083 void testMostLocalUrl() // relies on testCopyToDesktop being run before 0084 { 0085 const QUrl desktopUrl("desktop:/" + m_testFileName); 0086 const QString filePath(m_desktopPath + '/' + m_testFileName); 0087 KIO::StatJob *job = KIO::mostLocalUrl(desktopUrl, KIO::HideProgressInfo); 0088 QVERIFY(job); 0089 bool ok = job->exec(); 0090 QVERIFY(ok); 0091 QCOMPARE(job->mostLocalUrl().toLocalFile(), filePath); 0092 } 0093 0094 void testCreateSymlink() 0095 { 0096 const QUrl desktopUrl("desktop:/" + m_testFileName); 0097 const QUrl desktopLink("desktop:/" + m_testFileName + "_link"); 0098 const QString source = m_desktopPath + '/' + m_testFileName; 0099 const QString localLink = source + "_link"; 0100 0101 // Create a symlink using kio_desktop 0102 KIO::Job *linkJob = KIO::symlink(m_testFileName, desktopLink, KIO::HideProgressInfo); 0103 QVERIFY(linkJob->exec()); 0104 QVERIFY(QFileInfo(localLink).isSymLink()); 0105 QCOMPARE(QFileInfo(localLink).symLinkTarget(), source); 0106 0107 // Now try changing the link target, without Overwrite -> error 0108 linkJob = KIO::symlink(m_testFileName + QLatin1Char('2'), desktopLink, KIO::HideProgressInfo); 0109 QVERIFY(!linkJob->exec()); 0110 QCOMPARE(linkJob->error(), (int)KIO::ERR_FILE_ALREADY_EXIST); 0111 0112 // Now try changing the link target, with Overwrite (bug 360487) 0113 linkJob = KIO::symlink(m_testFileName + QLatin1Char('3'), desktopLink, KIO::Overwrite | KIO::HideProgressInfo); 0114 QVERIFY(linkJob->exec()); 0115 QVERIFY(QFileInfo(localLink).isSymLink()); 0116 QCOMPARE(QFileInfo(localLink).symLinkTarget(), source + QLatin1Char('3')); 0117 } 0118 0119 void testRename_data() 0120 { 0121 QTest::addColumn<bool>("withDirListerCache"); 0122 QTest::addColumn<QUrl>("srcUrl"); 0123 QTest::addColumn<QUrl>("destUrl"); 0124 0125 const QString str = "desktop:/" + m_testFileName; 0126 const QUrl orig(str); 0127 const QUrl part(str + ".part"); 0128 QTest::newRow("orig_to_part") << false << orig << part; 0129 QTest::newRow("part_to_orig") << false << part << orig; 0130 // Warnings: all tests without dirlister cache should above this line 0131 // and all tests with it should be below - the cache stays forever once it exists. 0132 QTest::newRow("orig_to_part_with_cache") << true << orig << part; 0133 QTest::newRow("part_to_orig_with_cache") << true << part << orig; // #218719 0134 } 0135 0136 void testRename() // relies on testCopyToDesktop being run before 0137 { 0138 QFETCH(bool, withDirListerCache); 0139 QFETCH(QUrl, srcUrl); 0140 QFETCH(QUrl, destUrl); 0141 0142 std::unique_ptr<KDirLister> lister; 0143 if (withDirListerCache) { 0144 lister.reset(new KDirLister); 0145 lister->openUrl(QUrl(QStringLiteral("desktop:/"))); 0146 QSignalSpy spyCompleted(lister.get(), static_cast<void (KDirLister::*)()>(&KDirLister::completed)); 0147 spyCompleted.wait(); 0148 } 0149 0150 org::kde::KDirNotify kdirnotify(QString(), QString(), QDBusConnection::sessionBus(), this); 0151 QSignalSpy spyFilesAdded(&kdirnotify, &org::kde::KDirNotify::FilesAdded); 0152 QSignalSpy spyFileRenamed(&kdirnotify, &org::kde::KDirNotify::FileRenamed); 0153 QSignalSpy spyFileRenamedWithLocalPath(&kdirnotify, &org::kde::KDirNotify::FileRenamedWithLocalPath); 0154 0155 const QString srcFilePath(m_desktopPath + srcUrl.path()); 0156 QVERIFY(QFile::exists(srcFilePath)); 0157 const QString destFilePath(m_desktopPath + destUrl.path()); 0158 QVERIFY(!QFile::exists(destFilePath)); 0159 0160 KIO::Job *job = KIO::rename(srcUrl, destUrl, KIO::HideProgressInfo); 0161 job->setUiDelegate(nullptr); 0162 QVERIFY(job); 0163 bool ok = job->exec(); 0164 QVERIFY(ok); 0165 QVERIFY(!QFile::exists(srcFilePath)); 0166 QVERIFY(QFile::exists(destFilePath)); 0167 0168 // kio_desktop's rename() calls org::kde::KDirNotify::emitFileRenamedWithLocalPath 0169 // FIXME: fix the double signal emission of fileRenamed 0170 // and then desktopnotifier notices something changed and emits KDirNotify::FilesAdded 0171 QTRY_VERIFY(spyFileRenamed.count() >= 1); 0172 QTRY_VERIFY(spyFileRenamedWithLocalPath.count() >= 1); 0173 0174 // check that KDirLister now has the correct item (#382341) 0175 if (lister) { 0176 QTRY_COMPARE(lister->findByUrl(destUrl).targetUrl(), QUrl::fromLocalFile(destFilePath)); 0177 } 0178 } 0179 0180 void testTrashAndUndo() 0181 { 0182 // Given a file on the desktop... 0183 const QString localPath = m_desktopPath + '/' + m_testFileName; 0184 QVERIFY(QFile::exists(localPath)); 0185 0186 // ...moved to the trash 0187 const QUrl desktopUrl("desktop:/" + m_testFileName); 0188 KIO::Job *job = KIO::trash({desktopUrl}, KIO::HideProgressInfo); 0189 job->setUiDelegate(nullptr); 0190 KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Trash, {desktopUrl}, QUrl(QStringLiteral("trash:/")), job); 0191 QVERIFY2(job->exec(), qPrintable(job->errorString())); 0192 QVERIFY(!QFile::exists(localPath)); 0193 0194 // When the user calls undo 0195 doUndo(); 0196 0197 // Then the file should re-appear 0198 QVERIFY(QFile::exists(localPath)); 0199 } 0200 0201 private: 0202 QString m_desktopPath; 0203 QString m_testFileName; 0204 QProcess m_kded; 0205 }; 0206 0207 QTEST_GUILESS_MAIN(TestDesktop) 0208 0209 #include "kio_desktop_test.moc"