File indexing completed on 2024-10-06 03:41:16

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2010-2018 Dominik Haumann <dhaumann@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "movingcursor_test.h"
0009 #include "moc_movingcursor_test.cpp"
0010 
0011 #include <katedocument.h>
0012 #include <kateglobal.h>
0013 #include <ktexteditor/movingcursor.h>
0014 
0015 #include <QTest>
0016 
0017 using namespace KTextEditor;
0018 
0019 QTEST_MAIN(MovingCursorTest)
0020 
0021 MovingCursorTest::MovingCursorTest()
0022     : QObject()
0023 {
0024     KTextEditor::EditorPrivate::enableUnitTestMode();
0025 }
0026 
0027 MovingCursorTest::~MovingCursorTest()
0028 {
0029 }
0030 
0031 // tests:
0032 // - MovingCursor with StayOnInsert
0033 // - MovingCursor with MoveOnInsert
0034 void MovingCursorTest::testMovingCursor()
0035 {
0036     KTextEditor::DocumentPrivate doc;
0037     MovingCursor *invalid = doc.newMovingCursor(Cursor::invalid());
0038     MovingCursor *moveOnInsert = doc.newMovingCursor(Cursor(0, 0), MovingCursor::MoveOnInsert);
0039     MovingCursor *stayOnInsert = doc.newMovingCursor(Cursor(0, 0), MovingCursor::StayOnInsert);
0040 
0041     // verify initial conditions
0042     QVERIFY(!invalid->isValid());
0043     QCOMPARE(moveOnInsert->toCursor(), Cursor(0, 0));
0044     QCOMPARE(stayOnInsert->toCursor(), Cursor(0, 0));
0045 
0046     // insert some text
0047     doc.insertText(Cursor(0, 0), QStringLiteral("\n1\n22"));
0048 
0049     // check new cursor positions
0050     QCOMPARE(moveOnInsert->toCursor(), Cursor(2, 2));
0051     QCOMPARE(stayOnInsert->toCursor(), Cursor(0, 0));
0052 
0053     // set position to (1, 1) and insert text before cursor
0054     stayOnInsert->setPosition(Cursor(1, 1));
0055     QCOMPARE(stayOnInsert->toCursor(), Cursor(1, 1));
0056     doc.insertText(Cursor(1, 0), QStringLiteral("test"));
0057     QCOMPARE(stayOnInsert->toCursor(), Cursor(1, 5));
0058     doc.undo();
0059     QCOMPARE(stayOnInsert->toCursor(), Cursor(1, 1));
0060 
0061     // position still at (1, 1). insert text at cursor
0062     doc.insertText(Cursor(1, 1), QStringLiteral("test"));
0063     QCOMPARE(stayOnInsert->toCursor(), Cursor(1, 1));
0064     doc.undo();
0065     QCOMPARE(stayOnInsert->toCursor(), Cursor(1, 1));
0066 
0067     //
0068     // same tests with the moveOnInsert cursor
0069     //
0070     // set position to (1, 1) and insert text before cursor
0071     moveOnInsert->setPosition(Cursor(1, 1));
0072     QCOMPARE(moveOnInsert->toCursor(), Cursor(1, 1));
0073     doc.insertText(Cursor(1, 0), QStringLiteral("test"));
0074     QCOMPARE(moveOnInsert->toCursor(), Cursor(1, 5));
0075     doc.undo();
0076     QCOMPARE(moveOnInsert->toCursor(), Cursor(1, 1));
0077 
0078     // position still at (1, 1). insert text at cursor
0079     doc.insertText(Cursor(1, 1), QStringLiteral("test"));
0080     QCOMPARE(moveOnInsert->toCursor(), Cursor(1, 5));
0081     doc.undo();
0082     QCOMPARE(moveOnInsert->toCursor(), Cursor(1, 1));
0083 
0084     // set both cursors to (2, 1) then delete text range that contains cursors
0085     moveOnInsert->setPosition(Cursor(2, 1));
0086     stayOnInsert->setPosition(Cursor(2, 1));
0087     doc.removeText(Range(Cursor(2, 0), Cursor(2, 2)));
0088     QCOMPARE(moveOnInsert->toCursor(), Cursor(2, 0));
0089     QCOMPARE(moveOnInsert->toCursor(), Cursor(2, 0));
0090 }
0091 
0092 // tests:
0093 // - atStartOfDocument
0094 // - atStartOfLine
0095 // - atEndOfDocument
0096 // - atEndOfLine
0097 // - move forward with Wrap
0098 // - move forward with NoWrap
0099 // - move backward
0100 // - gotoNextLine
0101 // - gotoPreviousLine
0102 void MovingCursorTest::testConvenienceApi()
0103 {
0104     KTextEditor::DocumentPrivate doc;
0105     doc.setText(
0106         QStringLiteral("\n"
0107                        "1\n"
0108                        "22\n"
0109                        "333\n"
0110                        "4444\n"
0111                        "55555"));
0112 
0113     // check start and end of document
0114     MovingCursor *startOfDoc = doc.newMovingCursor(Cursor(0, 0));
0115     MovingCursor *endOfDoc = doc.newMovingCursor(Cursor(5, 5));
0116     QVERIFY(startOfDoc->atStartOfDocument());
0117     QVERIFY(startOfDoc->atStartOfLine());
0118     QVERIFY(endOfDoc->atEndOfDocument());
0119     QVERIFY(endOfDoc->atEndOfLine());
0120 
0121     // set cursor to (2, 2) and then move to the left two times
0122     MovingCursor *moving = doc.newMovingCursor(Cursor(2, 2));
0123     QVERIFY(moving->atEndOfLine()); // at 2, 2
0124     QVERIFY(moving->move(-1)); // at 2, 1
0125     QCOMPARE(moving->toCursor(), Cursor(2, 1));
0126     QVERIFY(!moving->atEndOfLine());
0127     QVERIFY(moving->move(-1)); // at 2, 0
0128     QCOMPARE(moving->toCursor(), Cursor(2, 0));
0129     QVERIFY(moving->atStartOfLine());
0130 
0131     // now move again to the left, should wrap to (1, 1)
0132     QVERIFY(moving->move(-1)); // at 1, 1
0133     QCOMPARE(moving->toCursor(), Cursor(1, 1));
0134     QVERIFY(moving->atEndOfLine());
0135 
0136     // advance 7 characters to position (3, 3)
0137     QVERIFY(moving->move(7)); // at 3, 3
0138     QCOMPARE(moving->toCursor(), Cursor(3, 3));
0139 
0140     // advance 20 characters in NoWrap mode, then go back 10 characters
0141     QVERIFY(moving->move(20, MovingCursor::NoWrap)); // at 3, 23
0142     QCOMPARE(moving->toCursor(), Cursor(3, 23));
0143     QVERIFY(moving->move(-10)); // at 3, 13
0144     QCOMPARE(moving->toCursor(), Cursor(3, 13));
0145 
0146     // still at invalid text position. move one char to wrap around
0147     QVERIFY(!moving->isValidTextPosition()); // at 3, 13
0148     QVERIFY(moving->move(1)); // at 4, 0
0149     QCOMPARE(moving->toCursor(), Cursor(4, 0));
0150 
0151     // moving 11 characters in wrap mode moves to (5, 6), which is not a valid
0152     // text position anymore. Hence, moving should be rejected.
0153     QVERIFY(!moving->move(11));
0154     QVERIFY(moving->move(10));
0155     QVERIFY(moving->atEndOfDocument());
0156 
0157     // try to move to next line, which fails. then go to previous line
0158     QVERIFY(!moving->gotoNextLine());
0159     QVERIFY(moving->gotoPreviousLine());
0160     QCOMPARE(moving->toCursor(), Cursor(4, 0));
0161 }
0162 
0163 void MovingCursorTest::testOperators()
0164 {
0165     KTextEditor::DocumentPrivate doc;
0166     doc.setText(
0167         QStringLiteral("--oo--\n"
0168                        "--oo--\n"
0169                        "--oo--"));
0170 
0171     // create lots of cursors for comparison
0172     Cursor invalid = Cursor::invalid();
0173     Cursor c02(0, 2);
0174     Cursor c04(0, 4);
0175     Cursor c14(1, 4);
0176 
0177     MovingCursor *m02 = doc.newMovingCursor(Cursor(0, 2));
0178     MovingCursor *m04 = doc.newMovingCursor(Cursor(0, 4));
0179     MovingCursor *m14 = doc.newMovingCursor(Cursor(1, 4));
0180 
0181     // invalid comparison
0182     QVERIFY(invalid == invalid);
0183     QVERIFY(invalid <= c02);
0184     QVERIFY(invalid < c02);
0185     QVERIFY(!(invalid > c02));
0186     QVERIFY(!(invalid >= c02));
0187 
0188     QVERIFY(!(invalid == *m02));
0189     QVERIFY(invalid <= *m02);
0190     QVERIFY(invalid < *m02);
0191     QVERIFY(!(invalid > *m02));
0192     QVERIFY(!(invalid >= *m02));
0193 
0194     QVERIFY(!(*m02 == invalid));
0195     QVERIFY(!(*m02 <= invalid));
0196     QVERIFY(!(*m02 < invalid));
0197     QVERIFY(*m02 > invalid);
0198     QVERIFY(*m02 >= invalid);
0199 
0200     // MovingCursor <-> MovingCursor
0201     QVERIFY(*m02 == *m02);
0202     QVERIFY(*m02 <= *m02);
0203     QVERIFY(*m02 >= *m02);
0204     QVERIFY(!(*m02 < *m02));
0205     QVERIFY(!(*m02 > *m02));
0206     QVERIFY(!(*m02 != *m02));
0207 
0208     QVERIFY(!(*m02 == *m04));
0209     QVERIFY(*m02 <= *m04);
0210     QVERIFY(!(*m02 >= *m04));
0211     QVERIFY(*m02 < *m04);
0212     QVERIFY(!(*m02 > *m04));
0213     QVERIFY(*m02 != *m04);
0214 
0215     QVERIFY(!(*m04 == *m02));
0216     QVERIFY(!(*m04 <= *m02));
0217     QVERIFY(*m04 >= *m02);
0218     QVERIFY(!(*m04 < *m02));
0219     QVERIFY(*m04 > *m02);
0220     QVERIFY(*m04 != *m02);
0221 
0222     QVERIFY(!(*m02 == *m14));
0223     QVERIFY(*m02 <= *m14);
0224     QVERIFY(!(*m02 >= *m14));
0225     QVERIFY(*m02 < *m14);
0226     QVERIFY(!(*m02 > *m14));
0227     QVERIFY(*m02 != *m14);
0228 
0229     QVERIFY(!(*m14 == *m02));
0230     QVERIFY(!(*m14 <= *m02));
0231     QVERIFY(*m14 >= *m02);
0232     QVERIFY(!(*m14 < *m02));
0233     QVERIFY(*m14 > *m02);
0234     QVERIFY(*m14 != *m02);
0235 
0236     // MovingCursor <-> Cursor
0237     QVERIFY(*m02 == c02);
0238     QVERIFY(*m02 <= c02);
0239     QVERIFY(*m02 >= c02);
0240     QVERIFY(!(*m02 < c02));
0241     QVERIFY(!(*m02 > c02));
0242     QVERIFY(!(*m02 != c02));
0243 
0244     QVERIFY(!(*m02 == c04));
0245     QVERIFY(*m02 <= c04);
0246     QVERIFY(!(*m02 >= c04));
0247     QVERIFY(*m02 < c04);
0248     QVERIFY(!(*m02 > c04));
0249     QVERIFY(*m02 != c04);
0250 
0251     QVERIFY(!(*m04 == c02));
0252     QVERIFY(!(*m04 <= c02));
0253     QVERIFY(*m04 >= c02);
0254     QVERIFY(!(*m04 < c02));
0255     QVERIFY(*m04 > c02);
0256     QVERIFY(*m04 != c02);
0257 
0258     QVERIFY(!(*m02 == c14));
0259     QVERIFY(*m02 <= c14);
0260     QVERIFY(!(*m02 >= c14));
0261     QVERIFY(*m02 < c14);
0262     QVERIFY(!(*m02 > c14));
0263     QVERIFY(*m02 != c14);
0264 
0265     QVERIFY(!(*m14 == c02));
0266     QVERIFY(!(*m14 <= c02));
0267     QVERIFY(*m14 >= c02);
0268     QVERIFY(!(*m14 < c02));
0269     QVERIFY(*m14 > c02);
0270     QVERIFY(*m14 != c02);
0271 
0272     // Cursor <-> MovingCursor
0273     QVERIFY(c02 == *m02);
0274     QVERIFY(c02 <= *m02);
0275     QVERIFY(c02 >= *m02);
0276     QVERIFY(!(c02 < *m02));
0277     QVERIFY(!(c02 > *m02));
0278     QVERIFY(!(c02 != *m02));
0279 
0280     QVERIFY(!(c02 == *m04));
0281     QVERIFY(c02 <= *m04);
0282     QVERIFY(!(c02 >= *m04));
0283     QVERIFY(c02 < *m04);
0284     QVERIFY(!(c02 > *m04));
0285     QVERIFY(c02 != *m04);
0286 
0287     QVERIFY(!(c04 == *m02));
0288     QVERIFY(!(c04 <= *m02));
0289     QVERIFY(c04 >= *m02);
0290     QVERIFY(!(c04 < *m02));
0291     QVERIFY(c04 > *m02);
0292     QVERIFY(c04 != *m02);
0293 
0294     QVERIFY(!(c02 == *m14));
0295     QVERIFY(c02 <= *m14);
0296     QVERIFY(!(c02 >= *m14));
0297     QVERIFY(c02 < *m14);
0298     QVERIFY(!(c02 > *m14));
0299     QVERIFY(c02 != *m14);
0300 
0301     QVERIFY(!(c14 == *m02));
0302     QVERIFY(!(c14 <= *m02));
0303     QVERIFY(c14 >= *m02);
0304     QVERIFY(!(c14 < *m02));
0305     QVERIFY(c14 > *m02);
0306     QVERIFY(c14 != *m02);
0307 }
0308 
0309 void MovingCursorTest::testInvalidMovingCursor()
0310 {
0311     KTextEditor::DocumentPrivate *doc = new KTextEditor::DocumentPrivate;
0312 
0313     // add invalid MovingCursor. Inserts c into KateBuffer::m_invalidCursors
0314     MovingCursor *c = doc->newMovingCursor(Cursor(-1, -1));
0315     QVERIFY(Cursor(-1, -1) == *c);
0316 
0317     c->setPosition(Cursor(0, 0));
0318     QVERIFY(Cursor(0, 0) == *c);
0319 
0320     // now c should be removed from KateBuffer::m_invalidCursors
0321     delete c;
0322 
0323     // crash in bug https://bugs.kde.org/show_bug.cgi?id=248926
0324     // if it crashes: c is still in KateBuffer::m_invalidCursors -> double deletion
0325     delete doc;
0326 }