File indexing completed on 2024-12-08 06:39:43
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kfileitemtest.h" 0009 #include <QTest> 0010 #include <kfileitem.h> 0011 #include <kfileitemlistproperties.h> 0012 0013 #include "kiotesthelper.h" 0014 #include <KConfigGroup> 0015 #include <KDesktopFile> 0016 #include <KSycoca> 0017 #include <KUser> 0018 #include <QTemporaryDir> 0019 #include <QTemporaryFile> 0020 0021 #include <KProtocolInfo> 0022 #include <QMimeDatabase> 0023 0024 QTEST_MAIN(KFileItemTest) 0025 0026 struct CaseInsensitiveStringCompareHelper { 0027 explicit CaseInsensitiveStringCompareHelper(QStringView str) 0028 : m_str(str) 0029 { 0030 } 0031 QStringView m_str; 0032 bool operator==(QStringView other) const 0033 { 0034 return other.compare(m_str, Qt::CaseInsensitive) == 0; 0035 } 0036 }; 0037 0038 char *toString(const CaseInsensitiveStringCompareHelper &h) 0039 { 0040 return QTest::toString(h.m_str); 0041 } 0042 0043 void KFileItemTest::initTestCase() 0044 { 0045 QStandardPaths::setTestModeEnabled(true); 0046 KSycoca::setupTestMenu(); 0047 } 0048 0049 void KFileItemTest::testPermissionsString() 0050 { 0051 // Directory 0052 QTemporaryDir tempDir; 0053 KFileItem dirItem(QUrl::fromLocalFile(tempDir.path() + '/')); 0054 QCOMPARE((uint)dirItem.permissions(), (uint)0700); 0055 QCOMPARE(dirItem.permissionsString(), QStringLiteral("drwx------")); 0056 QVERIFY(dirItem.isReadable()); 0057 0058 // File 0059 QFile file(tempDir.path() + "/afile"); 0060 QVERIFY(file.open(QIODevice::WriteOnly)); 0061 file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadOther); // 0604 0062 KFileItem fileItem(QUrl::fromLocalFile(file.fileName()), QString(), KFileItem::Unknown); 0063 QCOMPARE((uint)fileItem.permissions(), (uint)0604); 0064 QCOMPARE(fileItem.permissionsString(), QStringLiteral("-rw----r--")); 0065 QVERIFY(fileItem.isReadable()); 0066 QCOMPARE(fileItem.getStatusBarInfo(), CaseInsensitiveStringCompareHelper(QStringLiteral("afile (Empty document, 0 B)"))); 0067 0068 // Folder 0069 QVERIFY(QDir(tempDir.path()) 0070 .mkdir(QStringLiteral("afolder"), 0071 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeUser | QFile::ReadGroup | QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther)); 0072 QFile folderFile(tempDir.path() + "/afolder"); 0073 KFileItem folderItem(QUrl::fromLocalFile(folderFile.fileName()), QString(), KFileItem::Unknown); 0074 QCOMPARE(folderItem.permissionsString(), QStringLiteral("drwxr-xr-x")); // 655 0075 QVERIFY(folderItem.isReadable()); 0076 QCOMPARE(folderItem.getStatusBarInfo(), CaseInsensitiveStringCompareHelper(QStringLiteral("afolder (Folder)"))); 0077 0078 // Symlink to file 0079 QString symlink = tempDir.path() + "/asymlink"; 0080 QVERIFY(file.link(symlink)); 0081 QUrl symlinkUrl = QUrl::fromLocalFile(symlink); 0082 KFileItem symlinkItem(symlinkUrl, QString(), KFileItem::Unknown); 0083 QCOMPARE((uint)symlinkItem.permissions(), (uint)0604); 0084 // This is a bit different from "ls -l": we get the 'l' but we see the permissions of the target. 0085 // This is actually useful though; the user sees it's a link, and can check if he can read the [target] file. 0086 QCOMPARE(symlinkItem.permissionsString(), QStringLiteral("lrw----r--")); 0087 QVERIFY(symlinkItem.isReadable()); 0088 QCOMPARE(symlinkItem.getStatusBarInfo(), 0089 CaseInsensitiveStringCompareHelper(QStringLiteral("asymlink (Empty document, Link to %1/afile)").arg(tempDir.path()))); 0090 0091 #ifdef Q_OS_UNIX 0092 // relative Symlink to a file 0093 QFile relativeFile("../afile"); 0094 QString relativeSymlink = tempDir.path() + "/afolder/relative-symlink"; 0095 QVERIFY(::symlink("../afile", relativeSymlink.toLatin1()) == 0); 0096 QUrl relativeSymlinkUrl = QUrl::fromLocalFile(relativeSymlink); 0097 KFileItem relativeSymlinkItem(relativeSymlinkUrl, QString(), KFileItem::Unknown); 0098 QCOMPARE((uint)relativeSymlinkItem.permissions(), (uint)0604); 0099 // This is a bit different from "ls -l": we get the 'l' but we see the permissions of the target. 0100 // This is actually useful though; the user sees it's a link, and can check if he can read the [target] file. 0101 QCOMPARE(relativeSymlinkItem.permissionsString(), QStringLiteral("lrw----r--")); 0102 QVERIFY(relativeSymlinkItem.isReadable()); 0103 QCOMPARE(relativeSymlinkItem.getStatusBarInfo(), 0104 CaseInsensitiveStringCompareHelper(QStringLiteral("relative-symlink (Empty document, Link to %1/afile)").arg(tempDir.path()))); 0105 #endif 0106 0107 // Symlink to directory (#162544) 0108 QVERIFY(QFile::remove(symlink)); 0109 QVERIFY(QFile(tempDir.path() + '/').link(symlink)); 0110 KFileItem symlinkToDirItem(symlinkUrl, QString(), KFileItem::Unknown); 0111 QCOMPARE((uint)symlinkToDirItem.permissions(), (uint)0700); 0112 QCOMPARE(symlinkToDirItem.permissionsString(), QStringLiteral("lrwx------")); 0113 QCOMPARE(symlinkToDirItem.getStatusBarInfo(), CaseInsensitiveStringCompareHelper(QStringLiteral("asymlink (Folder, Link to %1)").arg(tempDir.path()))); 0114 0115 // unkwnown file 0116 QFile unkwnownFile(tempDir.path() + "/unkwnown_file"); 0117 KFileItem unkwnownfileItem(QUrl::fromLocalFile(unkwnownFile.fileName()), QString(), KFileItem::Unknown); 0118 QCOMPARE(unkwnownfileItem.getStatusBarInfo(), CaseInsensitiveStringCompareHelper(QStringLiteral("unkwnown_file (Unknown)"))); 0119 } 0120 0121 void KFileItemTest::testNull() 0122 { 0123 KFileItem null; 0124 QVERIFY(null.isNull()); 0125 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/")), QString(), KFileItem::Unknown); 0126 QVERIFY(!fileItem.isNull()); 0127 null = fileItem; // ok, now 'null' isn't so null anymore 0128 QVERIFY(!null.isNull()); 0129 QVERIFY(null.isReadable()); 0130 QVERIFY(!null.isWritable()); 0131 QVERIFY(!null.isHidden()); 0132 } 0133 0134 void KFileItemTest::testDoesNotExist() 0135 { 0136 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/doesnotexist")), QString(), KFileItem::Unknown); 0137 QVERIFY(!fileItem.isNull()); 0138 QVERIFY(!fileItem.isReadable()); 0139 QVERIFY(!fileItem.isWritable()); 0140 QVERIFY(fileItem.user().isEmpty()); 0141 QVERIFY(fileItem.group().isEmpty()); 0142 } 0143 0144 void KFileItemTest::testDetach() 0145 { 0146 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString(), KFileItem::Unknown); 0147 QCOMPARE(fileItem.name(), QStringLiteral("one")); 0148 KFileItem fileItem2(fileItem); 0149 QVERIFY(fileItem == fileItem2); 0150 QVERIFY(fileItem.d == fileItem2.d); 0151 fileItem2.setName(QStringLiteral("two")); 0152 QCOMPARE(fileItem2.name(), QStringLiteral("two")); 0153 QCOMPARE(fileItem.name(), QStringLiteral("one")); // it detached 0154 QVERIFY(fileItem == fileItem2); 0155 QVERIFY(fileItem.d != fileItem2.d); 0156 0157 fileItem = fileItem2; 0158 QCOMPARE(fileItem.name(), QStringLiteral("two")); 0159 QVERIFY(fileItem == fileItem2); 0160 QVERIFY(fileItem.d == fileItem2.d); 0161 QVERIFY(!(fileItem != fileItem2)); 0162 } 0163 0164 void KFileItemTest::testMove() 0165 { 0166 // Test move constructor 0167 { 0168 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString(), KFileItem::Unknown); 0169 QCOMPARE(fileItem.name(), QStringLiteral("one")); 0170 KFileItem fileItem2(std::move(fileItem)); 0171 QCOMPARE(fileItem2.name(), QStringLiteral("one")); 0172 } 0173 0174 // Test move assignment 0175 { 0176 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString(), KFileItem::Unknown); 0177 QCOMPARE(fileItem.name(), QStringLiteral("one")); 0178 KFileItem fileItem2(QUrl::fromLocalFile(QStringLiteral("/two")), QString(), KFileItem::Unknown); 0179 fileItem2 = std::move(fileItem); 0180 QCOMPARE(fileItem2.name(), QStringLiteral("one")); 0181 } 0182 0183 // Now to test some value changes to make sure moving works as intended. 0184 KFileItem fileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString(), KFileItem::Unknown); 0185 QCOMPARE(fileItem.name(), QStringLiteral("one")); 0186 fileItem.setUrl(QUrl::fromLocalFile(QStringLiteral("/two"))); 0187 QCOMPARE(fileItem.name(), QStringLiteral("two")); 0188 0189 // Move fileitem to fileItem2, it should now contain everything fileItem had. 0190 // Just testing a property to make sure it does. 0191 KFileItem fileItem2(std::move(fileItem)); 0192 QCOMPARE(fileItem2.name(), QStringLiteral("two")); 0193 } 0194 0195 void KFileItemTest::testMimeTypeCtor() 0196 { 0197 KFileItem fileItem; 0198 0199 fileItem = KFileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString("inode/directory")); 0200 QVERIFY(fileItem.isDir()); 0201 QVERIFY(fileItem.isMimeTypeKnown()); 0202 0203 fileItem = KFileItem(QUrl::fromLocalFile(QStringLiteral("/one")), QString("image/jpeg")); 0204 QVERIFY(!fileItem.isDir()); 0205 QVERIFY(fileItem.isMimeTypeKnown()); 0206 0207 fileItem = KFileItem(QUrl::fromLocalFile(QStringLiteral("/one.txt")), QString("inode/directory")); 0208 QVERIFY(fileItem.isDir()); 0209 QVERIFY(fileItem.isMimeTypeKnown()); 0210 0211 fileItem = KFileItem(QUrl::fromLocalFile(QStringLiteral("/one.txt")), QString(" ")); 0212 QVERIFY(!fileItem.isMimeTypeKnown()); 0213 } 0214 0215 void KFileItemTest::testBasic() 0216 { 0217 QTemporaryFile file; 0218 QVERIFY(file.open()); 0219 QFile fileObj(file.fileName()); 0220 QVERIFY(fileObj.open(QIODevice::WriteOnly)); 0221 fileObj.write(QByteArray("Hello")); 0222 fileObj.close(); 0223 0224 QUrl url = QUrl::fromLocalFile(file.fileName()); 0225 KFileItem fileItem(url, QString(), KFileItem::Unknown); 0226 QCOMPARE(fileItem.text(), url.fileName()); 0227 QVERIFY(fileItem.isLocalFile()); 0228 QCOMPARE(fileItem.localPath(), url.toLocalFile()); 0229 QCOMPARE(fileItem.size(), KIO::filesize_t(5)); 0230 QVERIFY(fileItem.linkDest().isEmpty()); 0231 QVERIFY(!fileItem.isHidden()); 0232 QVERIFY(fileItem.isReadable()); 0233 QVERIFY(fileItem.isWritable()); 0234 QVERIFY(fileItem.isFile()); 0235 QVERIFY(!fileItem.isDir()); 0236 QVERIFY(!fileItem.isDesktopFile()); 0237 #ifndef Q_OS_WIN 0238 QCOMPARE(fileItem.user(), KUser().loginName()); 0239 #endif 0240 } 0241 0242 void KFileItemTest::testRootDirectory() 0243 { 0244 const QString rootPath = QDir::rootPath(); 0245 QUrl url = QUrl::fromLocalFile(rootPath); 0246 KIO::UDSEntry entry; 0247 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral(".")); 0248 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0249 KFileItem fileItem(entry, url); 0250 QCOMPARE(fileItem.text(), QStringLiteral(".")); 0251 QVERIFY(fileItem.isLocalFile()); 0252 QCOMPARE(fileItem.localPath(), url.toLocalFile()); 0253 QVERIFY(fileItem.linkDest().isEmpty()); 0254 QVERIFY(!fileItem.isHidden()); 0255 QVERIFY(!fileItem.isFile()); 0256 QVERIFY(fileItem.isDir()); 0257 QVERIFY(!fileItem.isDesktopFile()); 0258 } 0259 0260 void KFileItemTest::testHiddenFile() 0261 { 0262 QTemporaryDir tempDir; 0263 QFile file(tempDir.path() + "/.hiddenfile"); 0264 QVERIFY(file.open(QIODevice::WriteOnly)); 0265 KFileItem fileItem(QUrl::fromLocalFile(file.fileName()), QString(), KFileItem::Unknown); 0266 QCOMPARE(fileItem.text(), QStringLiteral(".hiddenfile")); 0267 QVERIFY(fileItem.isLocalFile()); 0268 QVERIFY(fileItem.isHidden()); 0269 } 0270 0271 void KFileItemTest::testMimeTypeOnDemand() 0272 { 0273 QTemporaryFile file; 0274 QVERIFY(file.open()); 0275 0276 { 0277 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0278 fileItem.setDelayedMimeTypes(true); 0279 QVERIFY(fileItem.currentMimeType().isDefault()); 0280 QVERIFY(!fileItem.isMimeTypeKnown()); 0281 QVERIFY(!fileItem.isFinalIconKnown()); 0282 // qDebug() << fileItem.determineMimeType().name(); 0283 QCOMPARE(fileItem.determineMimeType().name(), QStringLiteral("application/x-zerosize")); 0284 QCOMPARE(fileItem.mimetype(), QStringLiteral("application/x-zerosize")); 0285 QVERIFY(fileItem.isMimeTypeKnown()); 0286 QVERIFY(fileItem.isFinalIconKnown()); 0287 } 0288 0289 { 0290 // Calling mimeType directly also does MIME type determination 0291 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0292 fileItem.setDelayedMimeTypes(true); 0293 QVERIFY(!fileItem.isMimeTypeKnown()); 0294 QCOMPARE(fileItem.mimetype(), QStringLiteral("application/x-zerosize")); 0295 QVERIFY(fileItem.isMimeTypeKnown()); 0296 } 0297 0298 { 0299 // Calling overlays should NOT do MIME type determination (#237668) 0300 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0301 fileItem.setDelayedMimeTypes(true); 0302 QVERIFY(!fileItem.isMimeTypeKnown()); 0303 fileItem.overlays(); 0304 QVERIFY(!fileItem.isMimeTypeKnown()); 0305 } 0306 0307 { 0308 QTemporaryFile file; 0309 QVERIFY(file.open()); 0310 // Check whether mime-magic is used. 0311 // No known extension, so it should be used by determineMimeType. 0312 file.write(QByteArray("%PDF-")); 0313 QString fileName = file.fileName(); 0314 QVERIFY(!fileName.isEmpty()); 0315 file.close(); 0316 KFileItem fileItem(QUrl::fromLocalFile(fileName)); 0317 fileItem.setDelayedMimeTypes(true); 0318 QCOMPARE(fileItem.currentMimeType().name(), QLatin1String("application/octet-stream")); 0319 QVERIFY(fileItem.currentMimeType().isValid()); 0320 QVERIFY(fileItem.currentMimeType().isDefault()); 0321 QVERIFY(!fileItem.isMimeTypeKnown()); 0322 QCOMPARE(fileItem.determineMimeType().name(), QStringLiteral("application/pdf")); 0323 QCOMPARE(fileItem.mimetype(), QStringLiteral("application/pdf")); 0324 } 0325 0326 { 0327 QTemporaryFile file(QDir::tempPath() + QLatin1String("/kfileitemtest_XXXXXX.txt")); 0328 QVERIFY(file.open()); 0329 // Check whether mime-magic is used. 0330 // Known extension, so it should NOT be used. 0331 file.write(QByteArray("<smil")); 0332 QString fileName = file.fileName(); 0333 QVERIFY(!fileName.isEmpty()); 0334 file.close(); 0335 KFileItem fileItem(QUrl::fromLocalFile(fileName)); 0336 fileItem.setDelayedMimeTypes(true); 0337 QCOMPARE(fileItem.currentMimeType().name(), QStringLiteral("text/plain")); 0338 QVERIFY(fileItem.isMimeTypeKnown()); 0339 QCOMPARE(fileItem.determineMimeType().name(), QStringLiteral("text/plain")); 0340 QCOMPARE(fileItem.mimetype(), QStringLiteral("text/plain")); 0341 0342 // And if the MIME type is not on demand? 0343 KFileItem fileItem2(QUrl::fromLocalFile(fileName)); 0344 QCOMPARE(fileItem2.currentMimeType().name(), QStringLiteral("text/plain")); // XDG says: application/smil; but can't sniff all files so this can't work 0345 QVERIFY(fileItem2.isMimeTypeKnown()); 0346 } 0347 } 0348 0349 void KFileItemTest::testCmp() 0350 { 0351 QTemporaryFile file; 0352 QVERIFY(file.open()); 0353 0354 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0355 fileItem.setDelayedMimeTypes(true); 0356 KFileItem fileItem2(QUrl::fromLocalFile(file.fileName())); 0357 QVERIFY(fileItem == fileItem2); // created independently, but still 'equal' 0358 QVERIFY(fileItem.d != fileItem2.d); 0359 QVERIFY(!(fileItem != fileItem2)); 0360 QVERIFY(fileItem.cmp(fileItem2)); 0361 } 0362 0363 void KFileItemTest::testCmpAndInit() 0364 { 0365 QTemporaryDir tempDir; 0366 KFileItem dirItem(QUrl::fromLocalFile(tempDir.path())); 0367 QVERIFY(dirItem.isDir()); // this calls init() 0368 0369 KFileItem dirItem2(QUrl::fromLocalFile(tempDir.path())); 0370 // not yet init() called on dirItem2, but must be equal 0371 // compare init()ialized to un-init()ialized KFileItem 0372 QVERIFY(dirItem.cmp(dirItem2)); 0373 QVERIFY(dirItem2.isDir()); 0374 QVERIFY(dirItem.cmp(dirItem2)); 0375 QVERIFY(dirItem == dirItem2); 0376 QVERIFY(dirItem.d != dirItem2.d); 0377 QVERIFY(!(dirItem != dirItem2)); 0378 0379 // now the other way around, compare un-init()ialized to init()ialized KFileItem 0380 KFileItem dirItem3(QUrl::fromLocalFile(tempDir.path())); 0381 // not yet init() called on dirItem3, but must be equal 0382 QVERIFY(dirItem3.cmp(dirItem)); 0383 QVERIFY(dirItem3.isDir()); 0384 QVERIFY(dirItem3.cmp(dirItem)); 0385 QVERIFY(dirItem == dirItem3); 0386 QVERIFY(dirItem.d != dirItem3.d); 0387 QVERIFY(!(dirItem != dirItem3)); 0388 } 0389 0390 void KFileItemTest::testCmpByUrl() 0391 { 0392 const QUrl nulUrl; 0393 const QUrl url = QUrl::fromLocalFile(QStringLiteral("1foo")); 0394 const QUrl url2 = QUrl::fromLocalFile(QStringLiteral("fo1")); 0395 const QUrl url3 = QUrl::fromLocalFile(QStringLiteral("foo")); 0396 KFileItem nulFileItem; 0397 KFileItem nulFileItem2(nulUrl); 0398 KFileItem fileItem(url); 0399 KFileItem fileItem2(url2); 0400 KFileItem fileItem3(url3); 0401 0402 // an invalid KFileItem is considered equal to any other invalid KFileItem or invalid QUrl. 0403 QVERIFY(!(nulFileItem < nulFileItem)); 0404 QVERIFY(!(nulFileItem < nulFileItem2)); 0405 QVERIFY(!(nulFileItem2 < nulFileItem)); 0406 QVERIFY(!(nulFileItem < nulUrl)); 0407 // an invalid KFileItem is considered less than any valid KFileItem. 0408 QVERIFY(nulFileItem < fileItem); 0409 // a valid KFileItem is not less than an invalid KFileItem or invalid QUrl 0410 QVERIFY(!(fileItem < nulUrl)); 0411 QVERIFY(!(fileItem < nulFileItem)); 0412 QVERIFY(!(fileItem < nulFileItem2)); 0413 0414 QVERIFY(fileItem < fileItem2); 0415 QVERIFY(fileItem < url2); 0416 QVERIFY(!(fileItem2 < fileItem)); 0417 QVERIFY(fileItem2 < fileItem3); 0418 QVERIFY(fileItem < url3); 0419 QVERIFY(!(fileItem3 < fileItem2)); 0420 QVERIFY(!(fileItem3 < fileItem)); 0421 // Must be false as they are considered equal 0422 QVERIFY(!(fileItem < fileItem)); 0423 QVERIFY(!(fileItem < url)); 0424 } 0425 0426 void KFileItemTest::testRename() 0427 { 0428 KIO::UDSEntry entry; 0429 const QString origName = QStringLiteral("foo"); 0430 entry.fastInsert(KIO::UDSEntry::UDS_NAME, origName); 0431 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0432 KFileItem fileItem(entry, QUrl::fromLocalFile(QStringLiteral("/dir/foo"))); 0433 QCOMPARE(fileItem.name(), origName); 0434 QCOMPARE(fileItem.text(), origName); 0435 const QString newName = QStringLiteral("FiNeX_rocks"); 0436 fileItem.setName(newName); 0437 QCOMPARE(fileItem.name(), newName); 0438 QCOMPARE(fileItem.text(), newName); 0439 QCOMPARE(fileItem.entry().stringValue(KIO::UDSEntry::UDS_NAME), newName); // #195385 0440 } 0441 0442 void KFileItemTest::testRefresh() 0443 { 0444 QTemporaryDir tempDir; 0445 QFileInfo dirInfo(tempDir.path()); 0446 // Refresh on a dir 0447 KFileItem dirItem(QUrl::fromLocalFile(tempDir.path())); 0448 QVERIFY(dirItem.isDir()); 0449 QVERIFY(dirItem.entry().isDir()); 0450 QDateTime lastModified = dirInfo.lastModified(); 0451 // Qt 5.8 adds milliseconds (but UDSEntry has no support for that) 0452 lastModified = lastModified.addMSecs(-lastModified.time().msec()); 0453 QCOMPARE(dirItem.time(KFileItem::ModificationTime), lastModified); 0454 dirItem.refresh(); 0455 QVERIFY(dirItem.isDir()); 0456 QVERIFY(dirItem.entry().isDir()); 0457 QCOMPARE(dirItem.time(KFileItem::ModificationTime), lastModified); 0458 0459 // Refresh on a file 0460 QFile file(tempDir.path() + "/afile"); 0461 QVERIFY(file.open(QIODevice::WriteOnly)); 0462 file.write("Hello world\n"); 0463 file.close(); 0464 QFileInfo fileInfo(file.fileName()); 0465 const KIO::filesize_t expectedSize = 12; 0466 QCOMPARE(KIO::filesize_t(fileInfo.size()), expectedSize); 0467 file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadOther); // 0604 0468 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0469 QVERIFY(fileItem.isFile()); 0470 QVERIFY(!fileItem.isLink()); 0471 QCOMPARE(fileItem.size(), expectedSize); 0472 #ifndef Q_OS_WIN 0473 QCOMPARE(fileItem.user(), KUser().loginName()); 0474 #endif 0475 // Qt 5.8 adds milliseconds (but UDSEntry has no support for that) 0476 lastModified = dirInfo.lastModified(); 0477 // Truncate away the milliseconds... 0478 lastModified = lastModified.addMSecs(-lastModified.time().msec()); 0479 // ...but it looks like the kernel rounds up when the msecs are .998 or .999, 0480 // so add a bit of tolerance 0481 auto expectedLastModified = lastModified; 0482 if (fileItem.time(KFileItem::ModificationTime) != lastModified && fileItem.time(KFileItem::ModificationTime) == lastModified.addSecs(1)) { 0483 expectedLastModified = expectedLastModified.addSecs(1); 0484 } 0485 QCOMPARE(fileItem.time(KFileItem::ModificationTime), expectedLastModified); 0486 fileItem.refresh(); 0487 QVERIFY(fileItem.isFile()); 0488 QVERIFY(!fileItem.isLink()); 0489 QCOMPARE(fileItem.size(), expectedSize); 0490 #ifndef Q_OS_WIN 0491 QCOMPARE(fileItem.user(), KUser().loginName()); 0492 #endif 0493 QCOMPARE(fileItem.time(KFileItem::ModificationTime), expectedLastModified); 0494 0495 // Refresh on a symlink to a file 0496 const QString symlink = tempDir.path() + "/asymlink"; 0497 QVERIFY(file.link(symlink)); 0498 QDateTime symlinkTime = QDateTime::currentDateTime().addSecs(-20); 0499 // we currently lose milliseconds.... 0500 symlinkTime = symlinkTime.addMSecs(-symlinkTime.time().msec()); 0501 setTimeStamp(symlink, symlinkTime); // differentiate link time and source file time 0502 const QUrl symlinkUrl = QUrl::fromLocalFile(symlink); 0503 KFileItem symlinkItem(symlinkUrl); 0504 QVERIFY(symlinkItem.isFile()); 0505 QVERIFY(symlinkItem.isLink()); 0506 QCOMPARE(symlinkItem.size(), expectedSize); 0507 QCOMPARE(symlinkItem.time(KFileItem::ModificationTime), symlinkTime); 0508 symlinkItem.refresh(); 0509 QVERIFY(symlinkItem.isFile()); 0510 QVERIFY(symlinkItem.isLink()); 0511 QCOMPARE(symlinkItem.size(), expectedSize); 0512 QCOMPARE(symlinkItem.time(KFileItem::ModificationTime), symlinkTime); 0513 0514 // Symlink to directory (#162544) 0515 QVERIFY(QFile::remove(symlink)); 0516 QVERIFY(QFile(tempDir.path() + '/').link(symlink)); 0517 KFileItem symlinkToDirItem(symlinkUrl); 0518 QVERIFY(symlinkToDirItem.isDir()); 0519 QVERIFY(symlinkToDirItem.isLink()); 0520 symlinkToDirItem.refresh(); 0521 QVERIFY(symlinkToDirItem.isDir()); 0522 QVERIFY(symlinkToDirItem.isLink()); 0523 } 0524 0525 void KFileItemTest::testExists() 0526 { 0527 QTest::failOnWarning(QRegularExpression(".?")); 0528 0529 KFileItem dummy; 0530 QVERIFY(!dummy.exists()); 0531 0532 QTemporaryFile f; 0533 QVERIFY(f.open()); 0534 f.close(); 0535 const auto fileName = f.fileName(); 0536 dummy = KFileItem(QUrl::fromLocalFile(fileName)); 0537 dummy.refresh(); 0538 QVERIFY(dummy.exists()); 0539 0540 QVERIFY(QFile::remove(fileName)); 0541 QVERIFY(dummy.exists()); 0542 dummy.refresh(); 0543 QVERIFY(!dummy.exists()); 0544 0545 dummy = KFileItem(QUrl::fromLocalFile(fileName)); 0546 // this should trigger a warning 0547 QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("^KFileItem: exists called when not initialised QUrl")); 0548 QVERIFY(!dummy.exists()); 0549 } 0550 0551 void KFileItemTest::testDotDirectory() 0552 { 0553 QTemporaryDir tempDir; 0554 QFile file(tempDir.path() + "/.directory"); 0555 QVERIFY(file.open(QIODevice::WriteOnly)); 0556 file.write("[Desktop Entry]\nIcon=foo\nComment=com\n"); 0557 file.close(); 0558 { 0559 KFileItem fileItem(QUrl::fromLocalFile(tempDir.path() + '/'), QString(), KFileItem::Unknown); 0560 QVERIFY(fileItem.isLocalFile()); 0561 QCOMPARE(fileItem.mimeComment(), QStringLiteral("com")); 0562 QCOMPARE(fileItem.iconName(), QStringLiteral("foo")); 0563 } 0564 // Test for calling iconName first, to trigger MIME type resolution 0565 { 0566 KFileItem fileItem(QUrl::fromLocalFile(tempDir.path()), QString(), KFileItem::Unknown); 0567 QVERIFY(fileItem.isLocalFile()); 0568 QCOMPARE(fileItem.iconName(), QStringLiteral("foo")); 0569 } 0570 } 0571 0572 void KFileItemTest::testDecodeFileName_data() 0573 { 0574 QTest::addColumn<QString>("filename"); 0575 QTest::addColumn<QString>("expectedText"); 0576 0577 QTest::newRow("simple") << "filename" 0578 << "filename"; 0579 QTest::newRow("/ at end") << QString(QStringLiteral("foo") + QChar(0x2044)) << QString(QStringLiteral("foo") + QChar(0x2044)); 0580 QTest::newRow("/ at begin") << QString(QChar(0x2044)) << QString(QChar(0x2044)); 0581 } 0582 0583 void KFileItemTest::testDecodeFileName() 0584 { 0585 QFETCH(QString, filename); 0586 QFETCH(QString, expectedText); 0587 QCOMPARE(KIO::decodeFileName(filename), expectedText); 0588 } 0589 0590 void KFileItemTest::testEncodeFileName_data() 0591 { 0592 QTest::addColumn<QString>("text"); 0593 QTest::addColumn<QString>("expectedFileName"); 0594 0595 QTest::newRow("simple") << "filename" 0596 << "filename"; 0597 QTest::newRow("/ at end") << "foo/" << QString(QStringLiteral("foo") + QChar(0x2044)); 0598 QTest::newRow("/ at begin") << "/" << QString(QChar(0x2044)); 0599 } 0600 0601 void KFileItemTest::testEncodeFileName() 0602 { 0603 QFETCH(QString, text); 0604 QFETCH(QString, expectedFileName); 0605 QCOMPARE(KIO::encodeFileName(text), expectedFileName); 0606 } 0607 0608 void KFileItemTest::testListProperties_data() 0609 { 0610 QTest::addColumn<QString>("itemDescriptions"); 0611 QTest::addColumn<bool>("expectedReading"); 0612 QTest::addColumn<bool>("expectedDeleting"); 0613 QTest::addColumn<bool>("expectedIsLocal"); 0614 QTest::addColumn<bool>("expectedIsDirectory"); 0615 QTest::addColumn<bool>("expectedIsFile"); 0616 QTest::addColumn<QString>("expectedMimeType"); 0617 QTest::addColumn<QString>("expectedMimeGroup"); 0618 0619 /* clang-format off */ 0620 QTest::newRow("one file") << "f" << true << true << true << false << true << "text/plain" << "text"; 0621 QTest::newRow("one dir") << "d" << true << true << true << true << false << "inode/directory" << "inode"; 0622 QTest::newRow("root dir") << "/" << true << false << true << true << false << "inode/directory" << "inode"; 0623 QTest::newRow("file+dir") << "fd" << true << true << true << false << false << "" << ""; 0624 QTest::newRow("two dirs") << "dd" << true << true << true << true << false << "inode/directory" << "inode"; 0625 QTest::newRow("dir+root dir") << "d/" << true << false << true << true << false << "inode/directory" << "inode"; 0626 QTest::newRow("two (text+html) files") << "ff" << true << true << true << false << true << "" << "text"; 0627 QTest::newRow("three (text+html+empty) files") << "fff" << true << true << true << false << true << "" << ""; 0628 QTest::newRow("http url") << "h" << true << true /*says kio_http...*/ << false << false << true << "application/octet-stream" << "application"; 0629 QTest::newRow("2 http urls") << "hh" << true << true /*says kio_http...*/ << false << false << true << "application/octet-stream" << "application"; 0630 /* clang-format on */ 0631 } 0632 0633 void KFileItemTest::testListProperties() 0634 { 0635 QFETCH(QString, itemDescriptions); 0636 QFETCH(bool, expectedReading); 0637 QFETCH(bool, expectedDeleting); 0638 QFETCH(bool, expectedIsLocal); 0639 QFETCH(bool, expectedIsDirectory); 0640 QFETCH(bool, expectedIsFile); 0641 QFETCH(QString, expectedMimeType); 0642 QFETCH(QString, expectedMimeGroup); 0643 0644 QTemporaryDir tempDir; 0645 QDir baseDir(tempDir.path()); 0646 KFileItemList items; 0647 for (int i = 0; i < itemDescriptions.size(); ++i) { 0648 QString fileName = tempDir.path() + "/file" + QString::number(i); 0649 switch (itemDescriptions[i].toLatin1()) { 0650 case 'f': { 0651 if (i == 1) { // 2nd file is html 0652 fileName += QLatin1String(".html"); 0653 } 0654 QFile file(fileName); 0655 QVERIFY(file.open(QIODevice::WriteOnly)); 0656 if (i == 0) { 0657 file.write("Hello"); 0658 } else if (i == 1) { 0659 file.write("<html>"); 0660 } // i == 2: leave the file empty 0661 file.close(); 0662 KFileItem item(QUrl::fromLocalFile(fileName), QString(), KFileItem::Unknown); 0663 if (i == 0) { 0664 QCOMPARE(item.mimetype(), "text/plain"); 0665 } else if (i == 1) { 0666 QCOMPARE(item.mimetype(), "text/html"); 0667 } else if (i == 2) { 0668 QCOMPARE(item.mimetype(), "application/x-zerosize"); 0669 } 0670 items.push_back(std::move(item)); 0671 break; 0672 } 0673 case 'd': 0674 QVERIFY(baseDir.mkdir(fileName)); 0675 items << KFileItem(QUrl::fromLocalFile(fileName), QString(), KFileItem::Unknown); 0676 break; 0677 case '/': 0678 items << KFileItem(QUrl::fromLocalFile(QStringLiteral("/")), QString(), KFileItem::Unknown); 0679 break; 0680 case 'h': 0681 items << KFileItem(QUrl(QStringLiteral("http://www.kde.org")), QString(), KFileItem::Unknown); 0682 break; 0683 default: 0684 QVERIFY(false); 0685 } 0686 } 0687 KFileItemListProperties props(items); 0688 QCOMPARE(props.supportsReading(), expectedReading); 0689 QCOMPARE(props.supportsDeleting(), expectedDeleting); 0690 QCOMPARE(props.isLocal(), expectedIsLocal); 0691 QCOMPARE(props.isDirectory(), expectedIsDirectory); 0692 QCOMPARE(props.isFile(), expectedIsFile); 0693 QCOMPARE(props.mimeType(), expectedMimeType); 0694 QCOMPARE(props.mimeGroup(), expectedMimeGroup); 0695 } 0696 0697 void KFileItemTest::testIconNameForUrl_data() 0698 { 0699 QTest::addColumn<QUrl>("url"); 0700 QTest::addColumn<QString>("expectedIcon"); 0701 0702 QTest::newRow("root") << QUrl("file:/") << "inode-directory"; // the icon comes from KFileItem 0703 if (QFile::exists(QStringLiteral("/tmp"))) { 0704 QTest::newRow("subdir") << QUrl::fromLocalFile("/tmp") << "folder-temp"; 0705 } 0706 0707 QTest::newRow("home") << QUrl::fromLocalFile(QDir::homePath()) << "user-home"; 0708 const QString moviesPath = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).constFirst(); 0709 if (QFileInfo::exists(moviesPath)) { 0710 QTest::newRow("videos") << QUrl::fromLocalFile(moviesPath) << (moviesPath == QDir::homePath() ? "user-home" : "folder-videos"); 0711 } 0712 0713 QTest::newRow("empty") << QUrl() << "unknown"; 0714 QTest::newRow("relative") << QUrl("foo") << "unknown"; 0715 QTest::newRow("tilde") << QUrl("~") << "unknown"; 0716 0717 QTest::newRow("unknownscheme folder") << QUrl("unknownscheme:/") << "inode-directory"; 0718 QTest::newRow("unknownscheme file") << QUrl("unknownscheme:/test") << "application-octet-stream"; 0719 0720 QTest::newRow("trash:/ itself") << QUrl("trash:/") << "user-trash-full"; 0721 QTest::newRow("folder under trash:/") << QUrl("trash:/folder/") << "inode-directory"; 0722 QTest::newRow("file under trash:/") << QUrl("trash:/test") << "application-octet-stream"; 0723 QTest::newRow("image file under trash:/") << QUrl("trash:/test.png") << "image-png"; 0724 0725 QTest::newRow("https scheme") << QUrl("https://kde.org/") << "text-html"; 0726 0727 if (KProtocolInfo::isKnownProtocol("smb")) { 0728 QTest::newRow("smb root") << QUrl("smb:/") << "network-workgroup"; 0729 QTest::newRow("smb unknown file") << QUrl("smb:/test") << "network-workgroup"; 0730 QTest::newRow("smb directory/") << QUrl("smb:/unknown/") << "inode-directory"; 0731 QTest::newRow("smb image file") << QUrl("smb:/test.png") << "image-png"; 0732 } 0733 } 0734 0735 void KFileItemTest::testIconNameForUrl() 0736 { 0737 QFETCH(QUrl, url); 0738 QFETCH(QString, expectedIcon); 0739 0740 if (KIO::iconNameForUrl(url) != expectedIcon) { 0741 qDebug() << url; 0742 QCOMPARE(KIO::iconNameForUrl(url), expectedIcon); 0743 } 0744 } 0745 0746 void KFileItemTest::testMimetypeForRemoteFolder() 0747 { 0748 KIO::UDSEntry entry; 0749 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("foo")); 0750 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0751 QUrl url(QStringLiteral("smb://remoteFolder/foo")); 0752 KFileItem fileItem(entry, url); 0753 0754 QCOMPARE(fileItem.mimetype(), QStringLiteral("inode/directory")); 0755 } 0756 0757 void KFileItemTest::testMimetypeForRemoteFolderWithFileType() 0758 { 0759 QString udsMimeType = QStringLiteral("application/x-smb-workgroup"); 0760 QVERIFY2(QMimeDatabase().mimeTypeForName(udsMimeType).isValid(), 0761 qPrintable(QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).join(':'))); // kcoreaddons installed? XDG_DATA_DIRS set? 0762 KIO::UDSEntry entry; 0763 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("foo")); 0764 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0765 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, udsMimeType); 0766 0767 QUrl url(QStringLiteral("smb://remoteFolder/foo")); 0768 KFileItem fileItem(entry, url); 0769 0770 QCOMPARE(fileItem.mimetype(), udsMimeType); 0771 } 0772 0773 void KFileItemTest::testCurrentMimetypeForRemoteFolder() 0774 { 0775 KIO::UDSEntry entry; 0776 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("foo")); 0777 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0778 QUrl url(QStringLiteral("smb://remoteFolder/foo")); 0779 KFileItem fileItem(entry, url); 0780 0781 QCOMPARE(fileItem.currentMimeType().name(), QStringLiteral("inode/directory")); 0782 } 0783 0784 void KFileItemTest::testCurrentMimetypeForRemoteFolderWithFileType() 0785 { 0786 QString udsMimeType = QStringLiteral("application/x-smb-workgroup"); 0787 KIO::UDSEntry entry; 0788 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("foo")); 0789 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0790 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, udsMimeType); 0791 0792 QUrl url(QStringLiteral("smb://remoteFolder/foo")); 0793 KFileItem fileItem(entry, url); 0794 0795 QCOMPARE(fileItem.currentMimeType().name(), udsMimeType); 0796 } 0797 0798 void KFileItemTest::testIconNameForCustomFolderIcons() 0799 { 0800 // Custom folder icons should be displayed (bug 350612) 0801 0802 const QString iconName = QStringLiteral("folder-music"); 0803 0804 QTemporaryDir tempDir; 0805 const QUrl url = QUrl::fromLocalFile(tempDir.path()); 0806 KDesktopFile cfg(tempDir.path() + QLatin1String("/.directory")); 0807 cfg.desktopGroup().writeEntry("Icon", iconName); 0808 cfg.sync(); 0809 0810 KIO::UDSEntry entry; 0811 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0812 KFileItem fileItem(entry, url); 0813 0814 QCOMPARE(fileItem.iconName(), iconName); 0815 } 0816 0817 void KFileItemTest::testIconNameForStandardPath() 0818 { 0819 const QString iconName = QStringLiteral("folder-videos"); 0820 const QUrl url = QUrl::fromLocalFile(QDir::homePath() + QLatin1String("/Videos")); 0821 QStandardPaths::setTestModeEnabled(true); 0822 0823 KIO::UDSEntry entry; 0824 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0825 KFileItem fileItem(entry, url); 0826 0827 QCOMPARE(fileItem.iconName(), iconName); 0828 } 0829 0830 #ifndef Q_OS_WIN // user/group/other write permissions are not handled on windows 0831 0832 void KFileItemTest::testIsReadable_data() 0833 { 0834 QTest::addColumn<int>("mode"); 0835 QTest::addColumn<bool>("readable"); 0836 0837 QTest::newRow("fully-readable") << 0444 << true; 0838 QTest::newRow("user-readable") << 0400 << true; 0839 QTest::newRow("user-readable2") << 0440 << true; 0840 QTest::newRow("not-readable-by-us") << 0044 << false; 0841 QTest::newRow("not-readable-by-us2") << 0004 << false; 0842 QTest::newRow("not-readable-at-all") << 0000 << false; 0843 } 0844 0845 void KFileItemTest::testIsReadable() 0846 { 0847 QFETCH(int, mode); 0848 QFETCH(bool, readable); 0849 0850 QTemporaryFile file; 0851 QVERIFY(file.open()); 0852 int ret = fchmod(file.handle(), (mode_t)mode); 0853 QCOMPARE(ret, 0); 0854 0855 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0856 QCOMPARE(fileItem.isReadable(), readable); 0857 0858 QVERIFY(file.remove()); 0859 // still cached thanks to the cached internal udsentry 0860 QCOMPARE(fileItem.isReadable(), readable); 0861 } 0862 0863 void KFileItemTest::testIsWritable_data() 0864 { 0865 QTest::addColumn<int>("mode"); 0866 QTest::addColumn<bool>("writable"); 0867 0868 QTest::newRow("fully-writable") << 0333 << true; 0869 QTest::newRow("user-writable") << 0300 << true; 0870 QTest::newRow("user-writable2") << 0330 << true; 0871 QTest::newRow("not-writable-by-us") << 0033 << false; 0872 QTest::newRow("not-writable-by-us2") << 0003 << false; 0873 QTest::newRow("not-writable-at-all") << 0000 << false; 0874 } 0875 0876 void KFileItemTest::testIsWritable() 0877 { 0878 QFETCH(int, mode); 0879 QFETCH(bool, writable); 0880 0881 QTemporaryFile file; 0882 QVERIFY(file.open()); 0883 int ret = fchmod(file.handle(), (mode_t)mode); 0884 QCOMPARE(ret, 0); 0885 0886 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0887 QCOMPARE(fileItem.isWritable(), writable); 0888 0889 QVERIFY(file.remove()); 0890 // still cached thanks to the cached internal udsentry 0891 QCOMPARE(fileItem.isWritable(), writable); 0892 } 0893 0894 void KFileItemTest::testIsExecutable_data() 0895 { 0896 QTest::addColumn<int>("mode"); 0897 QTest::addColumn<bool>("executable"); 0898 0899 QTest::newRow("fully-executable") << 0111 << true; 0900 QTest::newRow("user-executable") << 0100 << true; 0901 QTest::newRow("user-executable2") << 0110 << true; 0902 QTest::newRow("not-executable-by-us") << 0011 << false; 0903 QTest::newRow("not-executable-by-us2") << 0001 << false; 0904 QTest::newRow("not-executable-at-all") << 0000 << false; 0905 } 0906 0907 void KFileItemTest::testIsExecutable() 0908 { 0909 QFETCH(int, mode); 0910 QFETCH(bool, executable); 0911 0912 QTemporaryFile file; 0913 QVERIFY(file.open()); 0914 int ret = fchmod(file.handle(), (mode_t)mode); 0915 QCOMPARE(ret, 0); 0916 0917 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); 0918 QCOMPARE(fileItem.isExecutable(), executable); 0919 0920 QVERIFY(file.remove()); 0921 // still cached thanks to the cached internal udsentry 0922 QCOMPARE(fileItem.isExecutable(), executable); 0923 } 0924 0925 // Restore permissions so that the QTemporaryDir cleanup can happen (taken from tst_qsavefile.cpp) 0926 class PermissionRestorer 0927 { 0928 Q_DISABLE_COPY(PermissionRestorer) 0929 public: 0930 explicit PermissionRestorer(const QString &path) 0931 : m_path(path) 0932 { 0933 } 0934 ~PermissionRestorer() 0935 { 0936 restore(); 0937 } 0938 0939 inline void restore() 0940 { 0941 QFile file(m_path); 0942 #ifdef Q_OS_UNIX 0943 file.setPermissions(QFile::Permissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner)); 0944 #else 0945 file.setPermissions(QFile::WriteOwner); 0946 file.remove(); 0947 #endif 0948 } 0949 0950 private: 0951 const QString m_path; 0952 }; 0953 0954 void KFileItemTest::testNonWritableDirectory() 0955 { 0956 // Given a directory with a file in it 0957 QTemporaryDir dir; 0958 QVERIFY2(dir.isValid(), qPrintable(dir.errorString())); 0959 QFile file(dir.path() + "/file1"); 0960 QVERIFY(file.open(QIODevice::WriteOnly)); 0961 QCOMPARE(file.write("Hello"), Q_INT64_C(5)); 0962 file.close(); 0963 // ... which is then made non-writable 0964 QVERIFY(QFile(dir.path()).setPermissions(QFile::ReadOwner | QFile::ExeOwner)); 0965 PermissionRestorer permissionRestorer(dir.path()); 0966 0967 // When using KFileItemListProperties on the file 0968 const KFileItem item(QUrl::fromLocalFile(file.fileName())); 0969 KFileItemListProperties props(KFileItemList{item}); 0970 0971 // Then it should say moving is not supported 0972 QVERIFY(!props.supportsMoving()); 0973 QVERIFY(props.supportsWriting()); // but we can write to the file itself 0974 } 0975 0976 #endif // Q_OS_WIN 0977 0978 #include "moc_kfileitemtest.cpp"