From dd89d731cfaad7cfd6c1c6aa54ceefe4ca5b82d1 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 8 Jul 2015 14:07:13 +0200 Subject: [PATCH] Clang: Extract and test action sequence Change-Id: I66f8f29d7b17be67a55560bdcc0b0a3aeb1ce480 Reviewed-by: Nikolai Kosjar --- .../activationsequenceprocessor.cpp | 208 ++++++++++++++++++ .../activationsequenceprocessor.h | 81 +++++++ src/plugins/clangcodemodel/clangcodemodel.pro | 2 + src/plugins/clangcodemodel/clangcodemodel.qbs | 2 + .../clangcodemodelunittestfiles.pri | 6 +- .../clangcompletionassistprocessor.cpp | 110 ++------- .../activationsequenceprocessortest.cpp | 203 +++++++++++++++++ tests/unit/unittest/cplusplus.pri | 5 + tests/unit/unittest/unittest.pro | 8 +- 9 files changed, 528 insertions(+), 97 deletions(-) create mode 100644 src/plugins/clangcodemodel/activationsequenceprocessor.cpp create mode 100644 src/plugins/clangcodemodel/activationsequenceprocessor.h create mode 100644 tests/unit/unittest/activationsequenceprocessortest.cpp create mode 100644 tests/unit/unittest/cplusplus.pri diff --git a/src/plugins/clangcodemodel/activationsequenceprocessor.cpp b/src/plugins/clangcodemodel/activationsequenceprocessor.cpp new file mode 100644 index 00000000000..fac5a58c28b --- /dev/null +++ b/src/plugins/clangcodemodel/activationsequenceprocessor.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "activationsequenceprocessor.h" + +namespace ClangCodeModel { +namespace Internal { + +namespace { + +QString truncateActivationStringByPosition(const QString &activationString, + int positionInDocument) +{ + if (positionInDocument == 1) + return activationString.left(1); + + if (positionInDocument == 2) + return activationString.left(2); + + return activationString; +} + +} + +ActivationSequenceProcessor::ActivationSequenceProcessor(const QString &activationString, + int positionInDocument, + bool wantFunctionCall) + : m_positionInDocument(positionInDocument), + m_wantFunctionCall(wantFunctionCall) +{ + extractCharactersBeforePosition(truncateActivationStringByPosition(activationString, + positionInDocument)); + + process(); +} + +CPlusPlus::Kind ActivationSequenceProcessor::completionKind() const +{ + return m_completionKind; +} + +int ActivationSequenceProcessor::offset() const +{ + return m_offset; +} + +int ActivationSequenceProcessor::position() const +{ + return m_positionInDocument - m_offset; +} + +void ActivationSequenceProcessor::extractCharactersBeforePosition(const QString &activationString) +{ + if (activationString.size() >= 3) { + m_char1 = activationString[0]; + m_char2 = activationString[1]; + m_char3 = activationString[2]; + } else if (activationString.size() == 2) { + m_char2 = activationString[0]; + m_char3 = activationString[1]; + } else if (activationString.size() == 1) { + m_char3 = activationString[0]; + } +} + +void ActivationSequenceProcessor::process() +{ + processDot(); + processComma(); + processLeftParen(); + processColonColon(); + processArrow(); + processDotStar(); + processArrowStar(); + processDoxyGenComment(); + processAngleStringLiteral(); + processStringLiteral(); + processSlash(); + processPound(); +} + +void ActivationSequenceProcessor::processDot() +{ + if (m_char3 == QLatin1Char('.') && m_char2 != QLatin1Char('.')) { + m_completionKind = CPlusPlus::T_DOT; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processComma() +{ + if (m_char3 == QLatin1Char(',') ) { + m_completionKind = CPlusPlus::T_COMMA; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processLeftParen() +{ + if (m_char3 == QLatin1Char('(') && m_wantFunctionCall) { + m_completionKind = CPlusPlus::T_LPAREN; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processColonColon() +{ + if (m_char2 == QLatin1Char(':') && m_char3 == QLatin1Char(':')) { + m_completionKind = CPlusPlus::T_COLON_COLON; + m_offset = 2; + } +} + +void ActivationSequenceProcessor::processArrow() +{ + if (m_char2 == QLatin1Char('-') && m_char3 == QLatin1Char('>')) { + m_completionKind = CPlusPlus::T_ARROW; + m_offset = 2; + } +} + +void ActivationSequenceProcessor::processDotStar() +{ + if (m_char2 == QLatin1Char('.') && m_char3 == QLatin1Char('*')) { + m_completionKind = CPlusPlus::T_DOT_STAR; + m_offset = 2; + } +} + +void ActivationSequenceProcessor::processArrowStar() +{ + if (m_char1 == QLatin1Char('-') && m_char2 == QLatin1Char('>') && m_char3 == QLatin1Char('*')) { + m_completionKind = CPlusPlus::T_ARROW_STAR; + m_offset = 3; + } +} + +void ActivationSequenceProcessor::processDoxyGenComment() +{ + if ((m_char2 == QLatin1Char('\\') || m_char2 == QLatin1Char('@')) + && (m_char3.isNull() || m_char3.isSpace())) { + m_completionKind = CPlusPlus::T_DOXY_COMMENT; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processAngleStringLiteral() +{ + if (m_char3 == QLatin1Char('<')) { + m_completionKind = CPlusPlus::T_ANGLE_STRING_LITERAL; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processStringLiteral() +{ + if (m_char3 == QLatin1Char('"')) { + m_completionKind = CPlusPlus::T_STRING_LITERAL; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processSlash() +{ + if (m_char3 == QLatin1Char('/')) { + m_completionKind = CPlusPlus::T_SLASH; + m_offset = 1; + } +} + +void ActivationSequenceProcessor::processPound() +{ + if (m_char3 == QLatin1Char('#')) { + m_completionKind = CPlusPlus::T_POUND; + m_offset = 1; + } +} + +} // namespace Internal +} // namespace ClangCodeModel + diff --git a/src/plugins/clangcodemodel/activationsequenceprocessor.h b/src/plugins/clangcodemodel/activationsequenceprocessor.h new file mode 100644 index 00000000000..eacc81af203 --- /dev/null +++ b/src/plugins/clangcodemodel/activationsequenceprocessor.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H +#define CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H + +#include + +#include + +namespace ClangCodeModel { +namespace Internal { + +class ActivationSequenceProcessor +{ +public: + ActivationSequenceProcessor(const QString &activationString, + int positionInDocument, + bool wantFunctionCall); + + CPlusPlus::Kind completionKind() const; + int offset() const; + int position() const; + +private: + void extractCharactersBeforePosition(const QString &activationString); + void process(); + void processDot(); + void processComma(); + void processLeftParen(); + void processColonColon(); + void processArrow(); + void processDotStar(); + void processArrowStar(); + void processDoxyGenComment(); + void processAngleStringLiteral(); + void processStringLiteral(); + void processSlash(); + void processPound(); + +private: + CPlusPlus::Kind m_completionKind = CPlusPlus::T_EOF_SYMBOL; + int m_offset = 0; + int m_positionInDocument; + QChar m_char1; + QChar m_char2; + QChar m_char3; + bool m_wantFunctionCall; +}; + +} // namespace Internal +} // namespace ClangCodeModel + +#endif // CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index 93ab1028e26..9ad3b7a989a 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -12,6 +12,7 @@ DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/incl unix:QMAKE_LFLAGS += -Wl,-rpath,\'$$LLVM_LIBDIR\' SOURCES += \ + activationsequenceprocessor.cpp \ clangassistproposal.cpp \ clangassistproposalitem.cpp \ clangassistproposalmodel.cpp \ @@ -47,6 +48,7 @@ SOURCES += \ HEADERS += \ + activationsequenceprocessor.h \ clangassistproposal.h \ clangassistproposalitem.h \ clangassistproposalmodel.h \ diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index f254cd21570..e0ba967fb76 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -53,6 +53,8 @@ QtcPlugin { name: "Completion support" condition: product.clangCompletion files: [ + "activationsequenceprocessor.cpp", + "activationsequenceprocessor.h", "clangassistproposal.cpp", "clangassistproposal.h", "clangassistproposalitem.cpp", diff --git a/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri b/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri index 6094bff9974..e40a4c8fa4b 100644 --- a/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri +++ b/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri @@ -1,5 +1,7 @@ INCLUDEPATH += $$PWD -SOURCES += $$PWD/completionchunkstotextconverter.cpp +SOURCES += $$PWD/completionchunkstotextconverter.cpp \ + $$PWD/activationsequenceprocessor.cpp -HEADERS += $$PWD/completionchunkstotextconverter.h +HEADERS += $$PWD/completionchunkstotextconverter.h \ + $$PWD/activationsequenceprocessor.h diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 779c8589752..1062a3726b8 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -30,6 +30,7 @@ #include "clangassistproposalitem.h" +#include "activationsequenceprocessor.h" #include "clangassistproposal.h" #include "clangassistproposalmodel.h" #include "clangcompletionassistprocessor.h" @@ -65,84 +66,6 @@ namespace { const char SNIPPET_ICON_PATH[] = ":/texteditor/images/snippet.png"; -int activationSequenceChar(const QChar &ch, - const QChar &ch2, - const QChar &ch3, - unsigned *kind, - bool wantFunctionCall) -{ - using namespace CPlusPlus; - - int referencePosition = 0; - int completionKind = T_EOF_SYMBOL; - switch (ch.toLatin1()) { - case '.': - if (ch2 != QLatin1Char('.')) { - completionKind = T_DOT; - referencePosition = 1; - } - break; - case ',': - completionKind = T_COMMA; - referencePosition = 1; - break; - case '(': - if (wantFunctionCall) { - completionKind = T_LPAREN; - referencePosition = 1; - } - break; - case ':': - if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) { - completionKind = T_COLON_COLON; - referencePosition = 2; - } - break; - case '>': - if (ch2 == QLatin1Char('-')) { - completionKind = T_ARROW; - referencePosition = 2; - } - break; - case '*': - if (ch2 == QLatin1Char('.')) { - completionKind = T_DOT_STAR; - referencePosition = 2; - } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) { - completionKind = T_ARROW_STAR; - referencePosition = 3; - } - break; - case '\\': - case '@': - if (ch2.isNull() || ch2.isSpace()) { - completionKind = T_DOXY_COMMENT; - referencePosition = 1; - } - break; - case '<': - completionKind = T_ANGLE_STRING_LITERAL; - referencePosition = 1; - break; - case '"': - completionKind = T_STRING_LITERAL; - referencePosition = 1; - break; - case '/': - completionKind = T_SLASH; - referencePosition = 1; - break; - case '#': - completionKind = T_POUND; - referencePosition = 1; - break; - } - - if (kind) - *kind = completionKind; - - return referencePosition; -} QList toAssistProposalItems(const CodeCompletions &completions) { @@ -423,18 +346,21 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() } // TODO: Extract duplicated logic from InternalCppCompletionAssistProcessor::startOfOperator -int ClangCompletionAssistProcessor::startOfOperator(int pos, +int ClangCompletionAssistProcessor::startOfOperator(int positionInDocument, unsigned *kind, bool wantFunctionCall) const { - const QChar ch = pos > -1 ? m_interface->characterAt(pos - 1) : QChar(); - const QChar ch2 = pos > 0 ? m_interface->characterAt(pos - 2) : QChar(); - const QChar ch3 = pos > 1 ? m_interface->characterAt(pos - 3) : QChar(); + auto activationSequence = m_interface->textAt(positionInDocument - 3, 3); + ActivationSequenceProcessor activationSequenceProcessor(activationSequence, + positionInDocument, + wantFunctionCall); - int start = pos - activationSequenceChar(ch, ch2, ch3, kind, wantFunctionCall); - if (start != pos) { + *kind = activationSequenceProcessor.completionKind(); + + int start = activationSequenceProcessor.position(); + if (start != positionInDocument) { QTextCursor tc(m_interface->textDocument()); - tc.setPosition(pos); + tc.setPosition(positionInDocument); // Include completion: make sure the quote character is the first one on the line if (*kind == T_STRING_LITERAL) { @@ -443,7 +369,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, QString sel = s.selectedText(); if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } } @@ -451,7 +377,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, ExpressionUnderCursor expressionUnderCursor(m_interface->languageFeatures()); if (expressionUnderCursor.startOfFunctionCall(tc) == -1) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } } @@ -464,7 +390,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } // Don't complete in comments or strings, but still check for include completion else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) @@ -473,12 +399,12 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, && *kind != T_ANGLE_STRING_LITERAL && *kind != T_SLASH))) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } // Include completion: can be triggered by slash, but only in a string else if (*kind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } else if (*kind == T_LPAREN) { if (tokenIdx > 0) { @@ -493,7 +419,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, default: // that's a bad token :) *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } } } @@ -516,7 +442,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos, if (!include) { *kind = T_EOF_SYMBOL; - start = pos; + start = positionInDocument; } } } diff --git a/tests/unit/unittest/activationsequenceprocessortest.cpp b/tests/unit/unittest/activationsequenceprocessortest.cpp new file mode 100644 index 00000000000..b12f6487037 --- /dev/null +++ b/tests/unit/unittest/activationsequenceprocessortest.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +namespace { + +using testing::PrintToString; +using namespace CPlusPlus; +using ClangCodeModel::Internal::ActivationSequenceProcessor; + +MATCHER_P3(HasResult, completionKind, offset, newPosition, + std::string(negation ? "hasn't" : "has") + + " result of completion kind " + PrintToString(Token::name(completionKind)) + + ", offset " + PrintToString(offset) + + " and new position in document" + PrintToString(newPosition)) +{ + if (arg.completionKind() != completionKind + || arg.offset() != offset + || arg.position() != newPosition) { + *result_listener << "completion kind is " << PrintToString(Token::name(arg.completionKind())) + << ", offset is " << PrintToString(arg.offset()) + << " and new position in document is " << PrintToString(arg.position()); + return false; + } + + return true; +} + +TEST(ActivationSequenceProcessor, CouldNotProcesseRandomCharacters) +{ + ActivationSequenceProcessor processor(QStringLiteral("xxx"), 3, false); + + ASSERT_THAT(processor, HasResult(T_EOF_SYMBOL, 0, 3)); +} + +TEST(ActivationSequenceProcessor, CouldNotProcesseEmptyString) +{ + ActivationSequenceProcessor processor(QStringLiteral(""), 0, true); + + ASSERT_THAT(processor, HasResult(T_EOF_SYMBOL, 0, 0)); +} + +TEST(ActivationSequenceProcessor, Dot) +{ + ActivationSequenceProcessor processor(QStringLiteral("."), 1, true); + + ASSERT_THAT(processor, HasResult(T_DOT, 1, 0)); +} + +TEST(ActivationSequenceProcessor, Comma) +{ + ActivationSequenceProcessor processor(QStringLiteral(","), 2, false); + + ASSERT_THAT(processor, HasResult(T_COMMA, 1, 1)); +} + +TEST(ActivationSequenceProcessor, LeftParenAsFunctionCall) +{ + ActivationSequenceProcessor processor(QStringLiteral("("), 3, true); + + ASSERT_THAT(processor, HasResult(T_LPAREN, 1, 2)); +} + +TEST(ActivationSequenceProcessor, LeftParenNotAsFunctionCall) +{ + ActivationSequenceProcessor processor(QStringLiteral("("), 3, false); + + ASSERT_THAT(processor, HasResult(T_EOF_SYMBOL, 0, 3)); +} + +TEST(ActivationSequenceProcessor, ColonColon) +{ + ActivationSequenceProcessor processor(QStringLiteral("::"), 20, true); + + ASSERT_THAT(processor, HasResult(T_COLON_COLON, 2, 18)); +} + +TEST(ActivationSequenceProcessor, Arrow) +{ + ActivationSequenceProcessor processor(QStringLiteral("->"), 2, true); + + ASSERT_THAT(processor, HasResult(T_ARROW, 2, 0)); +} + +TEST(ActivationSequenceProcessor, DotStar) +{ + ActivationSequenceProcessor processor(QStringLiteral(".*"), 3, true); + + ASSERT_THAT(processor, HasResult(T_DOT_STAR, 2, 1)); +} + +TEST(ActivationSequenceProcessor, ArrowStar) +{ + ActivationSequenceProcessor processor(QStringLiteral("->*"), 3, true); + + ASSERT_THAT(processor, HasResult(T_ARROW_STAR, 3, 0)); +} + +TEST(ActivationSequenceProcessor, DoxyGenCommentBackSlash) +{ + ActivationSequenceProcessor processor(QStringLiteral("\\ "), 3, true); + + ASSERT_THAT(processor, HasResult(T_DOXY_COMMENT, 1, 2)); +} + +TEST(ActivationSequenceProcessor, DoxyGenCommentAt) +{ + ActivationSequenceProcessor processor(QStringLiteral("@ "), 2, true); + + ASSERT_THAT(processor, HasResult(T_DOXY_COMMENT, 1, 1)); +} + +TEST(ActivationSequenceProcessor, AngleStringLiteral) +{ + ActivationSequenceProcessor processor(QStringLiteral("<"), 1, true); + + ASSERT_THAT(processor, HasResult(T_ANGLE_STRING_LITERAL, 1, 0)); +} + +TEST(ActivationSequenceProcessor, StringLiteral) +{ + ActivationSequenceProcessor processor(QStringLiteral("\""), 1, true); + + ASSERT_THAT(processor, HasResult(T_STRING_LITERAL, 1, 0)); +} + +TEST(ActivationSequenceProcessor, Slash) +{ + ActivationSequenceProcessor processor(QStringLiteral("/"), 1, true); + + ASSERT_THAT(processor, HasResult(T_SLASH, 1, 0)); +} + +TEST(ActivationSequenceProcessor, Pound) +{ + ActivationSequenceProcessor processor(QStringLiteral("#"), 1, true); + + ASSERT_THAT(processor, HasResult(T_POUND, 1, 0)); +} + +TEST(ActivationSequenceProcessor, PositionIsOne) +{ + ActivationSequenceProcessor processor(QStringLiteral("