From b97bfaa7f74158fa009fce9844ec256929e837f9 Mon Sep 17 00:00:00 2001
From: Leandro Melo <leandro.melo@nokia.com>
Date: Wed, 2 Jun 2010 17:34:27 +0200
Subject: [PATCH] Generic highlighter: New unit tests for the highlighter
 engine.

---
 .../generichighlighter/generichighlighter.pro |   2 +-
 .../basetextdocumentlayout.h                  |  44 +
 .../highlighterengine/formats.cpp             |  89 ++
 .../highlighterengine/formats.h               |  75 ++
 .../highlighterengine/highlighterengine.pro   |  25 +
 .../highlighterengine/highlightermock.cpp     | 125 +++
 .../highlighterengine/highlightermock.h       |  92 +++
 .../tst_highlighterengine.cpp                 | 780 ++++++++++++++++++
 8 files changed, 1231 insertions(+), 1 deletion(-)
 create mode 100644 tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h
 create mode 100644 tests/auto/generichighlighter/highlighterengine/formats.cpp
 create mode 100644 tests/auto/generichighlighter/highlighterengine/formats.h
 create mode 100644 tests/auto/generichighlighter/highlighterengine/highlighterengine.pro
 create mode 100644 tests/auto/generichighlighter/highlighterengine/highlightermock.cpp
 create mode 100644 tests/auto/generichighlighter/highlighterengine/highlightermock.h
 create mode 100644 tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp

diff --git a/tests/auto/generichighlighter/generichighlighter.pro b/tests/auto/generichighlighter/generichighlighter.pro
index 97a6f0b863c..0656a4345d3 100644
--- a/tests/auto/generichighlighter/generichighlighter.pro
+++ b/tests/auto/generichighlighter/generichighlighter.pro
@@ -1,2 +1,2 @@
 TEMPLATE = subdirs
