File indexing completed on 2024-04-28 11:44:48

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