/* This file is part of the KDE libraries * Copyright 2007, 2009, 2010 David Faure * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include "kmimeglobsfileparser_p.h" #include #include #include #include class KMimeFileParserTest : public QObject { Q_OBJECT public: KMimeFileParserTest() {} private Q_SLOTS: void testParseGlobs2File() { const QString ext1 = "*.kmimefileparserunittest"; const QString ext2 = "*.kmimefileparserunittest2"; QByteArray testFile = "# Test data\n" "40:text/plain:*.kmimefileparserunittest:cs\n" "40:text/plain:*.kmimefileparserunittest\n" "20:text/plain:*.kmimefileparserunittest2::futureextension"; QBuffer buf(&testFile); KMimeGlobsFileParser::GlobList textGlobs; QVERIFY(KMimeGlobsFileParser::parseGlobFile(&buf, textGlobs)); //kDebug() << textGlobs.keys(); QCOMPARE(textGlobs.count(), 2); QCOMPARE(textGlobs[0].pattern, ext1); QCOMPARE(textGlobs[0].mimeType, QString("text/plain")); QCOMPARE(textGlobs[0].weight, 40); QCOMPARE(textGlobs[0].casesensitive, true); QCOMPARE(textGlobs[1].pattern, ext2); QCOMPARE(textGlobs[1].weight, 20); QCOMPARE(textGlobs[1].casesensitive, false); QCOMPARE(textGlobs[1].mimeType, QString("text/plain")); } void testParseGlobs() { KMimeGlobsFileParser parser; const QString ext1 = "*.kmimefileparserunittest"; const QString ext2 = "*.kmimefileparserunittest2"; KTemporaryFile globTempFile; QVERIFY(globTempFile.open()); const QByteArray testFile = "# Test data\n50:text/plain:*.kmimefileparserunittest\n50:text/plain:*.kmimefileparserunittest2"; globTempFile.write(testFile); const QString fileName = globTempFile.fileName(); globTempFile.close(); KMimeGlobsFileParser::GlobList globs = parser.parseGlobs(QStringList() << fileName); const QStringList textPlainPatterns = globs.patternsMap().value("text/plain"); QVERIFY(textPlainPatterns.contains(ext1)); QVERIFY(textPlainPatterns.contains(ext2)); } void testMerging() // global+local merging { KMimeGlobsFileParser parser; const QString ext1 = "*.ext1"; const QString ext2 = "*.ext2"; const QString globalext = "*.globalext"; // "local" file // It defines *.ext1 and *.ext2 KTemporaryFile globTempFile1; QVERIFY(globTempFile1.open()); // Defining ext2 twice is a bonus in this test: it tests the case where // people install freedesktop.org.xml and kde.xml into the same prefix; // we shouldn't end up with *.txt twice in the text/plain patterns. const QByteArray testFile1 = "# Test data\n50:text/plain:*.ext1\n50:text/plain:*.ext2\n50:text/plain:*.ext2"; globTempFile1.write(testFile1); const QString fileName1 = globTempFile1.fileName(); globTempFile1.close(); // "global" file // It defines *.ext1 and *.globalext KTemporaryFile globTempFile2; QVERIFY(globTempFile2.open()); const QByteArray testFile2 = "# Test data\n50:text/plain:*.ext1\n50:text/plain:*.globalext"; globTempFile2.write(testFile2); const QString fileName2 = globTempFile2.fileName(); globTempFile2.close(); KMimeGlobsFileParser::GlobList globs = parser.parseGlobs(QStringList() << fileName1 << fileName2); const QStringList textPlainPatterns = globs.patternsMap().value("text/plain"); kDebug() << textPlainPatterns; QCOMPARE(textPlainPatterns.count(ext1), 1); QCOMPARE(textPlainPatterns.count(ext2), 1); QCOMPARE(textPlainPatterns.count(globalext), 1); } void testOverriding() // local overrides global when using __NOGLOBS__ { KMimeGlobsFileParser parser; const QString ext1 = "*.o1"; const QString ext2 = "*.o2"; // "local" file // It defines *.o1 and *.o2 KTemporaryFile globTempFile1; QVERIFY(globTempFile1.open()); const QByteArray testFile1 = "# Test data\n50:text/plain:__NOGLOBS__\n50:text/plain:*.o1\n50:text/plain:*.o2\n50:text/plain:*.o2"; globTempFile1.write(testFile1); const QString fileName1 = globTempFile1.fileName(); globTempFile1.close(); // "global" file // It defines *.o1 and *.exttoberemoved - this will all be overwritten by the local file // so it won't appear. KTemporaryFile globTempFile2; QVERIFY(globTempFile2.open()); const QByteArray testFile2 = "# Test data\n50:text/plain:*.o1\n50:text/plain:*.exttoberemoved"; globTempFile2.write(testFile2); const QString fileName2 = globTempFile2.fileName(); globTempFile2.close(); KMimeGlobsFileParser::GlobList globs = parser.parseGlobs(QStringList() << fileName1 << fileName2); const QStringList textPlainPatterns = globs.patternsMap().value("text/plain"); kDebug() << textPlainPatterns; QCOMPARE(textPlainPatterns.count(ext1), 1); QCOMPARE(textPlainPatterns.count(ext2), 1); QVERIFY(!textPlainPatterns.contains("*.exttoberemoved")); } void testGlobMatchingPerformance_data() { QTest::addColumn("fileName"); QTest::addColumn("expectedMimeType"); QTest::newRow("text") << "textfile.txt" << "text/plain"; QTest::newRow("case-insensitive search") << "textfile.TxT" << "text/plain"; QTest::newRow("glob that ends with *, extension") << "README.foo" << "text/x-readme"; QTest::newRow("doesn't exist, no extension") << "IDontExist" << ""; QTest::newRow("random other case") << "foo.wvc" << "audio/x-wavpack-correction"; QTest::newRow("the .tar.bz2 case; can't stop on short match") << "foo.tar.bz2" << "application/x-bzip-compressed-tar"; // Current results (using -callgrind) : // (mimetype: time with ksycoca (4.4 branch), time with linear search) // 4.4 4.5 linear // text: 122K, 75K, 323K // case-insensitive: 124K, 76K, 324K // README*: 109K, 74K, 235K // doesn't exist: 69K, 70K, 1280K [!] // random other: 116K, 67K, 254K // tar.bz2: 160K, 76K, 214K // Prepare m_allGlobs const QStringList globFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "globs2"); m_allGlobs = KMimeGlobsFileParser::parseGlobs(globFiles); m_patternsMap = m_allGlobs.patternsMap(); qDebug() << m_patternsMap.count() << "mimetypes," << m_allGlobs.count() << "patterns"; } void testGlobMatchingPerformance() { QFETCH(QString, fileName); QFETCH(QString, expectedMimeType); // Is the fast pattern dict worth it? (answer: yes) QBENCHMARK { // To investigate the difference if the current impl is slower than linear search, // comment out one block, callgrind, comment out the other block, callgrind, and compare. #if 1 QStringList mimeList = KMimeTypeRepository::self()->findFromFileName(fileName); QString mime = mimeList.isEmpty() ? QString() : mimeList.first(); QCOMPARE(mime, expectedMimeType); #endif } #if 0 QBENCHMARK { bool verbose = false; QString mime = matchGlobHelper(fileName, verbose); if (mime.isEmpty()) { const QString lowerCase = fileName.toLower(); mime = matchGlobHelper(lowerCase, verbose); } QCOMPARE(mime, expectedMimeType); } #endif } private: // Implementation of linear search, for comparison QString matchGlobHelper(const QString& fileName, bool verbose) const { const QString lowerCaseFileName = fileName.toLower(); QString mime; bool found = false; int numPatterns = 0; KMimeGlobsFileParser::PatternsMap::const_iterator it = m_patternsMap.begin(); const KMimeGlobsFileParser::PatternsMap::const_iterator end = m_patternsMap.end(); for ( ; it != end; ++it ) { ++numPatterns; Q_FOREACH(const QString& pattern, it.value()) { if (KMimeTypeRepository::matchFileName(/*(glob.flags & KMimeTypeRepository::CaseSensitive) ? fileName :*/ lowerCaseFileName, pattern)) { found = true; mime = it.key(); } } if (found) break; } Q_UNUSED(verbose); //if (verbose) // kDebug() << "Tested" << numPatterns << "patterns, found" << mime; return mime; } private: KMimeGlobsFileParser::GlobList m_allGlobs; KMimeGlobsFileParser::PatternsMap m_patternsMap; }; QTEST_KDEMAIN_CORE( KMimeFileParserTest ) #include "kmimeglobsfileparsertest.moc"