forked from qt-creator/qt-creator
TextEditor: add tests for semantic highlighter
Change-Id: Id64c933f01c0dbc0e077656b6f4260b93e124311 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -23,8 +23,12 @@ class SyntaxHighlighterPrivate
|
||||
Q_DECLARE_PUBLIC(SyntaxHighlighter)
|
||||
public:
|
||||
SyntaxHighlighterPrivate()
|
||||
: SyntaxHighlighterPrivate(TextEditorSettings::fontSettings())
|
||||
{ }
|
||||
|
||||
SyntaxHighlighterPrivate(const FontSettings &fontSettings)
|
||||
{
|
||||
updateFormats(TextEditorSettings::fontSettings());
|
||||
updateFormats(fontSettings);
|
||||
}
|
||||
|
||||
QPointer<QTextDocument> doc;
|
||||
@@ -76,6 +80,16 @@ void SyntaxHighlighter::delayedRehighlight()
|
||||
rehighlight();
|
||||
}
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent, const FontSettings &fontsettings)
|
||||
: QObject(parent), d_ptr(new SyntaxHighlighterPrivate(fontsettings))
|
||||
{
|
||||
d_ptr->q_ptr = this;
|
||||
if (parent)
|
||||
setDocument(parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, int charsAdded)
|
||||
{
|
||||
bool formatsChanged = false;
|
||||
|
||||
@@ -91,6 +91,11 @@ private:
|
||||
void delayedRehighlight();
|
||||
|
||||
QScopedPointer<SyntaxHighlighterPrivate> d_ptr;
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
friend class tst_highlighter;
|
||||
SyntaxHighlighter(QTextDocument *parent, const FontSettings &fontsettings);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace TextEditor
|
||||
|
||||
@@ -20,6 +20,7 @@ add_subdirectory(qml)
|
||||
add_subdirectory(runextensions)
|
||||
add_subdirectory(sdktool)
|
||||
add_subdirectory(solutions)
|
||||
add_subdirectory(texteditor)
|
||||
add_subdirectory(toolchaincache)
|
||||
add_subdirectory(tracing)
|
||||
add_subdirectory(treeviewfind)
|
||||
|
||||
@@ -23,6 +23,7 @@ Project {
|
||||
"runextensions/runextensions.qbs",
|
||||
"sdktool/sdktool.qbs",
|
||||
"solutions/solutions.qbs",
|
||||
"texteditor/texteditor.qbs",
|
||||
"toolchaincache/toolchaincache.qbs",
|
||||
"tracing/tracing.qbs",
|
||||
"treeviewfind/treeviewfind.qbs",
|
||||
|
||||
1
tests/auto/texteditor/CMakeLists.txt
Normal file
1
tests/auto/texteditor/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_subdirectory(highlighter)
|
||||
4
tests/auto/texteditor/highlighter/CMakeLists.txt
Normal file
4
tests/auto/texteditor/highlighter/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
add_qtc_test(tst_highlighter
|
||||
DEPENDS TextEditor Utils Qt::Widgets
|
||||
SOURCES tst_highlighter.cpp
|
||||
)
|
||||
15
tests/auto/texteditor/highlighter/highlighter.qbs
Normal file
15
tests/auto/texteditor/highlighter/highlighter.qbs
Normal file
@@ -0,0 +1,15 @@
|
||||
import qbs
|
||||
|
||||
QtcAutotest {
|
||||
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "Utils" }
|
||||
Depends { name: "Qt.widgets" } // For QTextDocument & friends
|
||||
|
||||
name: "Highlighter autotest"
|
||||
|
||||
Group {
|
||||
name: "Source Files"
|
||||
files: "tst_highlighter.cpp"
|
||||
}
|
||||
}
|
||||
317
tests/auto/texteditor/highlighter/tst_highlighter.cpp
Normal file
317
tests/auto/texteditor/highlighter/tst_highlighter.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
// 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 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.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());
|
||||
}
|
||||
|
||||
void tst_highlighter::cleanup()
|
||||
{
|
||||
delete doc;
|
||||
doc = nullptr;
|
||||
highlighter = nullptr;
|
||||
}
|
||||
|
||||
} // namespace TextEditor
|
||||
|
||||
QTEST_MAIN(TextEditor::tst_highlighter)
|
||||
|
||||
#include "tst_highlighter.moc"
|
||||
6
tests/auto/texteditor/texteditor.qbs
Normal file
6
tests/auto/texteditor/texteditor.qbs
Normal file
@@ -0,0 +1,6 @@
|
||||
import qbs
|
||||
|
||||
Project {
|
||||
name: "TextEditor autotests"
|
||||
references: [ "highlighter/highlighter.qbs" ]
|
||||
}
|
||||
Reference in New Issue
Block a user