-SUBDIRS += specificrules
+SUBDIRS += specificrules highlighterengine
diff --git a/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h b/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h
new file mode 100644
index 00000000000..37320e4361d
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BASETEXTDOCUMENTLAYOUT_H
+#define BASETEXTDOCUMENTLAYOUT_H
+
+/*
+ Since the text editor plugin directory is not included in the search list of the pro file, this
+ file replaces the "real" basetextdocumentlayout.h file. The objective is to simply use
+ QTextBlockUserData instead of TextEditor::TextBlockUserData to avoid "external"
+ dependencies or intrusive defines.
+ */
+
+#include <QtGui/QTextBlockUserData>
+
+typedef QTextBlockUserData TextBlockUserData;
+
+#endif // BASETEXTDOCUMENTLAYOUT_H
diff --git a/tests/auto/generichighlighter/highlighterengine/formats.cpp b/tests/auto/generichighlighter/highlighterengine/formats.cpp
new file mode 100644
index 00000000000..cec5d119ef8
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/formats.cpp
@@ -0,0 +1,89 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formats.h"
+
+#include <QtCore/Qt>
+
+Formats::Formats()
+{
+    m_keywordFormat.setForeground(Qt::darkGray);
+    m_dataTypeFormat.setForeground(Qt::gray);
+    m_decimalFormat.setForeground(Qt::lightGray);
+    m_baseNFormat.setForeground(Qt::red);
+    m_floatFormat.setForeground(Qt::green);
+    m_charFormat.setForeground(Qt::blue);
+    m_stringFormat.setForeground(Qt::cyan);
+    m_commentFormat.setForeground(Qt::magenta);
+    m_alertFormat.setForeground(Qt::yellow);
+    m_errorFormat.setForeground(Qt::darkRed);
+    m_functionFormat.setForeground(Qt::darkGreen);
+    m_regionMarkerFormat.setForeground(Qt::darkBlue);
+    m_othersFormat.setForeground(Qt::darkCyan);
+}
+
+Formats &Formats::instance()
+{
+    static Formats formats;
+    return formats;
+}
+
+QString Formats::name(const QTextCharFormat &format) const
+{
+    if (format == QTextCharFormat())
+        return "Default format";
+    else if (format == m_keywordFormat)
+        return "Keyword";
+    else if (format == m_dataTypeFormat)
+        return "Data type format";
+    else if (format == m_decimalFormat)
+        return "Decimal format";
+    else if (format == m_baseNFormat)
+        return "Base N format";
+    else if (format == m_floatFormat)
+        return "Float format";
+    else if (format == m_charFormat)
+        return "Char format";
+    else if (format == m_stringFormat)
+        return "String format";
+    else if (format == m_commentFormat)
+        return "Comment format";
+    else if (format == m_alertFormat)
+        return "Alert format";
+    else if (format == m_errorFormat)
+        return "Error format";
+    else if (format == m_functionFormat)
+        return "Function format";
+    else if (format == m_regionMarkerFormat)
+        return "Region Marker format";
+    else if (format == m_othersFormat)
+        return "Others format";
+    else
+        return "Unidentified format";
+}
diff --git a/tests/auto/generichighlighter/highlighterengine/formats.h b/tests/auto/generichighlighter/highlighterengine/formats.h
new file mode 100644
index 00000000000..e753732cc19
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/formats.h
@@ -0,0 +1,75 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMATS_H
+#define FORMATS_H
+
+#include <QtGui/QTextCharFormat>
+
+class Formats
+{
+public:
+    static Formats &instance();
+
+    const QTextCharFormat &keywordFormat() const { return m_keywordFormat; }
+    const QTextCharFormat &dataTypeFormat() const { return m_dataTypeFormat; }
+    const QTextCharFormat &decimalFormat() const { return m_decimalFormat; }
+    const QTextCharFormat &baseNFormat() const { return m_baseNFormat; }
+    const QTextCharFormat &floatFormat() const { return m_floatFormat; }
+    const QTextCharFormat &charFormat() const { return m_charFormat; }
+    const QTextCharFormat &stringFormat() const { return m_stringFormat; }
+    const QTextCharFormat &commentFormat() const { return m_commentFormat; }
+    const QTextCharFormat &alertFormat() const { return m_alertFormat; }
+    const QTextCharFormat &errorFormat() const { return m_errorFormat; }
+    const QTextCharFormat &functionFormat() const { return m_functionFormat; }
+    const QTextCharFormat &regionMarketFormat() const { return m_regionMarkerFormat; }
+    const QTextCharFormat &othersFormat() const { return m_othersFormat; }
+
+    QString name(const QTextCharFormat &format) const;
+
+private:
+    Formats();
+    Q_DISABLE_COPY(Formats);
+
+    QTextCharFormat m_keywordFormat;
+    QTextCharFormat m_dataTypeFormat;
+    QTextCharFormat m_decimalFormat;
+    QTextCharFormat m_baseNFormat;
+    QTextCharFormat m_floatFormat;
+    QTextCharFormat m_charFormat;
+    QTextCharFormat m_stringFormat;
+    QTextCharFormat m_commentFormat;
+    QTextCharFormat m_alertFormat;
+    QTextCharFormat m_errorFormat;
+    QTextCharFormat m_functionFormat;
+    QTextCharFormat m_regionMarkerFormat;
+    QTextCharFormat m_othersFormat;
+};
+
+#endif // FORMATS_H
diff --git a/tests/auto/generichighlighter/highlighterengine/highlighterengine.pro b/tests/auto/generichighlighter/highlighterengine/highlighterengine.pro
new file mode 100644
index 00000000000..dec3fa3bd89
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/highlighterengine.pro
@@ -0,0 +1,25 @@
+QT += gui testlib
+
+GENERICHIGHLIGHTERDIR = ../../../../src/plugins/texteditor/generichighlighter
+
+SOURCES += tst_highlighterengine.cpp \
+    highlightermock.cpp \
+    $$GENERICHIGHLIGHTERDIR/highlighter.cpp \
+    $$GENERICHIGHLIGHTERDIR/context.cpp \
+    $$GENERICHIGHLIGHTERDIR/dynamicrule.cpp \
+    $$GENERICHIGHLIGHTERDIR/rule.cpp \
+    $$GENERICHIGHLIGHTERDIR/specificrules.cpp \
+    $$GENERICHIGHLIGHTERDIR/progressdata.cpp \
+    $$GENERICHIGHLIGHTERDIR/highlightdefinition.cpp \
+    $$GENERICHIGHLIGHTERDIR/keywordlist.cpp \
+    $$GENERICHIGHLIGHTERDIR/itemdata.cpp \
+    formats.cpp
+
+HEADERS += \
+    highlightermock.h \
+    basetextdocumentlayout.h \
+    formats.h
+
+INCLUDEPATH += $$GENERICHIGHLIGHTERDIR
+
+TARGET=tst_$$TARGET
diff --git a/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp b/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp
new file mode 100644
index 00000000000..f3de75d19b4
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp
@@ -0,0 +1,125 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightermock.h"
+#include "context.h"
+#include "highlightdefinition.h"
+#include "formats.h"
+
+#include <QtCore/QDebug>
+#include <QtTest/QtTest>
+
+namespace QTest {
+template<>
+char *toString(const QTextCharFormat &format)
+{
+    QByteArray ba = Formats::instance().name(format).toLatin1();
+    return qstrdup(ba.data());
+}
+}
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlighterMock::HighlighterMock(const QSharedPointer<Context> &defaultContext,
+                                 QTextDocument *parent) :
+    Highlighter(defaultContext, parent),
+    m_debugDetails(false),
+    m_statesCounter(0),
+    m_formatsCounter(0),
+    m_noTestCall(false),
+    m_considerEmptyLines(false)
+{}
+
+void HighlighterMock::reset()
+{
+    m_states.clear();
+    m_statesCounter = 0;
+    m_formatSequence.clear();
+    m_formatsCounter = 0;
+    m_debugDetails = false;
+    m_noTestCall = false;
+    m_considerEmptyLines = false;
+}
+
+void HighlighterMock::showDebugDetails()
+{ m_debugDetails = true; }
+
+void HighlighterMock::considerEmptyLines()
+{ m_considerEmptyLines = true; }
+
+void HighlighterMock::startNoTestCalls()
+{ m_noTestCall = true; }
+
+void HighlighterMock::endNoTestCalls()
+{ m_noTestCall = false; }
+
+void HighlighterMock::setExpectedBlockState(const int state)
+{ m_states << state; }
+
+void HighlighterMock::setExpectedBlockStates(const QList<int> &states)
+{ m_states = states; }
+
+void HighlighterMock::setExpectedHighlightSequence(const HighlightSequence &format)
+{ m_formatSequence << format; }
+
+void HighlighterMock::setExpectedHighlightSequences(const QList<HighlightSequence> &formats)
+{ m_formatSequence = formats; }
+
+void HighlighterMock::highlightBlock(const QString &text)
+{
+    Highlighter::highlightBlock(text);
+
+    if (text.isEmpty() && !m_considerEmptyLines)
+        return;
+
+    if (m_noTestCall)
+        return;
+
+    if (m_states.isEmpty() || m_formatSequence.isEmpty())
+        QFAIL("No expected data setup.");
+
+    if (m_debugDetails)
+        qDebug() << "Highlighting" << text;
+
+    if (m_states.size() <= m_statesCounter)
+        QFAIL("Expected state for current block not set.");
+    QCOMPARE(currentBlockState(), m_states.at(m_statesCounter++));
+
+    if (m_formatSequence.size() <= m_formatsCounter)
+        QFAIL("Expected highlight sequence for current block not set.");
+    for (int i = 0; i < text.length(); ++i) {
+        if (text.at(i).isSpace())
+            continue;
+        if (m_debugDetails)
+            qDebug() << "at offset" << i;
+        QCOMPARE(format(i), m_formatSequence.at(m_formatsCounter).m_formats.at(i));
+    }
+    ++m_formatsCounter;
+}
diff --git a/tests/auto/generichighlighter/highlighterengine/highlightermock.h b/tests/auto/generichighlighter/highlighterengine/highlightermock.h
new file mode 100644
index 00000000000..cd8cdb84072
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/highlightermock.h
@@ -0,0 +1,92 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTERMOCK_H
+#define HIGHLIGHTERMOCK_H
+
+#include "highlighter.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+namespace Internal {
+class Context;
+class HighlightDefinition;
+}
+}
+
+struct HighlightSequence
+{
+    HighlightSequence() {}
+    HighlightSequence(int from, int to, const QTextCharFormat &format = QTextCharFormat())
+    { add(from, to, format); }
+    HighlightSequence(const HighlightSequence &sequence)
+    { m_formats = sequence.m_formats; }
+
+    void add(int from, int to, const QTextCharFormat &format = QTextCharFormat())
+    {
+        for (int i = from; i < to; ++i)
+            m_formats.append(format);
+    }
+
+    QList<QTextCharFormat> m_formats;
+};
+
+class HighlighterMock : public TextEditor::Internal::Highlighter
+{
+public:
+    HighlighterMock(const QSharedPointer<TextEditor::Internal::Context> &defaultContext,
+                    QTextDocument *parent = 0);
+
+    void reset();
+    void showDebugDetails();
+    void considerEmptyLines();
+
+    void startNoTestCalls();
+    void endNoTestCalls();
+
+    void setExpectedBlockState(const int state);
+    void setExpectedBlockStates(const QList<int> &states);
+    void setExpectedHighlightSequence(const HighlightSequence &format);
+    void setExpectedHighlightSequences(const QList<HighlightSequence> &formats);
+
+protected:
+    virtual void highlightBlock(const QString &text);
+
+private:
+    QList<int> m_states;
+    int m_statesCounter;
+    QList<HighlightSequence> m_formatSequence;
+    int m_formatsCounter;
+    bool m_debugDetails;
+    bool m_noTestCall;
+    bool m_considerEmptyLines;
+};
+
+#endif // HIGHLIGHTERMOCK_H
diff --git a/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp b/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp
new file mode 100644
index 00000000000..da28d88d3e9
--- /dev/null
+++ b/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp
@@ -0,0 +1,780 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinition.h"
+#include "keywordlist.h"
+#include "itemdata.h"
+#include "context.h"
+#include "specificrules.h"
+#include "highlightermock.h"
+#include "formats.h"
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QList>
+#include <QtCore/QMetaType>
+#include <QtGui/QPlainTextEdit>
+#include <QtTest/QtTest>
+
+using namespace TextEditor;
+using namespace Internal;
+
+Q_DECLARE_METATYPE(HighlightSequence)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<HighlightSequence>)
+
+class tst_HighlighterEngine : public QObject
+{
+    Q_OBJECT
+public:
+    tst_HighlighterEngine();
+
+private slots:    
+    void initTestCase();
+    void init();
+
+    void testSimpleLine();
+    void testSimpleLine_data();
+
+    void testLineContinue();
+    void testLineContinue_data();
+
+    void testEditingLineContinue0();
+    void testEditingLineContinue1();
+    void testEditingLineContinue2();
+    void testEditingLineContinue3();
+    void testEditingLineContinue4();
+    void testEditingLineContinue5();
+
+    void testPersistentStates();
+    void testPersistentStates_data();
+
+private:
+    void createKeywords();
+    void createContexts();
+    void createItemDatas();
+
+    void setExpectedData(int state, const HighlightSequence &seq);
+    void setExpectedData(const QList<int> &states, const QList<HighlightSequence> &seqs);
+    void createColumns();
+    void test();
+    void test(int state, const HighlightSequence &seq, const QString &line);
+    void test(const QList<int> &states, const QList<HighlightSequence> &seqs, const QString &lines);
+
+    void clear(QList<int> *states, QList<HighlightSequence> *sequences) const;
+
+    QList<int> createlDefaultStatesList(int size) const;
+
+    void addCharactersToBegin(QTextBlock block, const QString &s);
+    void addCharactersToEnd(QTextBlock block, const QString &s);
+    void removeFirstCharacters(const QTextBlock &block, int n);
+    void removeLastCharacters(const QTextBlock &block, int n);
+
+    void setupForEditingLineContinue();
+
+    QSharedPointer<HighlightDefinition> m_definition;
+    QScopedPointer<HighlighterMock> m_highlighterMock;
+    QPlainTextEdit m_text;
+};
+
+tst_HighlighterEngine::tst_HighlighterEngine() :
+    m_definition(new HighlightDefinition)
+{}
+
+void tst_HighlighterEngine::initTestCase()
+{
+    QWARN("\n***********************************************************\
+           \n*** Spaces are ignored when comparing text char formats ***\
+           \n***********************************************************");
+
+    createKeywords();
+    createContexts();
+    createItemDatas();
+
+    m_highlighterMock.reset(new HighlighterMock(m_definition->initialContext()));
+    m_highlighterMock->setDocument(m_text.document());
+    m_highlighterMock->configureFormat(Highlighter::Keyword, Formats::instance().keywordFormat());
+    m_highlighterMock->configureFormat(Highlighter::DataType, Formats::instance().dataTypeFormat());
+    m_highlighterMock->configureFormat(Highlighter::Decimal, Formats::instance().decimalFormat());
+    m_highlighterMock->configureFormat(Highlighter::BaseN, Formats::instance().baseNFormat());
+    m_highlighterMock->configureFormat(Highlighter::Float, Formats::instance().floatFormat());
+    m_highlighterMock->configureFormat(Highlighter::Char, Formats::instance().charFormat());
+    m_highlighterMock->configureFormat(Highlighter::String, Formats::instance().stringFormat());
+    m_highlighterMock->configureFormat(Highlighter::Comment, Formats::instance().commentFormat());
+    m_highlighterMock->configureFormat(Highlighter::Alert, Formats::instance().alertFormat());
+    m_highlighterMock->configureFormat(Highlighter::Error, Formats::instance().errorFormat());
+    m_highlighterMock->configureFormat(Highlighter::Function, Formats::instance().functionFormat());
+    m_highlighterMock->configureFormat(Highlighter::RegionMarker,
+                                       Formats::instance().regionMarketFormat());
+    m_highlighterMock->configureFormat(Highlighter::Others, Formats::instance().othersFormat());
+}
+
+void tst_HighlighterEngine::init()
+{
+    m_highlighterMock->reset();
+}
+
+void tst_HighlighterEngine::createKeywords()
+{
+    QSharedPointer<KeywordList> keywords = m_definition->createKeywordList("keywords");
+    keywords->addKeyword("int");
+    keywords->addKeyword("long");
+}
+
+void tst_HighlighterEngine::createContexts()
+{
+    // Normal context
+    QSharedPointer<Context> normal = m_definition->createContext("Normal", true);
+    normal->setItemData("Normal Text");
+    normal->setLineEndContext("#stay");
+    normal->setDefinition(m_definition);
+
+    // AfterHash context
+    QSharedPointer<Context> afterHash = m_definition->createContext("AfterHash", false);
+    afterHash->setItemData("Error");
+    afterHash->setLineEndContext("#pop");
+    afterHash->setDefinition(m_definition);
+
+    // Define context
+    QSharedPointer<Context> define = m_definition->createContext("Define", false);
+    define->setItemData("Preprocessor");
+    define->setLineEndContext("#pop");
+    define->setDefinition(m_definition);
+
+    // Preprocessor context
+    QSharedPointer<Context> preprocessor = m_definition->createContext("Preprocessor", false);
+    preprocessor->setItemData("Preprocessor");
+    preprocessor->setLineEndContext("#pop");
+    preprocessor->setDefinition(m_definition);
+
+    // SimpleComment context
+    QSharedPointer<Context> simpleComment = m_definition->createContext("SimpleComment", false);
+    simpleComment->setItemData("Comment");
+    simpleComment->setLineEndContext("#pop");
+    simpleComment->setDefinition(m_definition);
+
+    // MultilineComment context
+    QSharedPointer<Context> multiComment = m_definition->createContext("MultilineComment", false);
+    multiComment->setItemData("Comment");
+    multiComment->setLineEndContext("#stay");
+    multiComment->setDefinition(m_definition);
+
+    // NestedComment context
+    QSharedPointer<Context> nestedComment = m_definition->createContext("NestedComment", false);
+    nestedComment->setItemData("Other Comment");
+    nestedComment->setLineEndContext("#stay");
+    nestedComment->setDefinition(m_definition);
+
+    // Dummy context
+    QSharedPointer<Context> dummy = m_definition->createContext("Dummy", false);
+    dummy->setItemData("Dummy");
+    dummy->setLineEndContext("#pop");
+    dummy->setDefinition(m_definition);
+
+    // Rules
+    DetectCharRule *r0 = new DetectCharRule;
+    r0->setChar("#");
+    r0->setContext("AfterHash");
+    r0->setFirstNonSpace("true");
+    r0->setLookAhead("true");
+    r0->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r0));
+
+    RegExprRule *r1 = new RegExprRule;
+    r1->setPattern("#\\s*define.*((?=\\\\))");
+    r1->setInsensitive("true");
+    r1->setContext("Define");
+    r1->setItemData("Preprocessor");
+    r1->setFirstNonSpace("true");
+    r1->setDefinition(m_definition);
+    afterHash->addRule(QSharedPointer<Rule>(r1));
+
+    RegExprRule *r2 = new RegExprRule;
+    r2->setPattern("#\\s*(?:define|undef)");
+    r2->setInsensitive("true");
+    r2->setContext("Preprocessor");
+    r2->setItemData("Preprocessor");
+    r2->setFirstNonSpace("true");
+    r2->setDefinition(m_definition);
+    afterHash->addRule(QSharedPointer<Rule>(r2));
+
+    LineContinueRule *r3 = new LineContinueRule;
+    r3->setItemData("Preprocessor");
+    r3->setContext("#stay");
+    r3->setDefinition(m_definition);
+    define->addRule(QSharedPointer<Rule>(r3));
+
+    LineContinueRule *r4 = new LineContinueRule;
+    r4->setItemData("Preprocessor");
+    r4->setContext("#stay");
+    r4->setDefinition(m_definition);
+    preprocessor->addRule(QSharedPointer<Rule>(r4));
+
+    KeywordRule *r5 = new KeywordRule(m_definition);
+    r5->setList("keywords");
+    r5->setItemData("Keyword");
+    r5->setContext("#stay");
+    r5->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r5));
+
+    IntRule *r6 = new IntRule;
+    r6->setItemData("Decimal");
+    r6->setContext("#stay");
+    r6->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r6));
+
+    StringDetectRule *r7 = new StringDetectRule;
+    r7->setItemData("Decimal");
+    r7->setContext("#stay");
+    r7->setString("LL");
+    r7->setInsensitive("true");
+    r7->setDefinition(m_definition);
+    r6->addChild(QSharedPointer<Rule>(r7));
+
+    StringDetectRule *r8 = new StringDetectRule;
+    r8->setItemData("Decimal");
+    r8->setContext("#stay");
+    r8->setString("UL");
+    r8->setInsensitive("true");
+    r8->setDefinition(m_definition);
+    r6->addChild(QSharedPointer<Rule>(r8));
+
+    HlCOctRule *r9 = new HlCOctRule;
+    r9->setItemData("Octal");
+    r9->setContext("#stay");
+    r9->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r9));
+
+    Detect2CharsRule *r10 = new Detect2CharsRule;
+    r10->setChar("/");
+    r10->setChar1("/");
+    r10->setItemData("Comment");
+    r10->setContext("SimpleComment");
+    r10->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r10));
+
+    DetectIdentifierRule *r11 = new DetectIdentifierRule;
+    r11->setDefinition(m_definition);
+    simpleComment->addRule(QSharedPointer<Rule>(r11));
+
+    Detect2CharsRule *r12 = new Detect2CharsRule;
+    r12->setChar("/");
+    r12->setChar1("*");
+    r12->setItemData("Comment");
+    r12->setContext("MultilineComment");
+    r12->setDefinition(m_definition);
+    normal->addRule(QSharedPointer<Rule>(r12));
+
+    Detect2CharsRule *r13 = new Detect2CharsRule;
+    r13->setChar("*");
+    r13->setChar1("/");
+    r13->setItemData("Comment");
+    r13->setContext("#pop");
+    r13->setDefinition(m_definition);
+    multiComment->addRule(QSharedPointer<Rule>(r13));
+
+    Detect2CharsRule *r14 = new Detect2CharsRule;
+    r14->setChar("/");
+    r14->setChar1("#");
+    r14->setItemData("Other Comment");
+    r14->setContext("NestedComment");
+    r14->setDefinition(m_definition);
+    QSharedPointer<Rule> sr14(r14);
+    multiComment->addRule(sr14);
+
+    Detect2CharsRule *r15 = new Detect2CharsRule;
+    r15->setChar("#");
+    r15->setChar1("/");
+    r15->setItemData("Other Comment");
+    r15->setContext("#pop");
+    r15->setDefinition(m_definition);
+    nestedComment->addRule(QSharedPointer<Rule>(r15));
+
+    DetectCharRule *r16 = new DetectCharRule;
+    r16->setChar("@");
+    r16->setItemData("Marker");
+    r16->setContext("Dummy");
+    r16->setDefinition(m_definition);
+    multiComment->addRule(QSharedPointer<Rule>(r16));
+
+    StringDetectRule *r17 = new StringDetectRule;
+    r17->setString("dummy");
+    r17->setItemData("Dummy");
+    r17->setContext("#stay");
+    r17->setDefinition(m_definition);
+    dummy->addRule(QSharedPointer<Rule>(r17));
+
+    dummy->addRule(sr14);
+}
+
+void tst_HighlighterEngine::createItemDatas()
+{
+    QSharedPointer<ItemData> normalText = m_definition->createItemData("Normal Text");
+    normalText->setStyle("dsNormal");
+    QSharedPointer<ItemData> preprocessor = m_definition->createItemData("Preprocessor");
+    preprocessor->setStyle("dsOthers");
+    QSharedPointer<ItemData> error = m_definition->createItemData("Error");
+    error->setStyle("dsError");
+    QSharedPointer<ItemData> keyword = m_definition->createItemData("Keyword");
+    keyword->setStyle("dsKeyword");
+    QSharedPointer<ItemData> decimal = m_definition->createItemData("Decimal");
+    decimal->setStyle("dsDecVal");
+    QSharedPointer<ItemData> octal = m_definition->createItemData("Octal");
+    octal->setStyle("dsBaseN");
+    QSharedPointer<ItemData> comment = m_definition->createItemData("Comment");
+    comment->setStyle("dsComment");
+    QSharedPointer<ItemData> otherComment = m_definition->createItemData("Other Comment");
+    otherComment->setStyle("dsError");
+    QSharedPointer<ItemData> marker = m_definition->createItemData("Marker");
+    marker->setStyle("dsRegionMarker");
+    QSharedPointer<ItemData> dummy = m_definition->createItemData("Dummy");
+    dummy->setStyle("dsDataType");
+}
+
+void tst_HighlighterEngine::setExpectedData(int state, const HighlightSequence &seq)
+{
+    m_highlighterMock->setExpectedBlockState(state);
+    m_highlighterMock->setExpectedHighlightSequence(seq);
+}
+
+void tst_HighlighterEngine::setExpectedData(const QList<int> &states,
+                                            const QList<HighlightSequence> &seqs)
+{
+    m_highlighterMock->setExpectedBlockStates(states);
+    m_highlighterMock->setExpectedHighlightSequences(seqs);
+}
+
+void tst_HighlighterEngine::createColumns()
+{
+    QTest::addColumn<QList<int> >("states");
+    QTest::addColumn<QList<HighlightSequence> >("sequences");
+    QTest::addColumn<QString>("lines");
+}
+
+void tst_HighlighterEngine::test()
+{
+    QFETCH(QList<int>, states);
+    QFETCH(QList<HighlightSequence>, sequences);
+    QFETCH(QString, lines);
+
+    test(states, sequences, lines);
+}
+
+void tst_HighlighterEngine::test(int state, const HighlightSequence &seq, const QString &line)
+{
+    setExpectedData(state, seq);
+    m_text.setPlainText(line);
+}
+
+void tst_HighlighterEngine::test(const QList<int> &states,
+                                 const QList<HighlightSequence> &seqs,
+                                 const QString &lines)
+{
+    setExpectedData(states, seqs);
+    m_text.setPlainText(lines);
+}
+
+void tst_HighlighterEngine::clear(QList<int> *states, QList<HighlightSequence> *sequences) const
+{
+    states->clear();
+    sequences->clear();
+}
+
+QList<int> tst_HighlighterEngine::createlDefaultStatesList(int size) const
+{
+    QList<int> states;
+    for (int i = 0; i < size; ++i)
+        states.append(0);
+    return states;
+}
+
+void tst_HighlighterEngine::addCharactersToBegin(QTextBlock block, const QString &s)
+{
+    QTextCursor cursor = m_text.textCursor();
+    cursor.beginEditBlock();
+    cursor.setPosition(block.position());
+    cursor.insertText(s);
+    cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::addCharactersToEnd(QTextBlock block, const QString &s)
+{
+    QTextCursor cursor = m_text.textCursor();
+    cursor.beginEditBlock();
+    cursor.setPosition(block.position() + block.length() - 1);
+    cursor.insertText(s);
+    cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::removeFirstCharacters(const QTextBlock &block, int n)
+{
+    QTextCursor cursor = m_text.textCursor();
+    cursor.beginEditBlock();
+    cursor.setPosition(block.position());
+    cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, n);
+    cursor.removeSelectedText();
+    cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::removeLastCharacters(const QTextBlock &block, int n)
+{
+    QTextCursor cursor = m_text.textCursor();
+    cursor.beginEditBlock();
+    cursor.setPosition(block.position() + block.length() - 1);
+    cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, n);
+    cursor.removeSelectedText();
+    cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::testSimpleLine()
+{
+    test();
+}
+
+void tst_HighlighterEngine::testSimpleLine_data()
+{
+    createColumns();
+
+    QList<int> states;
+    QList<HighlightSequence> sequences;
+    QString text;
+
+    HighlightSequence seqa(0, 3);
+    HighlightSequence seqb(0, 15, Formats::instance().othersFormat());
+    HighlightSequence seqc(0, 1, Formats::instance().errorFormat());
+    HighlightSequence seqd(0, 3, Formats::instance().keywordFormat());
+    seqd.add(3, 8);
+    seqd.add(8, 9, Formats::instance().baseNFormat());
+    HighlightSequence seqe(0, 4, Formats::instance().keywordFormat());
+    seqe.add(4, 9);
+    seqe.add(9, 12, Formats::instance().decimalFormat());
+    HighlightSequence seqf(seqe);
+    seqf.add(12, 13);
+    HighlightSequence seqg(seqf);
+    seqg.add(13, 14);
+    HighlightSequence seqh(0, 8, Formats::instance().commentFormat());
+    HighlightSequence seqi(seqd);
+    seqi.add(9, 17, Formats::instance().commentFormat());
+    HighlightSequence seqj(seqd);
+    seqj.add(9, 11, Formats::instance().commentFormat());    
+    HighlightSequence seqk(0, 3);
+    HighlightSequence seql(0, 3, Formats::instance().keywordFormat());
+    HighlightSequence seqm(0, 2);
+    HighlightSequence seqn(0, 8, Formats::instance().commentFormat());
+
+    states << 0;
+    sequences << seqa;
+    text = "abc";
+    QTest::newRow("case 0") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqb;
+    text = "#define max 100";
+    QTest::newRow("case 1") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqc;
+    text = "#";
+    QTest::newRow("case 2") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqd;
+    text = "int i = 0";
+    QTest::newRow("case 3") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqe;
+    text = "long i = 1LL";
+    QTest::newRow("case 4") << states << sequences << text;
+
+    text = "long i = 1ul";
+    QTest::newRow("case 5") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqf;
+    text = "long i = 1ULL";
+    QTest::newRow("case 6") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqg;
+    text = "long i = 1LLUL";
+    QTest::newRow("case 7") << states << sequences << text;
+
+    text = "long i = 1ULLL";
+    QTest::newRow("case 8") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqh;
+    text = "//int i;";
+    QTest::newRow("case 9") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqi;
+    text = "int i = 0//int i;";
+    QTest::newRow("case 10") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqj;
+    text = "int i = 0//";
+    QTest::newRow("case 11") << states << sequences << text;
+
+    sequences.clear();
+    sequences << seqk << seqk;
+    text = "bla\nbla";
+    QTest::newRow("case 12") << createlDefaultStatesList(2) << sequences << text;
+
+    sequences.clear();
+    sequences << seql << seqm;
+    text = "int\ni;";
+    QTest::newRow("case 13") << createlDefaultStatesList(2) << sequences << text;
+
+    sequences.clear();
+    sequences << seqn << seqm;
+    text = "//int i;\ni;";
+    QTest::newRow("case 14") << createlDefaultStatesList(2) << sequences << text;
+}
+
+void tst_HighlighterEngine::testLineContinue()
+{
+    test();
+}
+
+void tst_HighlighterEngine::testLineContinue_data()
+{
+    createColumns();
+
+    QList<int> states;
+    QList<HighlightSequence> sequences;
+    QString lines;
+
+    HighlightSequence seqa(0, 12, Formats::instance().othersFormat());
+    HighlightSequence seqb(0, 7, Formats::instance().othersFormat());
+    HighlightSequence seqc(0, 8, Formats::instance().othersFormat());
+    HighlightSequence seqd(0, 3, Formats::instance().othersFormat());
+    HighlightSequence seqe(0, 3, Formats::instance().keywordFormat());
+    seqe.add(3, 8);
+    seqe.add(8, 9, Formats::instance().baseNFormat());
+    seqe.add(9, 10);
+
+    states << 1 << 2;
+    sequences << seqa << seqb;
+    lines = "#define max\\\n    100";
+    QTest::newRow("case 0") << states << sequences << lines;
+
+    clear(&states, &sequences);
+    states << 1 << 1;
+    sequences << seqa << seqc;
+    lines = "#define max\\\n    100\\";
+    QTest::newRow("case 1") << states << sequences << lines;
+
+    clear(&states, &sequences);
+    states << 1 << 1 << 2;
+    sequences << seqa << seqc << seqd;
+    lines = "#define max\\\n    100\\\n000";
+    QTest::newRow("case 2") << states << sequences << lines;
+
+    clear(&states, &sequences);
+    states << 1 << 1 << 2 << 0;
+    sequences << seqa << seqc << seqd << seqe;
+    lines = "#define max\\\n    100\\\n000\nint i = 0;";
+    QTest::newRow("case 3") << states << sequences << lines;
+}
+
+void tst_HighlighterEngine::testPersistentStates()
+{
+    test();
+}
+
+void tst_HighlighterEngine::testPersistentStates_data()
+{
+    createColumns();
+
+    QList<int> states;
+    QList<HighlightSequence> sequences;
+    QString text;
+
+    HighlightSequence seqa(0, 3, Formats::instance().keywordFormat());
+    seqa.add(3, 6);
+    seqa.add(6, 15, Formats::instance().commentFormat());
+    seqa.add(15, 16);
+    HighlightSequence seqb(0, 8, Formats::instance().commentFormat());
+    HighlightSequence seqc(0, 2, Formats::instance().commentFormat());
+    HighlightSequence seqd(0, 9, Formats::instance().commentFormat());
+    seqd.add(9, 18, Formats::instance().errorFormat());
+    HighlightSequence seqe(0, 5, Formats::instance().errorFormat());
+    seqe.add(5, 8, Formats::instance().commentFormat());
+    HighlightSequence seqf(0, 2, Formats::instance().commentFormat());
+    seqf.add(2, 6);
+    HighlightSequence seqg(0, 1);
+    seqg.add(1, 7, Formats::instance().commentFormat());
+    seqg.add(7, 8, Formats::instance().regionMarketFormat());
+    seqg.add(8, 15, Formats::instance().errorFormat());
+    seqg.add(15, 16, Formats::instance().regionMarketFormat());
+    seqg.add(16, 21, Formats::instance().dataTypeFormat());
+    seqg.add(21, 22, Formats::instance().regionMarketFormat());
+    HighlightSequence seqh(0, 2);
+
+    states << 0;
+    sequences << seqa;
+    text = "int i /* = 0 */;";
+    QTest::newRow("case 0") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3 << 3;
+    sequences << seqb << seqc;
+    text = "/*int i;\ni;";
+    QTest::newRow("case 1") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3 << 3 << 3;
+    sequences << seqb << seqc << seqb;
+    text = "/*int i;\ni;\nint abc;";
+    QTest::newRow("case 2") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3 << 3 << 0;
+    sequences << seqb << seqc << seqc;
+    text = "/*int i;\ni;\n*/";
+    QTest::newRow("case 3") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 4 << 3 << 0;
+    sequences << seqd << seqe << seqf;
+    text = "/*int i; /# int j;\nfoo#/bar\n*/f();";
+    QTest::newRow("case 4") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3;
+    sequences << seqg;
+    text = "i/*bla @/#foo#/ dummy ";
+    QTest::newRow("case 5") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3 << 3;
+    sequences << seqg << seqc;
+    text = "i/*bla @/#foo#/ dummy \ni;";
+    QTest::newRow("case 6") << states << sequences << text;
+
+    clear(&states, &sequences);
+    states << 3 << 3 << 0;
+    sequences << seqg << seqc << seqh;
+    text = "i/*bla @/#foo#/ dummy \ni;\n*/";
+    QTest::newRow("case 7") << states << sequences << text;
+}
+
+void tst_HighlighterEngine::setupForEditingLineContinue()
+{
+    m_highlighterMock->startNoTestCalls();
+    m_text.setPlainText("#define max\\\n    xxx\\\nzzz");
+    m_highlighterMock->endNoTestCalls();
+}
+
+void tst_HighlighterEngine::testEditingLineContinue0()
+{
+    setupForEditingLineContinue();
+
+    QList<HighlightSequence> sequences;
+    HighlightSequence seqa(0, 11, Formats::instance().othersFormat());
+    HighlightSequence seqb(0, 8);
+    HighlightSequence seqc(0, 3);
+    sequences << seqa << seqb << seqc;
+    setExpectedData(createlDefaultStatesList(3), sequences);
+
+    removeLastCharacters(m_text.document()->firstBlock(), 1);
+}
+
+void tst_HighlighterEngine::testEditingLineContinue1()
+{
+    setupForEditingLineContinue();
+
+    setExpectedData(1, HighlightSequence(0, 6, Formats::instance().othersFormat()));
+
+    // In this case highlighting should be triggered only for the modified line.
+    removeFirstCharacters(m_text.document()->firstBlock().next(), 2);
+}
+
+void tst_HighlighterEngine::testEditingLineContinue2()
+{
+    setupForEditingLineContinue();
+
+    QList<HighlightSequence> sequences;
+    HighlightSequence seqa(0, 17, Formats::instance().othersFormat());
+    HighlightSequence seqb(0, 8);
+    HighlightSequence seqc(0, 3);
+    sequences << seqa << seqb << seqc;
+    setExpectedData(createlDefaultStatesList(3), sequences);
+
+    addCharactersToEnd(m_text.document()->firstBlock(), "ixum");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue3()
+{
+    setupForEditingLineContinue();
+
+    setExpectedData(1, HighlightSequence(0, 12, Formats::instance().othersFormat()));
+
+    // In this case highlighting should be triggered only for the modified line.
+    addCharactersToBegin(m_text.document()->firstBlock().next(), "ixum");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue4()
+{
+    setupForEditingLineContinue();
+
+    QList<int> states;
+    states << 2 << 0 << 0;
+    QList<HighlightSequence> sequences;
+    HighlightSequence seqa(0, 0);
+    HighlightSequence seqb(0, 8);
+    HighlightSequence seqc(0, 3);
+    sequences << seqa << seqb << seqc;
+    setExpectedData(states, sequences);
+
+    m_highlighterMock->considerEmptyLines();
+    addCharactersToBegin(m_text.document()->firstBlock().next(), "\n");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue5()
+{
+    setupForEditingLineContinue();
+
+    QList<int> states;
+    states << 2 << 0;
+    QList<HighlightSequence> sequences;
+    HighlightSequence seqa(0, 9, Formats::instance().othersFormat());
+    HighlightSequence seqb(0, 3);
+    sequences << seqa << seqb;
+    setExpectedData(states, sequences);
+
+    addCharactersToEnd(m_text.document()->firstBlock().next(), "x");
+}
+
+QTEST_MAIN(tst_HighlighterEngine)
+#include "tst_highlighterengine.moc"
+
-- 
GitLab