File indexing completed on 2024-10-13 06:37:51

0001 /*
0002     This file is part of the Kate project.
0003 
0004     SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 #include "camelcursortest.h"
0008 
0009 #include <katedocument.h>
0010 #include <kateview.h>
0011 
0012 #include <QTest>
0013 
0014 QTEST_MAIN(CamelCursorTest)
0015 
0016 CamelCursorTest::CamelCursorTest(QObject *parent)
0017     : QObject(parent)
0018 {
0019     doc = new KTextEditor::DocumentPrivate(false, false);
0020     view = static_cast<KTextEditor::ViewPrivate *>(doc->createView(nullptr));
0021     view->resize(100, 100);
0022     view->show();
0023 }
0024 
0025 CamelCursorTest::~CamelCursorTest()
0026 {
0027     delete doc;
0028 }
0029 
0030 void CamelCursorTest::testWordMovementSingleRow_data()
0031 {
0032     /**
0033      * NOTE: If you are here to fix a bug, try not to add a new function please.
0034      * Instead consider adding a row here with the label as your bug-number.
0035      *
0036      * The other test cases are small because if this works, they will work automaitcally
0037      * since the core functionality is correct.
0038      */
0039 
0040     // The text for document
0041     QTest::addColumn<QString>("text");
0042     // The number of Ctrl + Right/Left movements
0043     QTest::addColumn<int>("movements");
0044     // The expected positions where your cursor is supposed to land
0045     QTest::addColumn<QList<int>>("colPos");
0046     // Highlighting mode
0047     QTest::addColumn<QString>("HlMode");
0048 
0049     // clang-format off
0050     // row name                                         text                                no of mov       expected positions
0051     QTest::addRow("KateView")             << QStringLiteral("KateView")                     << 2 << QList<int>{4, 8} << QStringLiteral("C++");
0052     QTest::addRow("Q_LOGGING_CATEGORY")   << QStringLiteral("Q_LOGGING_CATEGORY();")        << 4 << QList<int>{2, 10, 18, 21} << QStringLiteral("C");
0053     QTest::addRow("Q_L11GING_CATEG0RY")   << QStringLiteral("Q_L11GING_CATEG0RY();")        << 7 << QList<int>{2, 5, 10, 14, 16, 18, 21} << QString();
0054     QTest::addRow("snake_case_name")      << QStringLiteral("int snake_case_name = 123;")   << 7 << QList<int>{4, 10, 15, 20, 22, 25, 26} << QString();
0055     QTest::addRow("bad___SNAKE_case__")   << QStringLiteral("int bad___SNAKE_case__ = 11;") << 7 << QList<int>{4, 10, 16, 23, 25, 27, 28} << QString();
0056     QTest::addRow("QApplication")         << QStringLiteral("QApplication app;")            << 4 << QList<int>{1, 13, 16, 17} << QString();
0057     QTest::addRow("ABCDead")              << QStringLiteral("ABCDead")                      << 2 << QList<int>{3, 7} << QString();
0058     QTest::addRow("SE_CheckBoxIndicator") << QStringLiteral("QStyle::SE_CheckBoxIndicator") << 7 << QList<int>{1, 6, 8, 11, 16, 19, 28} << QStringLiteral("C++");
0059     QTest::addRow("SE_CHECKBoxIndicator") << QStringLiteral("QStyle::SE_CHECKBoxIndicator") << 7 << QList<int>{1, 6, 8, 11, 16, 19, 28} << QString();
0060     QTest::addRow("SE_CHECKBOXINDICATOR") << QStringLiteral("QStyle::SE_CHECKBOXINDICATOR") << 5 << QList<int>{1, 6, 8, 11, 28} << QString();
0061     QTest::addRow("abc0_asd")             << QStringLiteral("int abc0_asd")                 << 3 << QList<int>{4, 9, 12} << QString();
0062     QTest::addRow("abc120_aSD")           << QStringLiteral("int abc120_aSD")               << 4 << QList<int>{4, 11, 12, 14} << QString();
0063     QTest::addRow("aQQ_OPEN")             << QStringLiteral("aQQ_OPEN")                     << 3 << QList<int>{1, 4, 8} << QString();
0064     QTest::addRow("aQQ_OPEN")             << QStringLiteral("    aQQ_OPEN")                 << 4 << QList<int>{4, 5, 8, 12} << QString();
0065 
0066     // PHP stuff that starts with $
0067     doc->setHighlightingMode(QStringLiteral("PHP/PHP"));
0068     QTest::addRow("$phpVar")              << QStringLiteral("$phpVar = 0;")                 << 6 << QList<int>{1, 4, 8, 10, 11, 12} << QStringLiteral("PHP/PHP");
0069     QTest::addRow("$php_Var")             << QStringLiteral("$php_Var = 0;")                << 6 << QList<int>{1, 5, 9, 11, 12, 13} << QStringLiteral("PHP/PHP");
0070     QTest::addRow("$_SESSION")            << QStringLiteral("$_SESSION[\"some\"]")          << 6 << QList<int>{1, 2, 9, 11, 15, 17} << QStringLiteral("PHP/PHP");
0071 
0072     // CSS Color
0073     QTest::addRow("#ff00ff")              << QStringLiteral("#ff00ff")                      << 2 << QList<int>{1, 7} << QStringLiteral("CSS");
0074     QTest::addRow("#00FF00")              << QStringLiteral("#00FF00")                      << 4 << QList<int>{1, 3, 4, 7} << QStringLiteral("HTML");
0075 
0076     QTest::addRow("Bug 448692")             << QStringLiteral("asdf a")                     << 2 << QList<int>{5, 6} << QString();
0077     // unicode
0078     QTest::addRow("unicode")             << QStringLiteral("𝗺𝗮𝘆∕𝗺𝗶𝗴𝗵𝘁")                   << 3 << QList<int>{6, 7, 17} << QString();
0079 
0080     // clang-format on
0081 }
0082 
0083 void CamelCursorTest::testWordMovementSingleRow()
0084 {
0085     QFETCH(QString, text);
0086     QFETCH(int, movements);
0087     QFETCH(QList<int>, colPos);
0088     QFETCH(QString, HlMode);
0089 
0090     doc->setHighlightingMode(HlMode);
0091 
0092     doc->setText(text);
0093     view->setCursorPosition({0, 0});
0094 
0095     for (int i = 0; i < movements; ++i) {
0096         view->wordRight();
0097         QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(0, colPos.at(i)));
0098     }
0099 
0100     // reverse jumping. Reverse everything but last
0101     // element. Last element will be set to 0 as that
0102     // is our start pos
0103     std::reverse(colPos.begin(), colPos.end() - 1);
0104     colPos.back() = 0;
0105 
0106     for (int i = 0; i < movements; ++i) {
0107         view->wordLeft();
0108         QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(0, colPos.at(i)));
0109     }
0110 
0111     QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(0, 0));
0112     doc->setHighlightingMode(QString());
0113 }
0114 
0115 void CamelCursorTest::testRtlWordMovement()
0116 {
0117     doc->setText(QStringLiteral("اردو کا جملہ"));
0118     view->setCursorPosition({0, 0});
0119 
0120     // for RTL we move left
0121     auto pos = QList<int>{5, 8, 12};
0122     for (int i = 0; i < 3; ++i) {
0123         view->wordLeft();
0124         QCOMPARE(view->cursorPosition().column(), pos.at(i));
0125     }
0126 
0127     // now reverse to original pos
0128     pos = QList<int>{8, 5, 0};
0129     for (int i = 0; i < 3; ++i) {
0130         view->wordRight();
0131         QCOMPARE(view->cursorPosition().column(), pos.at(i));
0132     }
0133 }
0134 
0135 void CamelCursorTest::testWordMovementMultipleRow_data()
0136 {
0137     QTest::addColumn<QString>("text");
0138     QTest::addColumn<int>("movements");
0139     QTest::addColumn<QList<KTextEditor::Cursor>>("expect_cursor");
0140 
0141     using C = KTextEditor::Cursor;
0142     QTest::addRow("2 lines") << QStringLiteral("KateView\nnextLine") << 4 << QList<C>{C(0, 4), C(0, 8), C(1, 0), C(1, 4)};
0143     QTest::addRow("2 line caps") << QStringLiteral("Kate_VIEW\nNextLINE") << 4 << QList<C>{C(0, 5), C(0, 9), C(1, 0), C(1, 4)};
0144     QTest::addRow("4 lines") << QStringLiteral("Kate\nView\nNext\nLINE") << 7 << QList<C>{C(0, 4), C(1, 0), C(1, 4), C(2, 0), C(2, 4), C(3, 0), C(3, 4)};
0145 }
0146 
0147 void CamelCursorTest::testWordMovementMultipleRow()
0148 {
0149     QFETCH(QString, text);
0150     QFETCH(int, movements);
0151     QFETCH(QList<KTextEditor::Cursor>, expect_cursor);
0152 
0153     doc->setText(text);
0154     view->setCursorPosition({0, 0});
0155 
0156     for (int i = 0; i < movements; ++i) {
0157         view->wordRight();
0158         QCOMPARE(view->cursorPosition(), expect_cursor.at(i));
0159     }
0160 
0161     std::reverse(expect_cursor.begin(), expect_cursor.end() - 1);
0162     expect_cursor.back() = KTextEditor::Cursor(0, 0);
0163 
0164     for (int i = 0; i < movements; ++i) {
0165         view->wordLeft();
0166         QCOMPARE(view->cursorPosition(), expect_cursor.at(i));
0167     }
0168 }
0169 
0170 void CamelCursorTest::testDeletionRight()
0171 {
0172     doc->setText(QStringLiteral("SomeWord"));
0173     view->setCursorPosition({0, 0});
0174 
0175     view->deleteWordRight();
0176     QCOMPARE(doc->text(), QStringLiteral("Word"));
0177     view->deleteWordRight();
0178     QCOMPARE(doc->text(), QString());
0179 
0180     doc->setText(QStringLiteral("Some Word"));
0181     view->setCursorPosition({0, 0});
0182 
0183     view->deleteWordRight();
0184     QCOMPARE(doc->text(), QStringLiteral("Word"));
0185     view->deleteWordRight();
0186     QCOMPARE(doc->text(), QString());
0187 
0188     doc->setText(QStringLiteral("Some_WORD"));
0189     view->setCursorPosition({0, 0});
0190 
0191     view->deleteWordRight();
0192     QCOMPARE(doc->text(), QStringLiteral("WORD"));
0193     view->deleteWordRight();
0194     QCOMPARE(doc->text(), QString());
0195 
0196     doc->setText(QStringLiteral("Some      WORD"));
0197     view->setCursorPosition({0, 0});
0198 
0199     view->deleteWordRight();
0200     QCOMPARE(doc->text(), QStringLiteral("WORD"));
0201     view->deleteWordRight();
0202     QCOMPARE(doc->text(), QString());
0203 }
0204 
0205 void CamelCursorTest::testDeletionLeft()
0206 {
0207     doc->setText(QStringLiteral("SomeWord"));
0208     view->setCursorPosition({0, 8});
0209     view->deleteWordLeft();
0210     QCOMPARE(doc->text(), QStringLiteral("Some"));
0211     view->deleteWordLeft();
0212     QCOMPARE(doc->text(), QString());
0213 
0214     doc->setText(QStringLiteral("Some Word"));
0215     view->setCursorPosition({0, 9});
0216     view->deleteWordLeft();
0217     QCOMPARE(doc->text(), QStringLiteral("Some "));
0218     view->deleteWordLeft();
0219     QCOMPARE(doc->text(), QString());
0220 
0221     doc->setText(QStringLiteral("Some_WORD"));
0222     view->setCursorPosition({0, 9});
0223     view->deleteWordLeft();
0224     QCOMPARE(doc->text(), QStringLiteral("Some_"));
0225     view->deleteWordLeft();
0226     QCOMPARE(doc->text(), QString());
0227 
0228     doc->setText(QStringLiteral("Some   WORD"));
0229     view->setCursorPosition({0, 11});
0230     view->deleteWordLeft();
0231     QCOMPARE(doc->text(), QStringLiteral("Some   "));
0232     view->deleteWordLeft();
0233     QCOMPARE(doc->text(), QString());
0234 }
0235 
0236 void CamelCursorTest::testSelectionRight()
0237 {
0238     doc->setText(QStringLiteral("HelloWorld"));
0239     view->setCursorPosition({0, 0});
0240     view->shiftWordRight();
0241     QCOMPARE(view->selectionText(), QStringLiteral("Hello"));
0242     QCOMPARE(view->selectionRange(), KTextEditor::Range(0, 0, 0, 5));
0243 
0244     doc->setText(QStringLiteral("Hello\nWorld"));
0245     view->setCursorPosition({0, 0});
0246     view->shiftWordRight();
0247     view->shiftWordRight();
0248     QCOMPARE(view->selectionText(), QStringLiteral("Hello\n"));
0249     QCOMPARE(view->selectionRange(), KTextEditor::Range(0, 0, 1, 0));
0250 }
0251 
0252 void CamelCursorTest::testSelectionLeft()
0253 {
0254     doc->setText(QStringLiteral("HelloWorld"));
0255     view->setCursorPosition({0, 10});
0256     view->shiftWordLeft();
0257     QCOMPARE(view->selectionText(), QStringLiteral("World"));
0258     QCOMPARE(view->selectionRange(), KTextEditor::Range(0, 5, 0, 10));
0259 
0260     doc->setText(QStringLiteral("Hello\nWorld"));
0261     view->setCursorPosition({1, 0});
0262     view->shiftWordLeft();
0263     view->shiftWordLeft();
0264     QCOMPARE(view->selectionText(), QStringLiteral("Hello\n"));
0265     QCOMPARE(view->selectionRange(), KTextEditor::Range(0, 0, 1, 0));
0266 }
0267 
0268 #include "moc_camelcursortest.cpp"