File indexing completed on 2024-04-14 03:52: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"