File indexing completed on 2024-04-28 07:46:03

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams\gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "completion_test.h"
0009 #include "codecompletiontestmodels.h"
0010 // #include "codecompletiontestmodels.moc"
0011 
0012 #include <ktexteditor/document.h>
0013 #include <ktexteditor/editor.h>
0014 
0015 #include <katecompletionmodel.h>
0016 #include <katecompletiontree.h>
0017 #include <katecompletionwidget.h>
0018 #include <kateconfig.h>
0019 #include <kateglobal.h>
0020 #include <katerenderer.h>
0021 #include <kateview.h>
0022 
0023 #include <QApplication>
0024 #include <QKeyEvent>
0025 #include <QTest>
0026 
0027 QTEST_MAIN(CompletionTest)
0028 
0029 using namespace KTextEditor;
0030 static constexpr int TIMEOUT = 2000;
0031 
0032 int countItems(KateCompletionModel *model)
0033 {
0034     const int topLevel = model->rowCount(QModelIndex());
0035     if (!model->hasGroups()) {
0036         return topLevel;
0037     }
0038     int ret = 0;
0039     for (int i = 0; i < topLevel; ++i) {
0040         ret += model->rowCount(model->index(i, 0));
0041     }
0042     return ret;
0043 }
0044 
0045 static void verifyCompletionStarted(KTextEditor::ViewPrivate *view)
0046 {
0047     QTRY_VERIFY_WITH_TIMEOUT(view->completionWidget()->isCompletionActive(), TIMEOUT);
0048 }
0049 
0050 static void verifyCompletionAborted(KTextEditor::ViewPrivate *view)
0051 {
0052     QTRY_VERIFY_WITH_TIMEOUT(!view->completionWidget()->isCompletionActive(), TIMEOUT);
0053 }
0054 
0055 static void invokeCompletionBox(KTextEditor::ViewPrivate *view)
0056 {
0057     view->userInvokedCompletion();
0058     verifyCompletionStarted(view);
0059 }
0060 
0061 void CompletionTest::init()
0062 {
0063     KTextEditor::EditorPrivate::enableUnitTestMode();
0064     Editor *editor = KTextEditor::Editor::instance();
0065     QVERIFY(editor);
0066 
0067     m_doc = editor->createDocument(this);
0068     QVERIFY(m_doc);
0069     m_doc->setText(QStringLiteral("aa bb cc\ndd"));
0070 
0071     KTextEditor::View *v = m_doc->createView(nullptr);
0072     QApplication::setActiveWindow(v);
0073     m_view = static_cast<KTextEditor::ViewPrivate *>(v);
0074     Q_ASSERT(m_view);
0075 
0076     // view needs to be shown as completion won't work if the cursor is off screen
0077     m_view->show();
0078 }
0079 
0080 void CompletionTest::cleanup()
0081 {
0082     delete m_view;
0083     delete m_doc;
0084 }
0085 
0086 void CompletionTest::testFilterEmptyRange()
0087 {
0088     KateCompletionModel *model = m_view->completionWidget()->model();
0089 
0090     new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0091     m_view->setCursorPosition(Cursor(0, 0));
0092     invokeCompletionBox(m_view);
0093 
0094     QCOMPARE(countItems(model), 40);
0095     m_view->insertText(QStringLiteral("aa"));
0096     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 14, TIMEOUT);
0097 }
0098 
0099 void CompletionTest::testFilterWithRange()
0100 {
0101     KateCompletionModel *model = m_view->completionWidget()->model();
0102 
0103     CodeCompletionTestModel *testModel = new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0104     m_view->setCursorPosition(Cursor(0, 2));
0105     invokeCompletionBox(m_view);
0106 
0107     Range complRange = *m_view->completionWidget()->completionRange(testModel);
0108     QCOMPARE(complRange, Range(Cursor(0, 0), Cursor(0, 2)));
0109     QCOMPARE(countItems(model), 14);
0110 
0111     m_view->insertText(QStringLiteral("a"));
0112     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 1, TIMEOUT);
0113 }
0114 
0115 void CompletionTest::testAbortCursorMovedOutOfRange()
0116 {
0117     KateCompletionModel *model = m_view->completionWidget()->model();
0118 
0119     new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0120     m_view->setCursorPosition(Cursor(0, 2));
0121     invokeCompletionBox(m_view);
0122 
0123     QCOMPARE(countItems(model), 14);
0124     QVERIFY(m_view->completionWidget()->isCompletionActive());
0125 
0126     m_view->setCursorPosition(Cursor(0, 4));
0127     verifyCompletionAborted(m_view);
0128 }
0129 
0130 void CompletionTest::testAbortInvalidText()
0131 {
0132     KateCompletionModel *model = m_view->completionWidget()->model();
0133 
0134     new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0135     m_view->setCursorPosition(Cursor(0, 2));
0136     invokeCompletionBox(m_view);
0137 
0138     QCOMPARE(countItems(model), 14);
0139     QVERIFY(m_view->completionWidget()->isCompletionActive());
0140 
0141     m_view->insertText(QStringLiteral("."));
0142     verifyCompletionAborted(m_view);
0143 }
0144 
0145 void CompletionTest::testCustomRange1()
0146 {
0147     m_doc->setText(QStringLiteral("$aa bb cc\ndd"));
0148     KateCompletionModel *model = m_view->completionWidget()->model();
0149 
0150     CodeCompletionTestModel *testModel = new CustomRangeModel(m_view, QStringLiteral("$a"));
0151     m_view->setCursorPosition(Cursor(0, 3));
0152     invokeCompletionBox(m_view);
0153 
0154     Range complRange = *m_view->completionWidget()->completionRange(testModel);
0155     qDebug() << complRange;
0156     QCOMPARE(complRange, Range(Cursor(0, 0), Cursor(0, 3)));
0157     QCOMPARE(countItems(model), 14);
0158 
0159     m_view->insertText(QStringLiteral("a"));
0160     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 1, TIMEOUT);
0161 }
0162 
0163 void CompletionTest::testCustomRange2()
0164 {
0165     m_doc->setText(QStringLiteral("$ bb cc\ndd"));
0166     KateCompletionModel *model = m_view->completionWidget()->model();
0167 
0168     CodeCompletionTestModel *testModel = new CustomRangeModel(m_view, QStringLiteral("$a"));
0169     m_view->setCursorPosition(Cursor(0, 1));
0170     invokeCompletionBox(m_view);
0171 
0172     Range complRange = *m_view->completionWidget()->completionRange(testModel);
0173     QCOMPARE(complRange, Range(Cursor(0, 0), Cursor(0, 1)));
0174     QCOMPARE(countItems(model), 40);
0175 
0176     m_view->insertText(QStringLiteral("aa"));
0177     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 14, TIMEOUT);
0178 }
0179 
0180 void CompletionTest::testCustomRangeMultipleModels()
0181 {
0182     m_doc->setText(QStringLiteral("$a bb cc\ndd"));
0183     KateCompletionModel *model = m_view->completionWidget()->model();
0184 
0185     CodeCompletionTestModel *testModel1 = new CustomRangeModel(m_view, QStringLiteral("$a"));
0186     CodeCompletionTestModel *testModel2 = new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0187     m_view->setCursorPosition(Cursor(0, 1));
0188     invokeCompletionBox(m_view);
0189 
0190     QCOMPARE(Range(*m_view->completionWidget()->completionRange(testModel1)), Range(Cursor(0, 0), Cursor(0, 2)));
0191     QCOMPARE(Range(*m_view->completionWidget()->completionRange(testModel2)), Range(Cursor(0, 1), Cursor(0, 2)));
0192     QCOMPARE(model->currentCompletion(testModel1), QStringLiteral("$"));
0193     QCOMPARE(model->currentCompletion(testModel2), QString());
0194     QCOMPARE(countItems(model), 80);
0195 
0196     m_view->insertText(QStringLiteral("aa"));
0197     QTRY_COMPARE_WITH_TIMEOUT(model->currentCompletion(testModel1), QStringLiteral("$aa"), TIMEOUT);
0198     QCOMPARE(model->currentCompletion(testModel2), QStringLiteral("aa"));
0199     QCOMPARE(countItems(model), 14 * 2);
0200 }
0201 
0202 void CompletionTest::testAbortController()
0203 {
0204     KateCompletionModel *model = m_view->completionWidget()->model();
0205 
0206     new CustomRangeModel(m_view, QStringLiteral("$a"));
0207     m_view->setCursorPosition(Cursor(0, 0));
0208     invokeCompletionBox(m_view);
0209 
0210     QCOMPARE(countItems(model), 40);
0211     QVERIFY(m_view->completionWidget()->isCompletionActive());
0212 
0213     m_view->insertText(QStringLiteral("$a"));
0214     verifyCompletionStarted(m_view);
0215 
0216     m_view->insertText(QStringLiteral("."));
0217     verifyCompletionAborted(m_view);
0218 }
0219 
0220 void CompletionTest::testAbortControllerMultipleModels()
0221 {
0222     KateCompletionModel *model = m_view->completionWidget()->model();
0223 
0224     CodeCompletionTestModel *testModel1 = new CodeCompletionTestModel(m_view, QStringLiteral("aa"));
0225     CodeCompletionTestModel *testModel2 = new CustomAbortModel(m_view, QStringLiteral("a-"));
0226     m_view->setCursorPosition(Cursor(0, 0));
0227     invokeCompletionBox(m_view);
0228 
0229     QCOMPARE(countItems(model), 80);
0230     QVERIFY(m_view->completionWidget()->isCompletionActive());
0231 
0232     m_view->insertText(QStringLiteral("a"));
0233     verifyCompletionStarted(m_view);
0234     QCOMPARE(countItems(model), 80);
0235 
0236     m_view->insertText(QStringLiteral("-"));
0237     verifyCompletionStarted(m_view);
0238     QVERIFY(!m_view->completionWidget()->completionRanges().contains(testModel1));
0239     QVERIFY(m_view->completionWidget()->completionRanges().contains(testModel2));
0240 
0241     QCOMPARE(countItems(model), 40);
0242 
0243     m_view->insertText(QLatin1String(" "));
0244     verifyCompletionAborted(m_view);
0245 }
0246 
0247 void CompletionTest::testEmptyFilterString()
0248 {
0249     KateCompletionModel *model = m_view->completionWidget()->model();
0250 
0251     new EmptyFilterStringModel(m_view, QStringLiteral("aa"));
0252     m_view->setCursorPosition(Cursor(0, 0));
0253     invokeCompletionBox(m_view);
0254 
0255     QCOMPARE(countItems(model), 40);
0256 
0257     m_view->insertText(QStringLiteral("a"));
0258     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 40, TIMEOUT);
0259 
0260     m_view->insertText(QStringLiteral("bam"));
0261     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 40, TIMEOUT);
0262 }
0263 
0264 void CompletionTest::testUpdateCompletionRange()
0265 {
0266     m_doc->setText(QStringLiteral("ab    bb cc\ndd"));
0267     KateCompletionModel *model = m_view->completionWidget()->model();
0268 
0269     CodeCompletionTestModel *testModel = new UpdateCompletionRangeModel(m_view, QStringLiteral("ab ab"));
0270     m_view->setCursorPosition(Cursor(0, 3));
0271     invokeCompletionBox(m_view);
0272 
0273     QCOMPARE(countItems(model), 40);
0274     QCOMPARE(Range(*m_view->completionWidget()->completionRange(testModel)), Range(Cursor(0, 3), Cursor(0, 3)));
0275 
0276     m_view->insertText(QStringLiteral("ab"));
0277     QTRY_COMPARE_WITH_TIMEOUT(Range(*m_view->completionWidget()->completionRange(testModel)), Range(Cursor(0, 0), Cursor(0, 5)), TIMEOUT);
0278     QTRY_COMPARE_WITH_TIMEOUT(countItems(model), 40, TIMEOUT);
0279 }
0280 
0281 void CompletionTest::testCustomStartCompl()
0282 {
0283 #ifdef __SANITIZE_ADDRESS__
0284     QSKIP("issues with Qt 6.5 and sanitizer");
0285 #endif
0286 
0287     KateCompletionModel *model = m_view->completionWidget()->model();
0288 
0289     m_view->completionWidget()->setAutomaticInvocationDelay(1);
0290 
0291     new StartCompletionModel(m_view, QStringLiteral("aa"));
0292 
0293     m_view->setCursorPosition(Cursor(0, 0));
0294     m_view->insertText(QStringLiteral("%"));
0295 
0296     verifyCompletionStarted(m_view);
0297     QCOMPARE(countItems(model), 40);
0298 }
0299 
0300 void CompletionTest::testKateCompletionModel()
0301 {
0302     KateCompletionModel *model = m_view->completionWidget()->model();
0303     CodeCompletionTestModel *testModel1 = new CodeCompletionTestModel(m_view, QStringLiteral("aa"));
0304     CodeCompletionTestModel *testModel2 = new CodeCompletionTestModel(m_view, QStringLiteral("bb"));
0305 
0306     model->setCompletionModel(testModel1);
0307     QCOMPARE(countItems(model), 40);
0308 
0309     model->addCompletionModel(testModel2);
0310     QCOMPARE(countItems(model), 80);
0311 
0312     model->removeCompletionModel(testModel2);
0313     QCOMPARE(countItems(model), 40);
0314 }
0315 
0316 void CompletionTest::testAbortImmideatelyAfterStart()
0317 {
0318     new ImmideatelyAbortCompletionModel(m_view);
0319     m_view->setCursorPosition(Cursor(0, 3));
0320     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0321     Q_EMIT m_view->userInvokedCompletion();
0322     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0323 }
0324 
0325 void CompletionTest::testJumpToListBottomAfterCursorUpWhileAtTop()
0326 {
0327     new CodeCompletionTestModel(m_view, QStringLiteral("aa"));
0328     invokeCompletionBox(m_view);
0329 
0330     m_view->completionWidget()->cursorUp();
0331     m_view->completionWidget()->bottom();
0332     // TODO - better way of finding the index?
0333     QCOMPARE(m_view->completionWidget()->treeView()->selectionModel()->currentIndex().row(), 39);
0334 }
0335 
0336 void CompletionTest::testAbbreviationEngine()
0337 {
0338     int s = 0;
0339     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("fb"), s));
0340     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("foob"), s));
0341     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("fbar"), s));
0342     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("fba"), s));
0343     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("foba"), s));
0344     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarBazBang"), QStringLiteral("fbbb"), s));
0345     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("foo_bar_cat"), QStringLiteral("fbc"), s));
0346     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("foo_bar_cat"), QStringLiteral("fb"), s));
0347     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fba"), s));
0348     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fbara"), s));
0349     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fobaar"), s));
0350     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fb"), s));
0351 
0352     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("QualifiedIdentifier"), QStringLiteral("qid"), s));
0353     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("QualifiedIdentifier"), QStringLiteral("qualid"), s));
0354     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("QualifiedIdentifier"), QStringLiteral("qualidentifier"), s));
0355     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("QualifiedIdentifier"), QStringLiteral("qi"), s));
0356     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kcmodel"), s));
0357     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kc"), s));
0358     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kcomplmodel"), s));
0359     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kacomplmodel"), s));
0360     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kacom"), s));
0361 
0362     QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("QualifiedIdentifier"), QStringLiteral("identifier"), s));
0363     QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fobaara"), s));
0364     QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBarArr"), QStringLiteral("fbac"), s));
0365     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kamodel"), s));
0366 
0367     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("AbcdefBcdefCdefDefEfFzZ"), QStringLiteral("AbcdefBcdefCdefDefEfFzZ"), s));
0368     QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("AbcdefBcdefCdefDefEfFzZ"), QStringLiteral("ABCDEFX"), s));
0369     QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("AaaaaaBbbbbCcccDddEeFzZ"), QStringLiteral("XZYBFA"), s));
0370 
0371     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("fb"), s));
0372     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("FooBar"), QStringLiteral("FB"), s));
0373     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("kcmodel"), s));
0374     QVERIFY(KateCompletionModel::matchesAbbreviation(QStringLiteral("KateCompletionModel"), QStringLiteral("KCModel"), s));
0375 }
0376 
0377 void CompletionTest::testAutoCompletionPreselectFirst()
0378 {
0379     new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0380 
0381     m_view->config()->setValue(KateViewConfig::AutomaticCompletionPreselectFirst, false);
0382     // When AutomaticCompletionPreselectFirst is disabled, immediately pressing enter
0383     // should result into a newline instead of completion
0384     m_doc->clear();
0385     m_doc->insertText({0, 0}, QStringLiteral("a"));
0386     m_view->setCursorPosition(Cursor(0, 1));
0387     m_view->completionWidget()->automaticInvocation();
0388     verifyCompletionStarted(m_view);
0389     auto enterKeyEvent = QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
0390     QApplication::sendEvent(m_view->focusProxy(), &enterKeyEvent);
0391 
0392     verifyCompletionAborted(m_view);
0393     QCOMPARE(m_doc->text(), QStringLiteral("a\n"));
0394 }
0395 
0396 void CompletionTest::testTabCompletion()
0397 {
0398     new CodeCompletionTestModel(m_view, QStringLiteral("a"));
0399 
0400     m_view->config()->setValue(KateViewConfig::TabCompletion, true);
0401 
0402     // First entry already selected
0403     m_view->config()->setValue(KateViewConfig::AutomaticCompletionPreselectFirst, true);
0404 
0405     // Nothing to do, already selected
0406     m_doc->clear();
0407     m_doc->insertText({0, 0}, QStringLiteral("a"));
0408     m_view->completionWidget()->automaticInvocation();
0409     verifyCompletionStarted(m_view);
0410     m_view->completionWidget()->execute();
0411     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0412     QCOMPARE(m_doc->text(), QStringLiteral("aaa0"));
0413 
0414     // First entry already selected, going down will select the next completion
0415     m_doc->clear();
0416     m_doc->insertText({0, 0}, QStringLiteral("a"));
0417     m_view->completionWidget()->automaticInvocation();
0418     verifyCompletionStarted(m_view);
0419     m_view->completionWidget()->tabCompletion(KateCompletionWidget::Down);
0420     m_view->completionWidget()->execute();
0421     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0422     QCOMPARE(m_doc->text(), QStringLiteral("aad3"));
0423 
0424     // First entry _not_ already selected...
0425     m_view->config()->setValue(KateViewConfig::AutomaticCompletionPreselectFirst, false);
0426 
0427     m_doc->clear();
0428     m_doc->insertText({0, 0}, QStringLiteral("a"));
0429     m_view->completionWidget()->automaticInvocation();
0430     verifyCompletionStarted(m_view);
0431     // ... Tab will select the first entry
0432     m_view->completionWidget()->tabCompletion(KateCompletionWidget::Down);
0433     m_view->completionWidget()->execute();
0434     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0435     QCOMPARE(m_doc->text(), QStringLiteral("aaa0"));
0436 
0437     // While at the top, going up, cycles to the bottom of the list
0438     m_doc->clear();
0439     m_doc->insertText({0, 0}, QStringLiteral("a"));
0440     m_view->completionWidget()->automaticInvocation();
0441     verifyCompletionStarted(m_view);
0442     m_view->completionWidget()->cursorDown(); // Select first entry
0443     m_view->completionWidget()->tabCompletion(KateCompletionWidget::Up);
0444     m_view->completionWidget()->execute();
0445     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0446     QCOMPARE(m_doc->text(), QStringLiteral("ac\u008738"));
0447 
0448     // While at the bottom, going down cycles to the top of the list
0449     m_doc->clear();
0450     m_doc->insertText({0, 0}, QStringLiteral("a"));
0451     m_view->completionWidget()->automaticInvocation();
0452     verifyCompletionStarted(m_view);
0453     m_view->completionWidget()->cursorDown(); // Select first entry
0454     m_view->completionWidget()->tabCompletion(KateCompletionWidget::Up); // Go to bottom
0455     // While at the bottom, Tab goes to the top of the list
0456     m_view->completionWidget()->tabCompletion(KateCompletionWidget::Down);
0457     m_view->completionWidget()->execute();
0458     QVERIFY(!m_view->completionWidget()->isCompletionActive());
0459     QCOMPARE(m_doc->text(), QStringLiteral("aaa0"));
0460 }
0461 
0462 void CompletionTest::benchAbbreviationEngineGoodCase()
0463 {
0464     int s = 0;
0465     QBENCHMARK {
0466         for (int i = 0; i < 10000; i++) {
0467             QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("AaaaaaBbbbbCcccDddEeFzZ"), QStringLiteral("XZYBFA"), s));
0468         }
0469     }
0470 }
0471 
0472 void CompletionTest::benchAbbreviationEngineNormalCase()
0473 {
0474     int s = 0;
0475     QBENCHMARK {
0476         for (int i = 0; i < 10000; i++) {
0477             QVERIFY(!KateCompletionModel::matchesAbbreviation(QStringLiteral("AaaaaaBbbbbCcccDddEeFzZ"), QStringLiteral("ABCDEFX"), s));
0478         }
0479     }
0480 }
0481 
0482 void CompletionTest::benchAbbreviationEngineWorstCase()
0483 {
0484     int s = 0;
0485     QBENCHMARK {
0486         for (int i = 0; i < 10000; i++) {
0487             // This case is quite horrible, because it requires a branch at every letter.
0488             // The current code will at some point drop out and just return false.
0489             KateCompletionModel::matchesAbbreviation(QStringLiteral("XxBbbbbbBbbbbbBbbbbBbbbBbbbbbbBbbbbbBbbbbbBbbbFox"),
0490                                                      QStringLiteral("XbbbbbbbbbbbbbbbbbbbbFx"),
0491                                                      s);
0492         }
0493     }
0494 }
0495 
0496 void CompletionTest::testAbbrevAndContainsMatching()
0497 {
0498     KateCompletionModel *model = m_view->completionWidget()->model();
0499 
0500     new AbbreviationCodeCompletionTestModel(m_view, QString());
0501 
0502     m_view->document()->setText(QStringLiteral("SCA"));
0503     invokeCompletionBox(m_view);
0504     QCOMPARE(model->filteredItemCount(), (uint)6);
0505 
0506     m_view->document()->setText(QStringLiteral("SC"));
0507     invokeCompletionBox(m_view);
0508     QCOMPARE(model->filteredItemCount(), (uint)6);
0509 
0510     m_view->document()->setText(QStringLiteral("sca"));
0511     invokeCompletionBox(m_view);
0512     QCOMPARE(model->filteredItemCount(), (uint)6);
0513 
0514     m_view->document()->setText(QStringLiteral("contains"));
0515     invokeCompletionBox(m_view);
0516     QCOMPARE(model->filteredItemCount(), (uint)2);
0517 
0518     m_view->document()->setText(QStringLiteral("CONTAINS"));
0519     invokeCompletionBox(m_view);
0520     QCOMPARE(model->filteredItemCount(), (uint)2);
0521 
0522     m_view->document()->setText(QStringLiteral("containssome"));
0523     invokeCompletionBox(m_view);
0524     QCOMPARE(model->filteredItemCount(), (uint)1);
0525 
0526     m_view->document()->setText(QStringLiteral("matched"));
0527     m_view->userInvokedCompletion();
0528     QApplication::processEvents();
0529     QCOMPARE(model->filteredItemCount(), (uint)0);
0530 }
0531 
0532 void CompletionTest::testAsyncMatching()
0533 {
0534     KateCompletionModel *model = m_view->completionWidget()->model();
0535 
0536     auto asyncModel = new AsyncCodeCompletionTestModel(m_view, QString());
0537 
0538     m_view->document()->setText(QStringLiteral("matched"));
0539 
0540     m_view->userInvokedCompletion();
0541     QApplication::processEvents();
0542     asyncModel->setItems({QStringLiteral("this_should_be_matched"), QStringLiteral("do_not_find_this")});
0543     QCOMPARE(model->filteredItemCount(), (uint)1);
0544 }
0545 
0546 void CompletionTest::benchCompletionModel()
0547 {
0548     const int testFactor = 1;
0549     const QString text(QStringLiteral("abcdefg abcdef"));
0550     m_doc->setText(text);
0551     CodeCompletionTestModel *testModel1 = new CodeCompletionTestModel(m_view, QStringLiteral("abcdefg"));
0552     testModel1->setRowCount(50 * testFactor);
0553     CodeCompletionTestModel *testModel2 = new CodeCompletionTestModel(m_view, QStringLiteral("abcdef"));
0554     testModel2->setRowCount(50 * testFactor);
0555     CodeCompletionTestModel *testModel3 = new CodeCompletionTestModel(m_view, QStringLiteral("abcde"));
0556     testModel3->setRowCount(50 * testFactor);
0557     CodeCompletionTestModel *testModel4 = new CodeCompletionTestModel(m_view, QStringLiteral("abcd"));
0558     testModel4->setRowCount(500 * testFactor);
0559     QBENCHMARK_ONCE {
0560         for (int i = 0; i < text.size(); ++i) {
0561             m_view->setCursorPosition(Cursor(0, i));
0562             invokeCompletionBox(m_view);
0563         }
0564     }
0565 }
0566 
0567 #include "moc_completion_test.cpp"