diff --git a/autotests/syntaxrepository_test.cpp b/autotests/syntaxrepository_test.cpp index 7a79dcc..f9e2d64 100644 --- a/autotests/syntaxrepository_test.cpp +++ b/autotests/syntaxrepository_test.cpp @@ -1,349 +1,349 @@ /* Copyright (C) 2016 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License along with this program. If not, see . */ #include "test-config.h" #include #include #include #include #include #include #include #include #include #include namespace KSyntaxHighlighting { class NullHighlighter : public AbstractHighlighter { public: using AbstractHighlighter::highlightLine; void applyFormat(int offset, int length, const Format &format) Q_DECL_OVERRIDE { Q_UNUSED(offset); Q_UNUSED(length); // only here to ensure we don't crash format.isDefaultTextStyle(theme()); format.textColor(theme()); } }; class RepositoryTest : public QObject { Q_OBJECT private: Repository m_repo; private Q_SLOTS: void initTestCase() { QStandardPaths::enableTestMode(true); } void testDefinitionByExtension_data() { QTest::addColumn("fileName"); QTest::addColumn("defName"); QTest::newRow("empty") << QString() << QString(); QTest::newRow("qml") << QStringLiteral("/bla/foo.qml") << QStringLiteral("QML"); QTest::newRow("glsl") << QStringLiteral("flat.frag") << QStringLiteral("GLSL"); // the following ones are defined in multiple syntax definitions QTest::newRow("c") << QStringLiteral("test.c") << QStringLiteral("C"); QTest::newRow("c++") << QStringLiteral("test.cpp") << QStringLiteral("C++"); QTest::newRow("markdown") << QStringLiteral("test.md") << QStringLiteral("Markdown"); QTest::newRow("Makefile 1") << QStringLiteral("Makefile") << QStringLiteral("Makefile"); QTest::newRow("Makefile 2") << QStringLiteral("/some/path/to/Makefile") << QStringLiteral("Makefile"); QTest::newRow("Makefile 3") << QStringLiteral("Makefile.am") << QStringLiteral("Makefile"); } void testDefinitionByExtension() { QFETCH(QString, fileName); QFETCH(QString, defName); auto def = m_repo.definitionForFileName(fileName); if (defName.isEmpty()) { QVERIFY(!def.isValid()); } else { QVERIFY(def.isValid()); QCOMPARE(def.name(), defName); } } void testLoadAll() { foreach (const auto &def, m_repo.definitions()) { QVERIFY(!def.name().isEmpty()); QVERIFY(!def.translatedName().isEmpty()); QVERIFY(!def.isValid() || !def.section().isEmpty()); QVERIFY(!def.isValid() || !def.translatedSection().isEmpty()); // indirectly trigger loading, as we can't reach that from public API // if the loading fails the highlighter will produce empty states NullHighlighter hl; State initialState; hl.setDefinition(def); const auto state = hl.highlightLine(QLatin1String("This should not crash } ] ) !"), initialState); QVERIFY(!def.isValid() || state != initialState); } } void testMetaData() { auto def = m_repo.definitionForName(QLatin1String("Alerts")); QVERIFY(def.isValid()); QVERIFY(def.extensions().isEmpty()); QVERIFY(def.mimeTypes().isEmpty()); QVERIFY(def.version() >= 1.11f); QVERIFY(def.isHidden()); QCOMPARE(def.section(), QLatin1String("Other")); QCOMPARE(def.license(), QLatin1String("MIT")); QVERIFY(def.author().contains(QLatin1String("Dominik"))); QFileInfo fi(def.filePath()); QVERIFY(fi.isAbsolute()); QVERIFY(def.filePath().endsWith(QLatin1String("alert.xml"))); def = m_repo.definitionForName(QLatin1String("C++")); QVERIFY(def.isValid()); QCOMPARE(def.section(), QLatin1String("Sources")); QCOMPARE(def.indenter(), QLatin1String("cstyle")); QCOMPARE(def.style(), QLatin1String("C++")); QVERIFY(def.mimeTypes().contains(QLatin1String("text/x-c++hdr"))); QVERIFY(def.extensions().contains(QLatin1String("*.h"))); QCOMPARE(def.priority(), 9); def = m_repo.definitionForName(QLatin1String("Apache Configuration")); QVERIFY(def.isValid()); QVERIFY(def.extensions().contains(QLatin1String("httpd.conf"))); QVERIFY(def.extensions().contains(QLatin1String(".htaccess*"))); } void testGeneralMetaData() { auto def = m_repo.definitionForName(QLatin1String("C++")); QVERIFY(def.isValid()); QVERIFY(!def.indentationBasedFoldingEnabled()); // comment markers QCOMPARE(def.singleLineCommentMarker(), QLatin1String("//")); QCOMPARE(def.singleLineCommentPosition(), KSyntaxHighlighting::CommentPosition::StartOfLine); const auto cppMultiLineCommentMarker = QPair(QLatin1String("/*"), QLatin1String("*/")); QCOMPARE(def.multiLineCommentMarker(), cppMultiLineCommentMarker); def = m_repo.definitionForName(QLatin1String("Python")); QVERIFY(def.isValid()); // indentation QVERIFY(def.indentationBasedFoldingEnabled()); QCOMPARE(def.foldingIgnoreList(), QStringList() << QLatin1String("(?:\\s+|\\s*#.*)")); // keyword lists QVERIFY(!def.keywordLists().isEmpty()); QVERIFY(def.keywordList(QLatin1String("operators")).contains(QLatin1String("and"))); QVERIFY(!def.keywordList(QLatin1String("does not exits")).contains(QLatin1String("and"))); } void testFormatData() { auto def = m_repo.definitionForName(QLatin1String("ChangeLog")); QVERIFY(def.isValid()); auto formats = def.formats(); QVERIFY(!formats.isEmpty()); // verify that the formats are sorted, such that the order matches the order of the itemDatas in the xml files. auto sortComparator = [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs) { return lhs.id() < rhs.id(); }; QVERIFY(std::is_sorted(formats.begin(), formats.end(), sortComparator)); // check all names are listed QStringList formatNames; foreach (const auto & format, formats) { formatNames.append(format.name()); } const QStringList expectedItemDatas = { QStringLiteral("Normal Text"), QStringLiteral("Name"), QStringLiteral("E-Mail"), QStringLiteral("Date"), QStringLiteral("Entry") }; QCOMPARE(formatNames, expectedItemDatas); } void testIncludedDefinitions() { auto def = m_repo.definitionForName(QLatin1String("C++")); QVERIFY(def.isValid()); auto defs = def.includedDefinitions(); const QStringList expectedDefinitionNames = { QStringLiteral("ISO C++"), QStringLiteral("GCCExtensions"), QStringLiteral("Doxygen"), QStringLiteral("Alerts"), QStringLiteral("Modelines") }; QStringList definitionNames; for (auto d : defs) { QVERIFY(d.isValid()); definitionNames.push_back(d.name()); } QCOMPARE(definitionNames, expectedDefinitionNames); } void testReload() { auto def = m_repo.definitionForName(QLatin1String("QML")); QVERIFY(!m_repo.definitions().isEmpty()); QVERIFY(def.isValid()); NullHighlighter hl; hl.setDefinition(def); auto oldState = hl.highlightLine(QLatin1String("/* TODO this should not crash */"), State()); m_repo.reload(); QVERIFY(!m_repo.definitions().isEmpty()); QVERIFY(!def.isValid()); hl.highlightLine(QLatin1String("/* TODO this should not crash */"), State()); hl.highlightLine(QLatin1String("/* FIXME neither should this crash */"), oldState); QVERIFY(hl.definition().isValid()); QCOMPARE(hl.definition().name(), QLatin1String("QML")); } void testLifetime() { // common mistake with value-type like Repo API, make sure this doesn'T crash NullHighlighter hl; { Repository repo; hl.setDefinition(repo.definitionForName(QLatin1String("C++"))); hl.setTheme(repo.defaultTheme()); } hl.highlightLine(QLatin1String("/**! @todo this should not crash .*/"), State()); } void testCustomPath() { QString testInputPath = QStringLiteral(TESTSRCDIR "/input"); Repository repo; QVERIFY(repo.customSearchPaths().empty()); repo.addCustomSearchPath(testInputPath); QCOMPARE(repo.customSearchPaths().size(), 1); QCOMPARE(repo.customSearchPaths()[0], testInputPath); auto customDefinition = repo.definitionForName(QLatin1String("Test Syntax")); QVERIFY(customDefinition.isValid()); auto customTheme = repo.theme(QLatin1String("Test Theme")); QVERIFY(customTheme.isValid()); } void testInvalidDefinition() { Definition def; QVERIFY(!def.isValid()); QVERIFY(def.filePath().isEmpty()); QCOMPARE(def.name(), QLatin1String("None")); QVERIFY(def.section().isEmpty()); QVERIFY(def.translatedSection().isEmpty()); QVERIFY(def.mimeTypes().isEmpty()); QVERIFY(def.extensions().isEmpty()); QCOMPARE(def.version(), 0); QCOMPARE(def.priority(), 0); QVERIFY(!def.isHidden()); QVERIFY(def.style().isEmpty()); QVERIFY(def.indenter().isEmpty()); QVERIFY(def.author().isEmpty()); QVERIFY(def.license().isEmpty()); QVERIFY(!def.foldingEnabled()); QVERIFY(!def.indentationBasedFoldingEnabled()); QVERIFY(def.foldingIgnoreList().isEmpty()); QVERIFY(def.keywordLists().isEmpty()); QVERIFY(def.formats().isEmpty()); QVERIFY(def.includedDefinitions().isEmpty()); QVERIFY(def.singleLineCommentMarker().isEmpty()); QCOMPARE(def.singleLineCommentPosition(), KSyntaxHighlighting::CommentPosition::StartOfLine); const auto emptyPair = QPair(); QCOMPARE(def.multiLineCommentMarker(), emptyPair); for (QChar c : QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~")) { QVERIFY(def.isWordDelimiter(c)); QVERIFY(def.isWordWrapDelimiter(c)); } } void testDelimiters() { auto def = m_repo.definitionForName(QLatin1String("LaTeX")); QVERIFY(def.isValid()); // check that backslash '\' is removed for (QChar c : QStringLiteral("\t !%&()*+,-./:;<=>?[]^{|}~")) QVERIFY(def.isWordDelimiter(c)); QVERIFY(!def.isWordDelimiter(QLatin1Char('\\'))); // check where breaking a line is valid for (QChar c : QStringLiteral(",{}[]")) QVERIFY(def.isWordWrapDelimiter(c)); } void testFoldingEnabled() { // test invalid folding Definition def; QVERIFY(!def.isValid()); QVERIFY(!def.foldingEnabled()); QVERIFY(!def.indentationBasedFoldingEnabled()); // test no folding def = m_repo.definitionForName(QLatin1String("ChangeLog")); QVERIFY(def.isValid()); QVERIFY(!def.foldingEnabled()); QVERIFY(!def.indentationBasedFoldingEnabled()); - // C++ (itself has no regions, since it includes ISOC++ + // C++ itself has no regions, but it includes ISO C++ def = m_repo.definitionForName(QLatin1String("C++")); QVERIFY(def.isValid()); QVERIFY(def.foldingEnabled()); QVERIFY(!def.indentationBasedFoldingEnabled()); // ISO C++ itself has folding regions def = m_repo.definitionForName(QLatin1String("ISO C++")); QVERIFY(def.isValid()); QVERIFY(def.foldingEnabled()); QVERIFY(!def.indentationBasedFoldingEnabled()); // Python has indentation based folding def = m_repo.definitionForName(QLatin1String("Python")); QVERIFY(def.isValid()); QVERIFY(def.foldingEnabled()); QVERIFY(def.indentationBasedFoldingEnabled()); } }; } QTEST_GUILESS_MAIN(KSyntaxHighlighting::RepositoryTest) #include "syntaxrepository_test.moc"