File indexing completed on 2024-03-24 15:27:01
0001 /* 0002 * Copyright (C) 2005-2009 David Faure <faure@kde.org> 0003 * 0004 * This library is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU Lesser General Public License as published by 0006 * the Free Software Foundation; either version 2 of the License or ( at 0007 * your option ) version 3 or, at the discretion of KDE e.V. ( which shall 0008 * act as a proxy as in section 14 of the GPLv3 ), any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "kmimetypetest.h" 0022 0023 #include <kde_file.h> 0024 #include <kdeversion.h> // KDE_MAKE_VERSION 0025 #include <kmimetype.h> 0026 #include <ksycoca.h> 0027 #include <kuser.h> 0028 #include <qtemporarydir.h> 0029 #include <kconfiggroup.h> 0030 #include <kdebug.h> 0031 0032 #include <qtest_kde.h> // WARNING: do not port to qtest.h without adding a putenv for XDG_DATA_HOME! User data loss will occur otherwise. 0033 #include <qstandardpaths.h> 0034 #include <qprocess.h> 0035 #include <kmimetypetrader.h> 0036 #include <kservicetypetrader.h> 0037 #include <kmimetyperepository_p.h> 0038 #include <qtemporaryfile.h> 0039 #include <kdesktopfile.h> 0040 0041 #include <QtConcurrentRun> 0042 0043 extern KSERVICE_EXPORT bool kservice_require_kded; 0044 0045 static int initializeLang() 0046 { 0047 qputenv("LC_ALL", "en_US"); 0048 qputenv("LANG", "en_US"); 0049 qputenv("XDG_CURRENT_DESKTOP", "KDE"); 0050 kservice_require_kded = false; 0051 return 0; 0052 } 0053 0054 // Set LANG before QCoreApplication is created 0055 Q_CONSTRUCTOR_FUNCTION(initializeLang) 0056 0057 void KMimeTypeTest::initTestCase() 0058 { 0059 // Clean up local xdg dir in case of leftover mimetype definitions 0060 const QString xdgDir = QString::fromLocal8Bit(getenv("XDG_DATA_HOME")); 0061 if (!xdgDir.isEmpty()) { 0062 QDir d_(xdgDir); 0063 d_.removeRecursively(); 0064 // No need to run update-mime-database here, the dir is entirely gone. 0065 } 0066 0067 bool mustUpdateKSycoca = false; 0068 0069 // Create fake text/x-patch part. 0070 const QString fakePatchPart = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "fakepatchpart.desktop"; 0071 const bool mustCreatePatchPart = !QFile::exists(fakePatchPart); 0072 if (mustCreatePatchPart) { 0073 mustUpdateKSycoca = true; 0074 KDesktopFile file(fakePatchPart); 0075 KConfigGroup group = file.desktopGroup(); 0076 group.writeEntry("Name", "FakePatchPart"); 0077 group.writeEntry("Type", "Service"); 0078 group.writeEntry("X-KDE-Library", "fakepatchpart"); 0079 group.writeEntry("ServiceTypes", "KParts/ReadOnlyPart"); 0080 group.writeEntry("MimeType", "text/x-diff;"); // Use an alias on purpose, to test if that works 0081 group.writeEntry("InitialPreference", 5); 0082 } 0083 0084 // Create fake text/plain part with a higher initial preference than the patch part. 0085 QString fakePart = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "faketextpart.desktop"; 0086 const bool mustCreate = !QFile::exists(fakePart); 0087 if (mustCreate) { 0088 mustUpdateKSycoca = true; 0089 KDesktopFile file(fakePart); 0090 KConfigGroup group = file.desktopGroup(); 0091 group.writeEntry("Name", "FakePart"); 0092 group.writeEntry("Type", "Service"); 0093 group.writeEntry("X-KDE-Library", "faketextpart"); 0094 group.writeEntry("ServiceTypes", "KParts/ReadOnlyPart"); 0095 group.writeEntry("MimeType", "text/plain;"); 0096 group.writeEntry("InitialPreference", 100); 0097 } 0098 0099 // Create fake text/plain ktexteditor plugin. 0100 QString fakePlugin = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "faketextplugin.desktop"; 0101 const bool mustCreatePlugin = !QFile::exists(fakePlugin); 0102 if (mustCreatePlugin) { 0103 mustUpdateKSycoca = true; 0104 KDesktopFile file(fakePlugin); 0105 KConfigGroup group = file.desktopGroup(); 0106 group.writeEntry("Name", "FakePlugin"); 0107 group.writeEntry("Type", "Service"); 0108 group.writeEntry("X-KDE-Library", "faketextplugin"); 0109 group.writeEntry("ServiceTypes", "KPluginInfo"); 0110 group.writeEntry("MimeType", "text/plain;"); 0111 } 0112 0113 // Create fake "NotShowIn=KDE" service 0114 m_nonKdeApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1Char('/') + "fake_nonkde_application.desktop"; 0115 const bool mustCreateNonKdeApp = !QFile::exists(m_nonKdeApp); 0116 if (mustCreateNonKdeApp) { 0117 mustUpdateKSycoca = true; 0118 KDesktopFile file(m_nonKdeApp); 0119 KConfigGroup group = file.desktopGroup(); 0120 group.writeEntry("Name", "NonKDEApp"); 0121 group.writeEntry("Type", "Application"); 0122 group.writeEntry("Exec", "xterm"); 0123 group.writeEntry("NotShowIn", "KDE;FVWM;"); 0124 group.writeEntry("MimeType", "text/plain;"); 0125 group.writeEntry("InitialPreference", "50"); 0126 group.writeEntry("Categories", "Qt;KDE;"); 0127 } 0128 m_nonKdeApp = QFileInfo(m_nonKdeApp).canonicalFilePath(); 0129 0130 // Create fake text/plain app 0131 m_textPlainApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1Char('/') + "fake_textplain_application.desktop"; 0132 const bool mustCreateTextPlainApp = !QFile::exists(m_textPlainApp); 0133 if (mustCreateTextPlainApp) { 0134 mustUpdateKSycoca = true; 0135 KDesktopFile file(m_textPlainApp); 0136 KConfigGroup group = file.desktopGroup(); 0137 group.writeEntry("Name", "NonKDEApp"); 0138 group.writeEntry("Type", "Application"); 0139 group.writeEntry("Exec", "xterm"); 0140 group.writeEntry("MimeType", "text/plain;"); 0141 group.writeEntry("InitialPreference", "40"); 0142 group.writeEntry("Categories", "Qt;KDE;"); 0143 } 0144 m_textPlainApp = QFileInfo(m_textPlainApp).canonicalFilePath(); 0145 0146 if (mustUpdateKSycoca) { 0147 // Update ksycoca in ~/.kde-unit-test after creating the above 0148 QProcess::execute(QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME), QStringList()); 0149 } 0150 0151 QVERIFY(KService::serviceByStorageId("fake_nonkde_application.desktop")); 0152 QVERIFY(KService::serviceByDesktopPath(m_nonKdeApp)); // the desktoppath is the full path nowadays 0153 QVERIFY(KService::serviceByStorageId("fake_textplain_application.desktop")); 0154 QVERIFY(KService::serviceByDesktopPath(m_textPlainApp)); 0155 } 0156 0157 void KMimeTypeTest::cleanupTestCase() 0158 { 0159 // If I want the konqueror unit tests to work, then I better not have a non-working part 0160 // as the preferred part for text/plain... 0161 const QString fakePatchPart = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "fakepatchpart.desktop"; 0162 QFile::remove(fakePatchPart); 0163 const QString fakePart = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "faketextpart.desktop"; 0164 QFile::remove(fakePart); 0165 const QString fakePlugin = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + "faketextplugin.desktop"; 0166 QFile::remove(fakePlugin); 0167 QFile::remove(m_textPlainApp); 0168 QFile::remove(m_nonKdeApp); 0169 QProcess proc; 0170 proc.setProcessChannelMode(QProcess::MergedChannels); // silence kbuildsycoca output 0171 proc.start(QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME), QStringList()); 0172 proc.waitForFinished(); 0173 } 0174 0175 QTEST_KDEMAIN_CORE(KMimeTypeTest) 0176 0177 void KMimeTypeTest::testByName() 0178 { 0179 KMimeType::Ptr s0 = KMimeType::mimeType("application/x-zerosize"); 0180 QVERIFY(s0); 0181 QCOMPARE(s0->name(), QString::fromLatin1("application/x-zerosize")); 0182 QCOMPARE(s0->comment(), QString::fromLatin1("empty document")); 0183 0184 KMimeType::Ptr s0Again = KMimeType::mimeType("application/x-zerosize"); 0185 QCOMPARE(s0Again->name(), s0->name()); 0186 QVERIFY(s0Again != s0); 0187 0188 KMimeType::Ptr s1 = KMimeType::mimeType("text/plain"); 0189 QVERIFY(s1); 0190 QCOMPARE(s1->name(), QString::fromLatin1("text/plain")); 0191 //qDebug("Comment is %s", qPrintable(s1->comment()) ); 0192 0193 KMimeType::Ptr krita = KMimeType::mimeType("application/x-krita"); 0194 QVERIFY(krita); 0195 0196 // Test <comment> parsing with application/rdf+xml which has the english comment after the other ones 0197 KMimeType::Ptr rdf = KMimeType::mimeType("application/rdf+xml"); 0198 QVERIFY(rdf); 0199 QCOMPARE(rdf->comment(), QString::fromLatin1("RDF file")); 0200 0201 KMimeType::Ptr bzip2 = KMimeType::mimeType("application/x-bzip2"); 0202 QVERIFY(bzip2); 0203 QCOMPARE(bzip2->comment(), QString::fromLatin1("Bzip archive")); 0204 0205 KMimeType::Ptr defaultMime = KMimeType::mimeType("application/octet-stream"); 0206 QVERIFY(defaultMime); 0207 QVERIFY(defaultMime->isDefault()); 0208 } 0209 0210 void KMimeTypeTest::testIcons() 0211 { 0212 if (!KUser().isSuperUser()) { // Can't test this one if running as root 0213 QString emptyString; // gcc-3.3 workaround 0214 QTemporaryDir tmp(emptyString); 0215 QFile(tmp.path()).setPermissions(QFileDevice::Permissions()); 0216 tmp.setAutoRemove(true); 0217 //KUrl url( tmp.path() ); 0218 //QCOMPARE(KIO::iconNameForUrl(url), "inode-directory"); // was folder_locked, but we don't have that anymore - TODO 0219 QFile(tmp.path()).setPermissions(QFile::ReadOwner | QFile::ExeOwner); // so we can 'rm -rf' it 0220 } 0221 } 0222 0223 void KMimeTypeTest::testFindByPathUsingFileName_data() 0224 { 0225 QTest::addColumn<QString>("fileName"); 0226 QTest::addColumn<QString>("expectedMimeType"); 0227 // Maybe we could also add a expectedAccuracy column... 0228 0229 QTest::newRow("text") << "textfile.txt" << "text/plain"; 0230 QTest::newRow("case-insensitive search") << "textfile.TxT" << "text/plain"; 0231 // With QMime, this needs shared-mime-info > 0.91. Earlier versions wrote .Z to the mime.cache file... 0232 if (KMimeType::sharedMimeInfoVersion() > KDE_MAKE_VERSION(0, 91, 0)) { 0233 QTest::newRow("case-insensitive match on a non-lowercase glob") << "foo.z" << "application/x-compress"; 0234 } 0235 0236 QTest::newRow("case-sensitive uppercase match") << "textfile.C" << "text/x-c++src"; 0237 QTest::newRow("case-sensitive lowercase match") << "textfile.c" << "text/x-csrc"; 0238 QTest::newRow("case-sensitive long-extension match") << "foo.PS.gz" << "application/x-gzpostscript"; 0239 QTest::newRow("case-sensitive-only match") << "core" << "application/x-core"; 0240 QTest::newRow("case-sensitive-only match") << "Core" << "application/octet-stream"; // #198477 0241 0242 QTest::newRow("desktop file") << "foo.desktop" << "application/x-desktop"; 0243 QTest::newRow("old kdelnk file is x-desktop too") << "foo.kdelnk" << "application/x-desktop"; 0244 QTest::newRow("double-extension file") << "foo.tar.bz2" << "application/x-bzip-compressed-tar"; 0245 QTest::newRow("single-extension file") << "foo.bz2" << "application/x-bzip"; 0246 QTest::newRow(".doc should assume msword") << "somefile.doc" << "application/msword"; // #204139 0247 QTest::newRow("glob that uses [] syntax, 1") << "Makefile" << "text/x-makefile"; 0248 QTest::newRow("glob that uses [] syntax, 2") << "makefile" << "text/x-makefile"; 0249 QTest::newRow("glob that ends with *, no extension") << "README" << "text/x-readme"; 0250 QTest::newRow("glob that ends with *, extension") << "README.foo" << "text/x-readme"; 0251 QTest::newRow("glob that ends with *, also matches *.txt. Higher weight wins.") << "README.txt" << "text/plain"; 0252 QTest::newRow("glob that ends with *, also matches *.nfo. Higher weight wins.") << "README.nfo" << "text/x-nfo"; 0253 // fdo bug 15436, needs shared-mime-info >= 0.40 (and this tests the globs2-parsing code). 0254 QTest::newRow("glob that ends with *, also matches *.pdf. *.pdf has higher weight") << "README.pdf" << "application/pdf"; 0255 QTest::newRow("directory") << "/" << "inode/directory"; 0256 QTest::newRow("doesn't exist, no extension") << "IDontExist" << "application/octet-stream"; 0257 QTest::newRow("doesn't exist but has known extension") << "IDontExist.txt" << "text/plain"; 0258 QTest::newRow("png image") << QFINDTESTDATA("image.png") << "image/png"; 0259 0260 #ifdef Q_OS_WIN 0261 // Windows: use cmake 0262 const QString exePath = QStandardPaths::findExecutable("cmake"); 0263 QVERIFY2(!exePath.isEmpty(), "cmake not found. Isn't it in your $PATH?"); 0264 const QString executableType = QString::fromLatin1("application/x-ms-dos-executable"); 0265 #else 0266 // Linux: cmake can be found as x-sharedlib on CI for some reason, use ls like tst_qmimedatabase does 0267 const QString exePath = QStandardPaths::findExecutable("ls"); 0268 QVERIFY2(!exePath.isEmpty(), "ls not found. Isn't it in your $PATH?"); 0269 const QString executableType = QString::fromLatin1("application/x-executable"); 0270 #endif 0271 QTest::newRow("executable") << exePath << executableType; 0272 } 0273 0274 void KMimeTypeTest::testFindByPathUsingFileName() 0275 { 0276 QFETCH(QString, fileName); 0277 QFETCH(QString, expectedMimeType); 0278 KMimeType::Ptr mime = KMimeType::findByPath(fileName); 0279 QVERIFY(mime); 0280 if (expectedMimeType == QLatin1String("application/x-executable")) { 0281 // see bf87e1cfbd in qtbase 0282 QVERIFY(mime->name() == expectedMimeType || mime->name() == "application/x-sharedlib"); 0283 } else { 0284 QCOMPARE(mime->name(), expectedMimeType); 0285 } 0286 } 0287 0288 void KMimeTypeTest::testAdditionalGlobs_data() 0289 { 0290 // Other globs that are not in shared-mime-info but which users could define themselves. 0291 QTest::addColumn<QString>("filename"); 0292 QTest::addColumn<QString>("pattern"); 0293 QTest::addColumn<bool>("expected"); 0294 0295 QTest::newRow("one star, match") << "foo.txt" << "*.txt" << true; 0296 QTest::newRow("README*, match") << "README.foo" << "README*" << true; 0297 QTest::newRow("README.*, match") << "README.foo" << "README.*" << true; 0298 QTest::newRow("README.*, no match") << "README" << "README.*" << false; 0299 QTest::newRow("two stars, match") << "andre.ts.001" << "*.ts.0*" << true; 0300 QTest::newRow("two stars, no match") << "andre.ts" << "*.ts.0*" << false; 0301 } 0302 0303 void KMimeTypeTest::testAdditionalGlobs() 0304 { 0305 QFETCH(QString, filename); 0306 QFETCH(QString, pattern); 0307 QFETCH(bool, expected); 0308 0309 QCOMPARE(KMimeTypeRepository::matchFileName(filename, pattern), expected); 0310 } 0311 0312 // All the simple tests for findByPath are in testFindByPathUsingFileName_data. 0313 // In here we do the tests that need some content in a temporary file. 0314 void KMimeTypeTest::testFindByPathWithContent() 0315 { 0316 KMimeType::Ptr mime; 0317 0318 // Test a real PDF file. 0319 // If we find x-matlab because it starts with '%' then we are not ordering by priority. 0320 QTemporaryFile tempFile; 0321 QVERIFY(tempFile.open()); 0322 QString tempFileName = tempFile.fileName(); 0323 tempFile.write("%PDF-"); 0324 tempFile.close(); 0325 mime = KMimeType::findByPath(tempFileName); 0326 QVERIFY(mime); 0327 QCOMPARE(mime->name(), QString::fromLatin1("application/pdf")); 0328 // fast mode cannot find the mimetype 0329 mime = KMimeType::findByPath(tempFileName, 0, true); 0330 QVERIFY(mime); 0331 QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream")); 0332 0333 // Test the case where the extension doesn't match the contents: extension wins 0334 { 0335 QTemporaryFile txtTempFile(QDir::tempPath() + QLatin1String("/kmimetypetest_XXXXXX.txt")); 0336 QVERIFY(txtTempFile.open()); 0337 txtTempFile.write("%PDF-"); 0338 QString txtTempFileName = txtTempFile.fileName(); 0339 txtTempFile.close(); 0340 mime = KMimeType::findByPath(txtTempFileName); 0341 QVERIFY(mime); 0342 QCOMPARE(mime->name(), QString::fromLatin1("text/plain")); 0343 // fast mode finds the same 0344 mime = KMimeType::findByPath(txtTempFileName, 0, true); 0345 QVERIFY(mime); 0346 QCOMPARE(mime->name(), QString::fromLatin1("text/plain")); 0347 } 0348 0349 // Now the case where extension differs from contents, but contents has >80 magic rule 0350 // XDG spec used to say: contents wins. But we can't sniff all files... 0351 // XDG spec has now been amended, extensions always win. 0352 { 0353 QTemporaryFile txtTempFile(QDir::tempPath() + QLatin1String("/kmimetypetest_XXXXXX.txt")); 0354 QVERIFY(txtTempFile.open()); 0355 txtTempFile.write("<smil"); 0356 QString txtTempFileName = txtTempFile.fileName(); 0357 txtTempFile.close(); 0358 mime = KMimeType::findByPath(txtTempFileName); 0359 QVERIFY(mime); 0360 QCOMPARE(mime->name(), QString::fromLatin1("text/plain")); 0361 } 0362 } 0363 0364 void KMimeTypeTest::testFindByUrl() 0365 { 0366 // Tests with local files are already done in testFindByPath, 0367 // here we test for remote urls only. 0368 KMimeType::Ptr mime; 0369 mime = KMimeType::findByUrl(KUrl("http://foo/bar.png")); 0370 QVERIFY(mime); 0371 0372 QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream")); // HTTP can't know before downloading 0373 0374 mime = KMimeType::findByUrl(KUrl("http://foo/s0/")); 0375 QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream")); // HTTP can't know before downloading 0376 0377 #if 0 // no such logic in QMimeType, we get default mimetype, KRun will figure it out 0378 if (!KProtocolInfo::isKnownProtocol(KUrl("man:/"))) { 0379 QSKIP("man protocol not installed"); 0380 } 0381 0382 mime = KMimeType::findByUrl(KUrl("man:/ls")); 0383 QVERIFY(mime); 0384 QCOMPARE(mime->name(), QString::fromLatin1("text/html")); 0385 0386 mime = KMimeType::findByUrl(KUrl("man:/ls/")); 0387 QVERIFY(mime); 0388 QCOMPARE(mime->name(), QString::fromLatin1("text/html")); 0389 #endif 0390 0391 mime = KMimeType::findByUrl(KUrl("fish://host/test1")); // like fish does, to test for known extensions 0392 QVERIFY(mime); 0393 QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream")); 0394 } 0395 0396 void KMimeTypeTest::testFindByNameAndContent() 0397 { 0398 KMimeType::Ptr mime; 0399 0400 QByteArray textData = "Hello world"; 0401 // textfile -> text/plain. No extension -> mimetype is found from the contents. 0402 mime = KMimeType::findByNameAndContent("textfile", textData); 0403 QVERIFY(mime); 0404 QCOMPARE(mime->name(), QString::fromLatin1("text/plain")); 0405 0406 // textfile.foo -> text/plain. Unknown extension -> mimetype is found from the contents. 0407 mime = KMimeType::findByNameAndContent("textfile.foo", textData); 0408 QVERIFY(mime); 0409 QCOMPARE(mime->name(), QString::fromLatin1("text/plain")); 0410 0411 // textfile.doc -> application/msword. Text files called *.doc are very rare these days, and no longer defined in kde5.xml 0412 mime = KMimeType::findByNameAndContent("textfile.doc", textData); 0413 QVERIFY(mime); 0414 QCOMPARE(mime->name(), QString::fromLatin1("application/msword")); 0415 0416 // mswordfile.doc -> application/msword. Found by contents, because of the above case. 0417 // Note that it's application/msword, not application/vnd.ms-word, since it's the former that is registered to IANA. 0418 QByteArray mswordData = "\320\317\021\340\241\261\032\341"; 0419 mime = KMimeType::findByNameAndContent("mswordfile.doc", mswordData); 0420 QVERIFY(mime); 0421 if (mime->name() == "application/vnd.ms-word") { // this comes from /usr/share/mime/packages/libreoffice.xml.... 0422 QEXPECT_FAIL("", "libreoffice.xml is messing with us", Continue); 0423 } 0424 // If you get powerpoint instead, then you're hit by https://bugs.freedesktop.org/show_bug.cgi?id=435 - upgrade to shared-mime-info >= 0.22 0425 QCOMPARE(mime->name(), QString::fromLatin1("application/msword")); 0426 0427 // excelfile.xls -> application/vnd.ms-excel. Found by extension. 0428 mime = KMimeType::findByNameAndContent("excelfile.xls", mswordData /*same magic*/); 0429 QVERIFY(mime); 0430 QCOMPARE(mime->name(), QString::fromLatin1("application/vnd.ms-excel")); 0431 0432 // textfile.xls -> application/vnd.ms-excel. Found by extension. User shouldn't rename a text file to .xls ;) 0433 mime = KMimeType::findByNameAndContent("textfile.xls", textData); 0434 QVERIFY(mime); 0435 QCOMPARE(mime->name(), QString::fromLatin1("application/vnd.ms-excel")); 0436 0437 #if 0 // needs shared-mime-info >= 0.20 0438 QByteArray tnefData = "\x78\x9f\x3e\x22"; 0439 mime = KMimeType::findByNameAndContent("tneffile", mswordData); 0440 QVERIFY(mime); 0441 QCOMPARE(mime->name(), QString::fromLatin1("application/vnd.ms-tnef")); 0442 #endif 0443 0444 QByteArray pdfData = "%PDF-"; 0445 mime = KMimeType::findByNameAndContent("foo", pdfData); 0446 QVERIFY(mime); 0447 QCOMPARE(mime->name(), QString::fromLatin1("application/pdf")); 0448 0449 // High-priority rule (80) 0450 QByteArray phpData = "<?php"; 0451 mime = KMimeType::findByNameAndContent("foo", phpData); 0452 QVERIFY(mime); 0453 QCOMPARE(mime->name(), QString::fromLatin1("application/x-php")); 0454 } 0455 0456 void KMimeTypeTest::testFindByContent_data() 0457 { 0458 QTest::addColumn<QByteArray>("data"); 0459 QTest::addColumn<QString>("expectedMimeType"); 0460 QTest::newRow("simple text") << QByteArray("Hello world") << "text/plain"; 0461 QTest::newRow("html: <html>") << QByteArray("<html>foo</html>") << "text/html"; 0462 0463 // fixed in smi-0.30, xml magic has prio 40 0464 QTest::newRow("html: comment+<html>") << QByteArray("<!--foo--><html>foo</html>") << "text/html"; 0465 // https://bugs.freedesktop.org/show_bug.cgi?id=11259, fixed in smi-0.22 0466 QTest::newRow("html: <script>") << QByteArray("<script>foo</script>") << "text/html"; 0467 0468 QTest::newRow("pdf") << QByteArray("%PDF-") << "application/pdf"; 0469 QTest::newRow("no mimetype known") << QByteArray("\261\032\341\265") << "application/octet-stream"; 0470 0471 QByteArray mswordData = "\320\317\021\340\241\261\032\341"; 0472 // same as \xD0\xCF\x11\xE0 \xA1\xB1\x1A\xE1 0473 QVERIFY(KMimeType::isBufferBinaryData(mswordData)); 0474 // We have no magic specific to msword data, so finding x-ole-storage is correct. 0475 // If you get powerpoint instead, then you're hit by https://bugs.freedesktop.org/show_bug.cgi?id=435 - upgrade to shared-mime-info >= 0.22 0476 QTest::newRow("msword") << mswordData << "application/x-ole-storage"; 0477 } 0478 0479 void KMimeTypeTest::testFindByContent() 0480 { 0481 QFETCH(QByteArray, data); 0482 QFETCH(QString, expectedMimeType); 0483 0484 KMimeType::Ptr mime = KMimeType::findByContent(data); 0485 QVERIFY(mime); 0486 QCOMPARE(mime->name(), expectedMimeType); 0487 } 0488 0489 void KMimeTypeTest::testFindByFileContent() 0490 { 0491 KMimeType::Ptr mime; 0492 int accuracy = 0; 0493 0494 // Calling findByFileContent on a directory 0495 mime = KMimeType::findByFileContent("/", &accuracy); 0496 QVERIFY(mime); 0497 QCOMPARE(mime->name(), QString::fromLatin1("inode/directory")); 0498 QCOMPARE(accuracy, 100); 0499 0500 // Albert calls findByFileContent with a URL instead of a path and gets 11021 as accuracy :) 0501 // It was not set inside findByFileContent -> fixed. 0502 mime = KMimeType::findByFileContent("file:///etc/passwd" /*bad example code, use a path instead*/, &accuracy); 0503 QVERIFY(mime); 0504 QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream")); 0505 QCOMPARE(accuracy, 0); 0506 } 0507 0508 void KMimeTypeTest::testAllMimeTypes() 0509 { 0510 const KMimeType::List lst = KMimeType::allMimeTypes(); // does NOT include aliases 0511 QVERIFY(!lst.isEmpty()); 0512 0513 for (KMimeType::List::ConstIterator it = lst.begin(); 0514 it != lst.end(); ++it) { 0515 const KMimeType::Ptr mime = (*it); 0516 const QString name = mime->name(); 0517 //qDebug( "%s", qPrintable( name ) ); 0518 QVERIFY(!name.isEmpty()); 0519 QCOMPARE(name.count('/'), 1); 0520 0521 const KMimeType::Ptr lookedupMime = KMimeType::mimeType(name); 0522 QVERIFY(lookedupMime); // not null 0523 #if 0 // this just breaks too often to run on systems with uncontrolled files in /usr/share/mime/packages 0524 if (name != "application/vnd.ms-word" && name != "application/x-pkcs7-certificates" 0525 && name != "application/x-x509-ca-cert" 0526 && name != "application/x-vnd.kde.kexi" // due to /usr/share/mime/packages/kde.xml from KDE4 0527 && name != "application/x-kexiproject-sqlite" // due to /usr/share/mime/packages/kde.xml from KDE4 0528 && name != "application/vnd.sun.xml.base" // libreoffice.xml messing things up yet again 0529 ) { 0530 QCOMPARE(lookedupMime->name(), name); 0531 // if this fails, you have an alias defined as a real mimetype too! 0532 // 0533 // Note: this also happens with x-win-lnk when your kde.xml defines it as an alias, while 0534 // /usr/share/mime/packages/kde.xml defines it as a real mimetype. This is a false positive, 0535 // remove one of the kde.xml files. 0536 // 0537 // It also happens with application/x-pkcs7-certificates due to 0538 // /usr/share/mime/packages/gcr-crypto-types.xml. Remove that file and run 0539 // `update-mime-database /usr/share/mime`. 0540 } 0541 #endif 0542 } 0543 } 0544 0545 void KMimeTypeTest::testAlias() 0546 { 0547 const KMimeType::Ptr canonical = KMimeType::mimeType("application/xml"); 0548 QVERIFY(canonical); 0549 KMimeType::Ptr alias = KMimeType::mimeType("text/xml"); 0550 QVERIFY(alias); 0551 QCOMPARE(alias->name(), QString("application/xml")); 0552 0553 QVERIFY(alias->is("application/xml")); 0554 QVERIFY(canonical->is("text/xml")); 0555 0556 // Test for bug 197346: does nspluginscan see that audio/mp3 already exists? 0557 bool mustWriteMimeType = !KMimeType::mimeType("audio/mp3"); 0558 QVERIFY(!mustWriteMimeType); 0559 } 0560 0561 void KMimeTypeTest::testMimeTypeParent() 0562 { 0563 // All file-like mimetypes inherit from octet-stream 0564 const KMimeType::Ptr wordperfect = KMimeType::mimeType("application/vnd.wordperfect"); 0565 QVERIFY(wordperfect); 0566 QCOMPARE(wordperfect->parentMimeTypes().join(","), QString("application/octet-stream")); 0567 QVERIFY(wordperfect->is("application/octet-stream")); 0568 0569 QVERIFY(KMimeType::mimeType("image/svg+xml-compressed")->is("application/x-gzip")); 0570 0571 // Check that msword derives from ole-storage [it didn't in 0.20, but we added it to kde.xml] 0572 const KMimeType::Ptr msword = KMimeType::mimeType("application/msword"); 0573 QVERIFY(msword); 0574 const KMimeType::Ptr olestorage = KMimeType::mimeType("application/x-ole-storage"); 0575 QVERIFY(olestorage); 0576 QVERIFY(msword->is(olestorage->name())); 0577 QVERIFY(msword->is("application/octet-stream")); 0578 0579 const KMimeType::Ptr directory = KMimeType::mimeType("inode/directory"); 0580 QVERIFY(directory); 0581 QCOMPARE(directory->parentMimeTypes().count(), 0); 0582 QVERIFY(!directory->is("application/octet-stream")); 0583 0584 // Check that text/x-patch knows that it inherits from text/plain (it says so explicitly) 0585 const KMimeType::Ptr plain = KMimeType::mimeType("text/plain"); 0586 const KMimeType::Ptr derived = KMimeType::mimeType("text/x-patch"); 0587 QVERIFY(derived); 0588 QCOMPARE(derived->parentMimeTypes().join(","), plain->name()); 0589 QVERIFY(derived->is("text/plain")); 0590 QVERIFY(derived->is("application/octet-stream")); 0591 0592 // Check that application/x-shellscript inherits from application/x-executable 0593 // (Otherwise KRun cannot start shellscripts...) 0594 // This is a test for multiple inheritance... 0595 const KMimeType::Ptr shellscript = KMimeType::mimeType("application/x-shellscript"); 0596 QVERIFY(shellscript); 0597 QVERIFY(shellscript->is("text/plain")); 0598 QVERIFY(shellscript->is("application/x-executable")); 0599 const QStringList shellParents = shellscript->parentMimeTypes(); 0600 QVERIFY(shellParents.contains("text/plain")); 0601 QVERIFY(shellParents.contains("application/x-executable")); 0602 QCOMPARE(shellParents.count(), 2); // only the above two 0603 const QStringList allShellParents = shellscript->allParentMimeTypes(); 0604 QVERIFY(allShellParents.contains("text/plain")); 0605 QVERIFY(allShellParents.contains("application/x-executable")); 0606 QVERIFY(allShellParents.contains("application/octet-stream")); 0607 // Must be least-specific last, i.e. breadth first. 0608 QCOMPARE(allShellParents.last(), QString("application/octet-stream")); 0609 0610 // Check that text/x-mrml knows that it inherits from text/plain (implicitly) 0611 const KMimeType::Ptr mrml = KMimeType::mimeType("text/x-mrml"); 0612 if (!mrml) { 0613 QSKIP("kdelibs not installed"); 0614 } 0615 QVERIFY(mrml->is("text/plain")); 0616 QVERIFY(mrml->is("application/octet-stream")); 0617 } 0618 0619 void KMimeTypeTest::testMimeTypeInheritancePerformance() 0620 { 0621 // Check performance of is(). In kde3 the list of mimetypes with previews had 63 items... 0622 // We could get it with KServiceTypeTrader::self()->query("ThumbCreator") and the "MimeTypes" 0623 // property, but this would give variable results and requires other modules installed. 0624 QStringList mimeTypes; mimeTypes << "image/jpeg" << "image/png" << "image/tiff" << "text/plain" << "text/html"; 0625 mimeTypes += mimeTypes; 0626 mimeTypes += mimeTypes; 0627 mimeTypes += mimeTypes; 0628 QCOMPARE(mimeTypes.count(), 40); 0629 KMimeType::Ptr mime = KMimeType::mimeType("text/x-chdr"); 0630 QVERIFY(mime); 0631 QTime dt; dt.start(); 0632 QBENCHMARK { 0633 QString match; 0634 foreach (const QString &mt, mimeTypes) 0635 { 0636 if (mime->is(mt)) { 0637 match = mt; 0638 // of course there would normally be a "break" here, but we're testing worse-case 0639 // performance here 0640 } 0641 } 0642 QCOMPARE(match, QString("text/plain")); 0643 } 0644 // Results on David's machine (April 2009): 0645 // With the KMimeType::is() code that loaded every parent KMimeType: 0646 // 3.5 msec / 7,000,000 ticks / 5,021,498 instr. loads per iteration 0647 // After the QHash for parent mimetypes in ksycoca, removing the need to load full mimetypes: 0648 // 0.57 msec / 1,115,000 ticks / 938,356 instr. loads per iteration 0649 // After converting the QMap for aliases into a QHash too: 0650 // 0.48 msec / 960,000 ticks / 791,404 instr. loads per iteration 0651 // July 2010: After moving KMimeType out of ksycoca: 0652 // 0.21 msec / 494,000 ticks / 568,345 instr. loads per iteration 0653 } 0654 0655 // Helper method for all the trader tests 0656 static bool offerListHasService(const KService::List &offers, 0657 const QString &entryPath) 0658 { 0659 bool found = false; 0660 KService::List::const_iterator it = offers.begin(); 0661 for (; it != offers.end(); ++it) { 0662 if ((*it)->entryPath() == entryPath) { 0663 if (found) { // should be there only once 0664 qWarning("ERROR: %s was found twice in the list", qPrintable(entryPath)); 0665 return false; // make test fail 0666 } 0667 found = true; 0668 } 0669 } 0670 return found; 0671 } 0672 0673 void KMimeTypeTest::testMimeTypeTraderForTextPlain() 0674 { 0675 if (!KSycoca::isAvailable()) { 0676 QSKIP("ksycoca not available"); 0677 } 0678 0679 // Querying mimetype trader for services associated with text/plain 0680 KService::List offers = KMimeTypeTrader::self()->query("text/plain", "KParts/ReadOnlyPart"); 0681 QVERIFY(!offerListHasService(offers, "fakepatchpart.desktop")); 0682 QVERIFY(offerListHasService(offers, "faketextpart.desktop")); 0683 0684 offers = KMimeTypeTrader::self()->query("text/plain", "KPluginInfo"); 0685 QVERIFY(offers.count() > 0); 0686 0687 // We should have at least the fake text plugin that we created for this. 0688 // (The actual plugins from kdelibs don't mention text/plain anymore) 0689 QVERIFY(offerListHasService(offers, "faketextplugin.desktop")); 0690 0691 // We shouldn't have non-plugins 0692 QVERIFY(!offerListHasService(offers, "fakepatchpart.desktop")); 0693 QVERIFY(!offerListHasService(offers, "faketextpart.desktop")); 0694 } 0695 0696 void KMimeTypeTest::testMimeTypeTraderForDerivedMimeType() 0697 { 0698 if (!KSycoca::isAvailable()) { 0699 QSKIP("ksycoca not available"); 0700 } 0701 0702 // Querying mimetype trader for services associated with text/x-patch, which inherits from text/plain 0703 KService::List offers = KMimeTypeTrader::self()->query("text/x-patch", "KParts/ReadOnlyPart"); 0704 QVERIFY(offerListHasService(offers, "fakepatchpart.desktop")); 0705 QVERIFY(offerListHasService(offers, "faketextpart.desktop")); 0706 QVERIFY((*offers.begin())->entryPath() != "faketextpart.desktop"); // in the list, but not preferred 0707 0708 offers = KMimeTypeTrader::self()->query("text/x-patch", "KPluginInfo"); 0709 QVERIFY(offers.count() > 0); 0710 0711 // We should have at least the fake text plugin that we created for this. 0712 // (The actual plugins from kdelibs don't mention text/plain anymore) 0713 QVERIFY(offerListHasService(offers, "faketextplugin.desktop")); 0714 0715 offers = KMimeTypeTrader::self()->query("text/x-patch", "Application"); 0716 QVERIFY(!offerListHasService(offers, "faketextpart.desktop")); 0717 0718 // We shouldn't have non-kde apps 0719 Q_FOREACH (KService::Ptr service, offers) { 0720 kDebug() << service->name() << service->entryPath(); 0721 } 0722 0723 QVERIFY(!offerListHasService(offers, m_nonKdeApp)); 0724 } 0725 0726 void KMimeTypeTest::testPreferredService() 0727 { 0728 // The "NotShowIn=KDE" service should not be the preferred one! 0729 KService::Ptr serv = KMimeTypeTrader::self()->preferredService("text/plain"); 0730 QVERIFY(serv); 0731 qDebug() << serv->entryPath(); 0732 QVERIFY(serv->entryPath() != m_nonKdeApp); 0733 QCOMPARE(serv->entryPath(), m_textPlainApp); 0734 } 0735 0736 void KMimeTypeTest::testMimeTypeTraderForAlias() 0737 { 0738 if (!KSycoca::isAvailable()) { 0739 QSKIP("ksycoca not available"); 0740 } 0741 0742 const KService::List referenceOffers = KMimeTypeTrader::self()->query("application/xml", "KParts/ReadOnlyPart"); 0743 QVERIFY(offerListHasService(referenceOffers, "faketextpart.desktop")); 0744 QVERIFY(!offerListHasService(referenceOffers, "fakepatchpart.desktop")); 0745 0746 // Querying mimetype trader for services associated with text/xml, which is an alias for application/xml 0747 const KService::List offers = KMimeTypeTrader::self()->query("text/xml", "KParts/ReadOnlyPart"); 0748 QVERIFY(offerListHasService(offers, "faketextpart.desktop")); 0749 QVERIFY(!offerListHasService(offers, "fakepatchpart.desktop")); 0750 0751 QCOMPARE(offers.count(), referenceOffers.count()); 0752 } 0753 0754 void KMimeTypeTest::testHasServiceType1() // with services constructed with a full path (rare) 0755 { 0756 QString faketextpartPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("/kservices5/") + "faketextpart.desktop"); 0757 QVERIFY(!faketextpartPath.isEmpty()); 0758 KService faketextpart(faketextpartPath); 0759 QVERIFY(faketextpart.hasMimeType("text/plain")); 0760 QVERIFY(!faketextpart.hasMimeType("text/x-patch")); // inherited mimetype; fails 0761 QVERIFY(!faketextpart.hasMimeType("image/png")); 0762 QVERIFY(faketextpart.hasServiceType("KParts/ReadOnlyPart")); 0763 QVERIFY(!faketextpart.hasServiceType("KParts/ReadWritePart")); 0764 QVERIFY(!faketextpart.hasServiceType("KPluginInfo")); 0765 0766 QString textPluginPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("/kservices5/") + "faketextplugin.desktop"); 0767 QVERIFY(!textPluginPath.isEmpty()); 0768 KService textPlugin(textPluginPath); 0769 QVERIFY(textPlugin.hasServiceType("KPluginInfo")); 0770 QVERIFY(!textPlugin.hasServiceType("KParts/ReadOnlyPart")); 0771 } 0772 0773 void KMimeTypeTest::testHasServiceType2() // with services coming from ksycoca 0774 { 0775 KService::Ptr faketextpart = KService::serviceByDesktopPath("faketextpart.desktop"); 0776 QVERIFY(faketextpart); 0777 QVERIFY(faketextpart->hasMimeType("text/plain")); 0778 QVERIFY(faketextpart->hasMimeType("text/x-patch")); // due to inheritance 0779 QVERIFY(!faketextpart->hasMimeType("image/png")); 0780 QVERIFY(faketextpart->hasServiceType("KParts/ReadOnlyPart")); 0781 QVERIFY(!faketextpart->hasServiceType("KParts/ReadWritePart")); 0782 QVERIFY(!faketextpart->hasServiceType("KPluginInfo")); 0783 0784 KService::Ptr textPlugin = KService::serviceByDesktopPath("faketextplugin.desktop"); 0785 QVERIFY(textPlugin); 0786 QVERIFY(textPlugin->hasServiceType("KPluginInfo")); 0787 QVERIFY(!textPlugin->hasServiceType("KParts/ReadOnlyPart")); 0788 } 0789 0790 void KMimeTypeTest::testPatterns_data() 0791 { 0792 QTest::addColumn<QString>("mimeType"); 0793 QTest::addColumn<QString>("patterns"); 0794 QTest::addColumn<QString>("mainExtension"); 0795 QTest::newRow("mimetype with a single pattern") << "application/pdf" << "*.pdf" << ".pdf"; 0796 QTest::newRow("mimetype with multiple patterns") << "application/x-kpresenter" << "*.kpr;*.kpt" << ".kpr"; 0797 if (KMimeType::sharedMimeInfoVersion() > KDE_MAKE_VERSION(0, 60, 0)) { 0798 QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << "*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << ".wp"; 0799 } 0800 QTest::newRow("oasis text mimetype") << "application/vnd.oasis.opendocument.text" << "*.odt" << ".odt"; 0801 QTest::newRow("oasis presentation mimetype") << "application/vnd.oasis.opendocument.presentation" << "*.odp" << ".odp"; 0802 QTest::newRow("mimetype with multiple patterns") << "text/plain" << "*.asc;*.txt;*,v" << ".txt"; 0803 QTest::newRow("mimetype with uncommon pattern") << "application/x-kcachegrind" << "callgrind.out*;cachegrind.out*" << QString(); 0804 QTest::newRow("mimetype with no patterns") << "application/x-ole-storage" << QString() << QString(); 0805 } 0806 0807 void KMimeTypeTest::testPatterns() 0808 { 0809 QFETCH(QString, mimeType); 0810 QFETCH(QString, patterns); 0811 QFETCH(QString, mainExtension); 0812 KMimeType::Ptr mime = KMimeType::mimeType(mimeType); 0813 QVERIFY(mime); 0814 // Sort both lists; order is unreliable since shared-mime-info uses hashes internally. 0815 QStringList expectedPatterns = patterns.split(';', QString::SkipEmptyParts); 0816 expectedPatterns.sort(); 0817 QStringList mimePatterns = mime->patterns(); 0818 0819 if (mimeType == "application/vnd.oasis.opendocument.text" && mimePatterns.contains("*.fodt")) { 0820 QSKIP("Skipping test which would fail due to an upstream bug, see https://bugs.freedesktop.org/show_bug.cgi?id=31242"); 0821 } 0822 0823 if (mimeType == "application/vnd.oasis.opendocument.presentation" && mimePatterns.contains("*.fodp")) { 0824 QSKIP("Skipping test which would fail due to an upstream bug, see https://bugs.freedesktop.org/show_bug.cgi?id=31242"); 0825 } 0826 0827 // shared-mime-info 0.30 adds *,v to text/plain, let's add it from this test so that it works 0828 // with older versions too. 0829 if (mimeType == "text/plain" && !mimePatterns.contains("*,v")) { 0830 mimePatterns.append("*,v"); 0831 } 0832 mimePatterns.sort(); 0833 // Not robust enough, other packages can add additional patterns, like libfm.xml adds *.inf to text/plain 0834 //QCOMPARE(mimePatterns.join(";"), expectedPatterns.join(";")); 0835 Q_FOREACH (const QString &expected, expectedPatterns) { 0836 QVERIFY2(mimePatterns.contains(expected), qPrintable(mimeType + " did not have pattern " + expected)); 0837 } 0838 0839 QCOMPARE(mime->mainExtension(), mainExtension); 0840 } 0841 0842 void KMimeTypeTest::testExtractKnownExtension_data() 0843 { 0844 QTest::addColumn<QString>("fileName"); 0845 QTest::addColumn<QString>("extension"); 0846 QTest::newRow("simple extension") << "foo.pdf" << "pdf"; 0847 QTest::newRow("filename has two extensions, last one matches") << "kpresenter.foo.kpt" << "kpt"; 0848 QTest::newRow("filename has two extensions, pattern for both exist") << "foo.tar.bz2" << "tar.bz2"; 0849 QTest::newRow("bz2 alone works too") << "foo.bz2" << "bz2"; 0850 } 0851 0852 void KMimeTypeTest::testExtractKnownExtension() 0853 { 0854 QFETCH(QString, fileName); 0855 QFETCH(QString, extension); 0856 QCOMPARE(KMimeType::extractKnownExtension(fileName), extension); 0857 } 0858 0859 struct LessMimeType_ByComment { 0860 bool operator()(const KMimeType::Ptr &lhs, const KMimeType::Ptr &rhs) const 0861 { 0862 return lhs->comment() < rhs->comment(); 0863 } 0864 }; 0865 0866 void KMimeTypeTest::testSortByComment() 0867 { 0868 QBENCHMARK { 0869 KMimeType::List sortedList = KMimeType::allMimeTypes(); 0870 std::sort(sortedList.begin(), sortedList.end(), LessMimeType_ByComment()); 0871 } 0872 } 0873 0874 void KMimeTypeTest::testFromThread() 0875 { 0876 // Some simple tests to test more API from testThreads without using _data() 0877 KMimeType::Ptr mime = KMimeType::mimeType("application/pdf"); 0878 QVERIFY(mime); 0879 QCOMPARE(mime->mainExtension(), QString::fromLatin1(".pdf")); 0880 } 0881 0882 void KMimeTypeTest::testThreads() 0883 { 0884 QThreadPool::globalInstance()->setMaxThreadCount(20); 0885 // Note that data-based tests cannot be used here (QTest::fetchData asserts). 0886 QList<QFuture<void> > futures; 0887 futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByUrl); 0888 futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByFileContent); 0889 futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByNameAndContent); 0890 futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByPathWithContent); 0891 futures << QtConcurrent::run(this, &KMimeTypeTest::testAllMimeTypes); 0892 futures << QtConcurrent::run(this, &KMimeTypeTest::testAlias); 0893 futures << QtConcurrent::run(this, &KMimeTypeTest::testMimeTypeParent); 0894 futures << QtConcurrent::run(this, &KMimeTypeTest::testPreferredService); 0895 futures << QtConcurrent::run(this, &KMimeTypeTest::testFromThread); 0896 kDebug() << "Joining all threads"; 0897 Q_FOREACH (QFuture<void> f, futures) { // krazy:exclude=foreach 0898 f.waitForFinished(); 0899 } 0900 } 0901 0902 void KMimeTypeTest::testProperties() 0903 { 0904 KMimeType::Ptr pngMimeType = KMimeType::mimeType("image/png"); 0905 #if 0 // API removed 0906 QVariant comment = pngMimeType->property("Comment"); 0907 QVariant patterns = pngMimeType->property("Patterns"); 0908 0909 QCOMPARE(comment.toString(), pngMimeType->comment()); 0910 QCOMPARE(patterns.toStringList(), pngMimeType->patterns()); 0911 #endif 0912 } 0913 0914 void KMimeTypeTest::testIsNull() 0915 { 0916 KMimeType::Ptr ptr; 0917 QVERIFY(ptr.isNull()); 0918 ptr = KMimeType::mimeType(QStringLiteral("image/jpeg")); 0919 QVERIFY(!ptr.isNull()); 0920 } 0921 0922 #include "moc_kmimetypetest.cpp"