Files
qt-creator/tests/auto/texteditor/highlighter/tst_highlighter.cpp

375 lines
14 KiB
C++
Raw Normal View History

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef WITH_TESTS
#define WITH_TESTS
#endif
#include <texteditor/semantichighlighter.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/texteditorsettings.h>
#include <QObject>
#include <QTextBlock>
#include <QTextDocument>
#include <QtTest>
namespace TextEditor {
class tst_highlighter: public QObject
{
Q_OBJECT
private slots:
void init_testCase();
void init();
void test_setExtraAdditionalFormats();
void test_clearExtraFormats();
void test_incrementalApplyAdditionalFormats();
void test_preeditText();
void cleanup();
private:
QTextDocument *doc = nullptr;
SyntaxHighlighter *highlighter = nullptr;
FontSettings fontsettings;
QHash<int, QTextCharFormat> formatHash;
QTextCharFormat whitespaceFormat;
};
void tst_highlighter::init_testCase()
{
QTextCharFormat c0;
c0.setFontItalic(true);
formatHash[0] = c0;
QTextCharFormat c1;
c1.setFontOverline(true);
formatHash[1] = c1;
}
void tst_highlighter::init()
{
const QString text =
R"(First
Second with spaces
Last)";
doc = new QTextDocument();
doc->setPlainText(text);
highlighter = new SyntaxHighlighter(doc, fontsettings);
}
static const HighlightingResults &highlightingResults()
{
static HighlightingResults results{HighlightingResult(),
HighlightingResult(1, 1, 5, 0),
HighlightingResult(2, 4, 7, 0),
HighlightingResult(2, 17, 5, 1),
HighlightingResult(4, 1, 8, 0),
HighlightingResult(6, 1, 8, 1)};
return results;
}
void tst_highlighter::test_setExtraAdditionalFormats()
{
QCOMPARE(doc->blockCount(), 4);
SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash);
for (auto block = doc->firstBlock(); block.isValid(); block = block.next()) {
QVERIFY(block.blockNumber() < 4);
QVERIFY(block.layout());
auto formats = block.layout()->formats();
switch (block.blockNumber()) {
case 0: // First
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 5);
break;
case 1: // Second with spaces
QCOMPARE(formats.size(), 4);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 6);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), false);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 11);
QCOMPARE(formats.at(1).length, 1);
QCOMPARE(formats.at(2).format.fontItalic(), true);
QCOMPARE(formats.at(2).format.fontOverline(), false);
QCOMPARE(formats.at(2).start, 3);
QCOMPARE(formats.at(2).length, 7);
QCOMPARE(formats.at(3).format.fontItalic(), false);
QCOMPARE(formats.at(3).format.fontOverline(), true);
QCOMPARE(formats.at(3).start, 16);
QCOMPARE(formats.at(3).length, 3);
break;
case 2: //
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), true);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 1);
break;
case 3: // Last
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), true);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), true);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 0);
QCOMPARE(formats.at(1).length, 5);
break;
}
}
}
void tst_highlighter::test_clearExtraFormats()
{
QCOMPARE(doc->blockCount(), 4);
SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash);
QTextBlock firstBlock = doc->findBlockByNumber(0);
QTextBlock spacesLineBlock = doc->findBlockByNumber(1);
QTextBlock emptyLineBlock = doc->findBlockByNumber(2);
QTextBlock lastBlock = doc->findBlockByNumber(3);
highlighter->clearExtraFormats(emptyLineBlock);
QVERIFY(emptyLineBlock.layout()->formats().isEmpty());
highlighter->clearExtraFormats(spacesLineBlock);
auto formats = spacesLineBlock.layout()->formats();
// the spaces are not extra formats and should remain when clearing extra formats
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 6);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), false);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 11);
QCOMPARE(formats.at(1).length, 1);
// first and last should be untouched
formats = firstBlock.layout()->formats();
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 5);
formats = lastBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), true);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), true);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 0);
QCOMPARE(formats.at(1).length, 5);
highlighter->clearAllExtraFormats();
QVERIFY(firstBlock.layout()->formats().isEmpty());
QVERIFY(emptyLineBlock.layout()->formats().isEmpty());
formats = spacesLineBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 6);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), false);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 11);
QCOMPARE(formats.at(1).length, 1);
QVERIFY(lastBlock.layout()->formats().isEmpty());
}
void tst_highlighter::test_incrementalApplyAdditionalFormats()
{
const HighlightingResults newResults{HighlightingResult(),
HighlightingResult(1, 1, 5, 0),
HighlightingResult(2, 4, 7, 0),
HighlightingResult(4, 1, 8, 0),
HighlightingResult(6, 1, 8, 1)};
QCOMPARE(doc->blockCount(), 4);
QTextBlock firstBlock = doc->findBlockByNumber(0);
QTextBlock spacesLineBlock = doc->findBlockByNumber(1);
QTextBlock emptyLineBlock = doc->findBlockByNumber(2);
QTextBlock lastBlock = doc->findBlockByNumber(3);
QFutureInterface<HighlightingResult> fiOld;
fiOld.reportResults(highlightingResults());
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fiOld.future(),
2,
0,
formatHash);
auto formats = firstBlock.layout()->formats();
QVERIFY(formats.isEmpty());
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fiOld.future(),
0,
2,
formatHash);
formats = firstBlock.layout()->formats();
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 5);
formats = spacesLineBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 6);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), false);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 11);
QCOMPARE(formats.at(1).length, 1);
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fiOld.future(),
3,
6,
formatHash);
formats = firstBlock.layout()->formats();
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 5);
formats = lastBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), true);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 1);
QCOMPARE(formats.at(1).format.fontItalic(), true);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 0);
QCOMPARE(formats.at(1).length, 5);
QFutureInterface<HighlightingResult> fiNew;
fiNew.reportResults(newResults);
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fiNew.future(),
0,
3,
formatHash);
// should still contain the highlight from oldResults
formats = emptyLineBlock.layout()->formats();
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), false);
QCOMPARE(formats.at(0).format.fontOverline(), true);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 1);
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fiNew.future(),
3,
4,
formatHash);
// should have no results since the new results do not contain a highlight at that position
formats = emptyLineBlock.layout()->formats();
QVERIFY(formats.isEmpty());
// QTCREATORBUG-29218
highlighter->clearAllExtraFormats();
const HighlightingResults bug29218Results{HighlightingResult(1, 1, 2, 0),
HighlightingResult(1, 3, 2, 1)};
QFutureInterface<HighlightingResult> fi29218;
fi29218.reportResults(bug29218Results);
formats = firstBlock.layout()->formats();
QVERIFY(formats.isEmpty());
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fi29218.future(),
0,
1,
formatHash);
formats = firstBlock.layout()->formats();
QCOMPARE(formats.size(), 1);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 2);
SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter,
fi29218.future(),
1,
2,
formatHash);
formats = firstBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 2);
QCOMPARE(formats.at(1).format.fontItalic(), false);
QCOMPARE(formats.at(1).format.fontOverline(), true);
QCOMPARE(formats.at(1).start, 2);
QCOMPARE(formats.at(1).length, 2);
}
void tst_highlighter::test_preeditText()
{
QCOMPARE(doc->blockCount(), 4);
QTextBlock firstBlock = doc->findBlockByNumber(0);
firstBlock.layout()->setPreeditArea(2, "uaf");
SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash);
auto formats = firstBlock.layout()->formats();
QCOMPARE(formats.size(), 2);
QCOMPARE(formats.at(0).format.fontItalic(), true);
QCOMPARE(formats.at(0).format.fontOverline(), false);
QCOMPARE(formats.at(0).start, 0);
QCOMPARE(formats.at(0).length, 2);
QCOMPARE(formats.at(1).format.fontItalic(), true);
QCOMPARE(formats.at(1).format.fontOverline(), false);
QCOMPARE(formats.at(1).start, 5);
QCOMPARE(formats.at(1).length, 3);
}
void tst_highlighter::cleanup()
{
delete doc;
doc = nullptr;
highlighter = nullptr;
}
} // namespace TextEditor
QTEST_MAIN(TextEditor::tst_highlighter)
#include "tst_highlighter.moc"