File indexing completed on 2024-05-05 16:22:32

0001 /*
0002     SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "test-config.h"
0008 
0009 #include <KSyntaxHighlighting/AbstractHighlighter>
0010 #include <KSyntaxHighlighting/Definition>
0011 #include <KSyntaxHighlighting/Format>
0012 #include <KSyntaxHighlighting/Repository>
0013 #include <KSyntaxHighlighting/State>
0014 
0015 #include <QDir>
0016 #include <QObject>
0017 #include <QTest>
0018 
0019 using namespace KSyntaxHighlighting;
0020 
0021 class NullHighlighter : public AbstractHighlighter
0022 {
0023 public:
0024     /**
0025      * Read in the given file and cache it for the highlighting benchmarking
0026      * @param inFileName file to read
0027      */
0028     NullHighlighter(const QString &inFileName)
0029     {
0030         QFile f(inFileName);
0031         if (!f.open(QFile::ReadOnly)) {
0032             qWarning() << "Failed to open input file" << inFileName << ":" << f.errorString();
0033             return;
0034         }
0035 
0036         QTextStream in(&f);
0037 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0038         in.setCodec("UTF-8");
0039 #endif
0040         while (!in.atEnd()) {
0041             m_fileContents.append(in.readLine());
0042         }
0043     }
0044 
0045     /**
0046      * highlight the in-memory stored file
0047      * @return number of highlighted lines
0048      */
0049     int highlightFile()
0050     {
0051         State state;
0052         for (const auto &line : std::as_const(m_fileContents)) {
0053             state = highlightLine(line, state);
0054         }
0055         return m_fileContents.size();
0056     }
0057 
0058 protected:
0059     void applyFormat(int, int, const Format &) override
0060     {
0061     }
0062     QStringList m_fileContents;
0063 };
0064 
0065 class HighlighterBenchmark : public QObject
0066 {
0067     Q_OBJECT
0068 public:
0069     explicit HighlighterBenchmark(QObject *parent = nullptr)
0070         : QObject(parent)
0071     {
0072     }
0073 
0074 private:
0075     Repository m_repo;
0076 
0077 private Q_SLOTS:
0078     void initTestCase()
0079     {
0080         initRepositorySearchPaths(m_repo);
0081     }
0082 
0083     void cleanupTestCase()
0084     {
0085     }
0086 
0087     void benchmarkHighlight_data()
0088     {
0089         QTest::addColumn<QString>("inFile");
0090         QTest::addColumn<QString>("syntax");
0091 
0092         const QDir dir(QStringLiteral(TESTSRCDIR "/input"));
0093         for (const auto &fileName : dir.entryList(QDir::Files | QDir::NoSymLinks | QDir::Readable | QDir::Hidden, QDir::Name)) {
0094             if (fileName == QLatin1String(".clang-format")) {
0095                 continue;
0096             }
0097 
0098             const auto inFile = dir.absoluteFilePath(fileName);
0099             if (inFile.endsWith(QLatin1String(".syntax"))) {
0100                 continue;
0101             }
0102 
0103             QString syntax;
0104             QFile syntaxOverride(inFile + QStringLiteral(".syntax"));
0105             if (syntaxOverride.exists() && syntaxOverride.open(QFile::ReadOnly)) {
0106                 syntax = QString::fromUtf8(syntaxOverride.readAll()).trimmed();
0107             }
0108 
0109             QTest::newRow(fileName.toUtf8().constData()) << inFile << syntax;
0110         }
0111     }
0112 
0113     void benchmarkHighlight()
0114     {
0115         QFETCH(QString, inFile);
0116         QFETCH(QString, syntax);
0117 
0118         NullHighlighter highlighter(inFile);
0119         auto def = m_repo.definitionForFileName(inFile);
0120         if (!syntax.isEmpty()) {
0121             def = m_repo.definitionForName(syntax);
0122         }
0123         QVERIFY(def.isValid());
0124         highlighter.setDefinition(def);
0125 
0126         // trigger loading of definition per benchmarking loop
0127         QVERIFY(!def.formats().isEmpty());
0128 
0129         // benchmark the highlighting
0130         // try to highlight ~ 20000 lines per file
0131         // bail out, if file is empty, else we are stuck
0132         for (int i = 0; i <= 20000;) {
0133             int lines = highlighter.highlightFile();
0134             if (lines <= 0) {
0135                 break;
0136             }
0137             i += lines;
0138         }
0139     }
0140 };
0141 
0142 QTEST_GUILESS_MAIN(HighlighterBenchmark)
0143 
0144 #include "highlighter_benchmark.moc"