File indexing completed on 2024-12-01 03:42:29
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2012-2018 Dominik Haumann <dhaumann@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kte_documentcursor.h" 0009 0010 #include <katedocument.h> 0011 #include <kateglobal.h> 0012 #include <ktexteditor/documentcursor.h> 0013 #include <ktexteditor/view.h> 0014 0015 #include <QTest> 0016 0017 QTEST_MAIN(DocumentCursorTest) 0018 0019 using namespace KTextEditor; 0020 0021 DocumentCursorTest::DocumentCursorTest() 0022 : QObject() 0023 { 0024 } 0025 0026 DocumentCursorTest::~DocumentCursorTest() 0027 { 0028 } 0029 0030 void DocumentCursorTest::initTestCase() 0031 { 0032 KTextEditor::EditorPrivate::enableUnitTestMode(); 0033 } 0034 0035 void DocumentCursorTest::cleanupTestCase() 0036 { 0037 } 0038 0039 // tests: 0040 // - atStartOfDocument 0041 // - atStartOfLine 0042 // - atEndOfDocument 0043 // - atEndOfLine 0044 // - move forward with Wrap 0045 // - move forward with NoWrap 0046 // - move backward 0047 // - gotoNextLine 0048 // - gotoPreviousLine 0049 void DocumentCursorTest::testConvenienceApi() 0050 { 0051 KTextEditor::DocumentPrivate doc; 0052 doc.setText( 0053 QStringLiteral("\n" 0054 "1\n" 0055 "22\n" 0056 "333\n" 0057 "4444\n" 0058 "55555")); 0059 0060 // check start and end of document 0061 DocumentCursor startOfDoc(&doc); 0062 startOfDoc.setPosition(Cursor(0, 0)); 0063 DocumentCursor endOfDoc(&doc); 0064 endOfDoc.setPosition(Cursor(5, 5)); 0065 QVERIFY(startOfDoc.atStartOfDocument()); 0066 QVERIFY(startOfDoc.atStartOfLine()); 0067 QVERIFY(endOfDoc.atEndOfDocument()); 0068 QVERIFY(endOfDoc.atEndOfLine()); 0069 0070 // set cursor to (2, 2) and then move to the left two times 0071 DocumentCursor moving(&doc); 0072 moving.setPosition(Cursor(2, 2)); 0073 QVERIFY(moving.atEndOfLine()); // at 2, 2 0074 QVERIFY(moving.move(-1)); // at 2, 1 0075 QCOMPARE(moving.toCursor(), Cursor(2, 1)); 0076 QVERIFY(!moving.atEndOfLine()); 0077 QVERIFY(moving.move(-1)); // at 2, 0 0078 QCOMPARE(moving.toCursor(), Cursor(2, 0)); 0079 QVERIFY(moving.atStartOfLine()); 0080 0081 // now move again to the left, should wrap to (1, 1) 0082 QVERIFY(moving.move(-1)); // at 1, 1 0083 QCOMPARE(moving.toCursor(), Cursor(1, 1)); 0084 QVERIFY(moving.atEndOfLine()); 0085 0086 // advance 7 characters to position (3, 3) 0087 QVERIFY(moving.move(7)); // at 3, 3 0088 QCOMPARE(moving.toCursor(), Cursor(3, 3)); 0089 0090 // advance 20 characters in NoWrap mode, then go back 10 characters 0091 QVERIFY(moving.move(20, DocumentCursor::NoWrap)); // at 3, 23 0092 QCOMPARE(moving.toCursor(), Cursor(3, 23)); 0093 QVERIFY(moving.move(-10)); // at 3, 13 0094 QCOMPARE(moving.toCursor(), Cursor(3, 13)); 0095 0096 // still at invalid text position. move one char to wrap around 0097 QVERIFY(!moving.isValidTextPosition()); // at 3, 13 0098 QVERIFY(moving.move(1)); // at 4, 0 0099 QCOMPARE(moving.toCursor(), Cursor(4, 0)); 0100 0101 // moving 11 characters in wrap mode moves to (5, 6), which is not a valid 0102 // text position anymore. Hence, moving should be rejected. 0103 QVERIFY(!moving.move(11)); 0104 QVERIFY(moving.move(10)); 0105 QVERIFY(moving.atEndOfDocument()); 0106 0107 // try to move to next line, which fails. then go to previous line 0108 QVERIFY(!moving.gotoNextLine()); 0109 QVERIFY(moving.gotoPreviousLine()); 0110 QCOMPARE(moving.toCursor(), Cursor(4, 0)); 0111 } 0112 0113 void DocumentCursorTest::testOperators() 0114 { 0115 KTextEditor::DocumentPrivate doc; 0116 doc.setText( 0117 QStringLiteral("--oo--\n" 0118 "--oo--\n" 0119 "--oo--")); 0120 0121 // create lots of cursors for comparison 0122 Cursor invalid = Cursor::invalid(); 0123 Cursor c02(0, 2); 0124 Cursor c04(0, 4); 0125 Cursor c14(1, 4); 0126 0127 DocumentCursor m02(&doc); 0128 DocumentCursor m04(&doc); 0129 DocumentCursor m14(&doc); 0130 0131 QVERIFY(m02 == invalid); 0132 QVERIFY(m04 == invalid); 0133 QVERIFY(m14 == invalid); 0134 0135 m02.setPosition(Cursor(0, 2)); 0136 m04.setPosition(Cursor(0, 4)); 0137 m14.setPosition(Cursor(1, 4)); 0138 0139 // invalid comparison 0140 // cppcheck-suppress duplicateExpression 0141 QVERIFY(invalid == invalid); 0142 QVERIFY(invalid <= c02); 0143 QVERIFY(invalid < c02); 0144 QVERIFY(!(invalid > c02)); 0145 QVERIFY(!(invalid >= c02)); 0146 0147 QVERIFY(!(invalid == m02)); 0148 QVERIFY(invalid <= m02); 0149 QVERIFY(invalid < m02); 0150 QVERIFY(!(invalid > m02)); 0151 QVERIFY(!(invalid >= m02)); 0152 0153 QVERIFY(!(m02 == invalid)); 0154 QVERIFY(!(m02 <= invalid)); 0155 QVERIFY(!(m02 < invalid)); 0156 QVERIFY(m02 > invalid); 0157 QVERIFY(m02 >= invalid); 0158 0159 // DocumentCursor <-> DocumentCursor 0160 // cppcheck-suppress duplicateExpression 0161 QVERIFY(m02 == m02); 0162 // cppcheck-suppress duplicateExpression 0163 QVERIFY(m02 <= m02); 0164 // cppcheck-suppress duplicateExpression 0165 QVERIFY(m02 >= m02); 0166 // cppcheck-suppress duplicateExpression 0167 QVERIFY(!(m02 < m02)); 0168 // cppcheck-suppress duplicateExpression 0169 QVERIFY(!(m02 > m02)); 0170 // cppcheck-suppress duplicateExpression 0171 QVERIFY(!(m02 != m02)); 0172 0173 QVERIFY(!(m02 == m04)); 0174 QVERIFY(m02 <= m04); 0175 QVERIFY(!(m02 >= m04)); 0176 QVERIFY(m02 < m04); 0177 QVERIFY(!(m02 > m04)); 0178 QVERIFY(m02 != m04); 0179 0180 QVERIFY(!(m04 == m02)); 0181 QVERIFY(!(m04 <= m02)); 0182 QVERIFY(m04 >= m02); 0183 QVERIFY(!(m04 < m02)); 0184 QVERIFY(m04 > m02); 0185 QVERIFY(m04 != m02); 0186 0187 QVERIFY(!(m02 == m14)); 0188 QVERIFY(m02 <= m14); 0189 QVERIFY(!(m02 >= m14)); 0190 QVERIFY(m02 < m14); 0191 QVERIFY(!(m02 > m14)); 0192 QVERIFY(m02 != m14); 0193 0194 QVERIFY(!(m14 == m02)); 0195 QVERIFY(!(m14 <= m02)); 0196 QVERIFY(m14 >= m02); 0197 QVERIFY(!(m14 < m02)); 0198 QVERIFY(m14 > m02); 0199 QVERIFY(m14 != m02); 0200 0201 // DocumentCursor <-> Cursor 0202 QVERIFY(m02 == c02); 0203 QVERIFY(m02 <= c02); 0204 QVERIFY(m02 >= c02); 0205 QVERIFY(!(m02 < c02)); 0206 QVERIFY(!(m02 > c02)); 0207 QVERIFY(!(m02 != c02)); 0208 0209 QVERIFY(!(m02 == c04)); 0210 QVERIFY(m02 <= c04); 0211 QVERIFY(!(m02 >= c04)); 0212 QVERIFY(m02 < c04); 0213 QVERIFY(!(m02 > c04)); 0214 QVERIFY(m02 != c04); 0215 0216 QVERIFY(!(m04 == c02)); 0217 QVERIFY(!(m04 <= c02)); 0218 QVERIFY(m04 >= c02); 0219 QVERIFY(!(m04 < c02)); 0220 QVERIFY(m04 > c02); 0221 QVERIFY(m04 != c02); 0222 0223 QVERIFY(!(m02 == c14)); 0224 QVERIFY(m02 <= c14); 0225 QVERIFY(!(m02 >= c14)); 0226 QVERIFY(m02 < c14); 0227 QVERIFY(!(m02 > c14)); 0228 QVERIFY(m02 != c14); 0229 0230 QVERIFY(!(m14 == c02)); 0231 QVERIFY(!(m14 <= c02)); 0232 QVERIFY(m14 >= c02); 0233 QVERIFY(!(m14 < c02)); 0234 QVERIFY(m14 > c02); 0235 QVERIFY(m14 != c02); 0236 0237 // Cursor <-> DocumentCursor 0238 QVERIFY(c02 == m02); 0239 QVERIFY(c02 <= m02); 0240 QVERIFY(c02 >= m02); 0241 QVERIFY(!(c02 < m02)); 0242 QVERIFY(!(c02 > m02)); 0243 QVERIFY(!(c02 != m02)); 0244 0245 QVERIFY(!(c02 == m04)); 0246 QVERIFY(c02 <= m04); 0247 QVERIFY(!(c02 >= m04)); 0248 QVERIFY(c02 < m04); 0249 QVERIFY(!(c02 > m04)); 0250 QVERIFY(c02 != m04); 0251 0252 QVERIFY(!(c04 == m02)); 0253 QVERIFY(!(c04 <= m02)); 0254 QVERIFY(c04 >= m02); 0255 QVERIFY(!(c04 < m02)); 0256 QVERIFY(c04 > m02); 0257 QVERIFY(c04 != m02); 0258 0259 QVERIFY(!(c02 == m14)); 0260 QVERIFY(c02 <= m14); 0261 QVERIFY(!(c02 >= m14)); 0262 QVERIFY(c02 < m14); 0263 QVERIFY(!(c02 > m14)); 0264 QVERIFY(c02 != m14); 0265 0266 QVERIFY(!(c14 == m02)); 0267 QVERIFY(!(c14 <= m02)); 0268 QVERIFY(c14 >= m02); 0269 QVERIFY(!(c14 < m02)); 0270 QVERIFY(c14 > m02); 0271 QVERIFY(c14 != m02); 0272 } 0273 0274 void DocumentCursorTest::testValidTextPosition() 0275 { 0276 // test: utf-32 characters that are visually only one single character (Unicode surrogates) 0277 // Inside such a utf-32 character, the text position is not valid. 0278 KTextEditor::DocumentPrivate doc; 0279 DocumentCursor c(&doc); 0280 0281 // 0xfffe: byte-order-mark (BOM) 0282 // 0x002d: '-' 0283 // 0x3dd8, 0x38de: an utf32-surrogate, see https://www.fileformat.info/info/unicode/char/1f638/browsertest.htm 0284 const char16_t line0[] = {0xfffe, 0x2d00, 0x3dd8, 0x38de, 0x2d00}; // -xx- where xx is one utf32 char 0285 const char16_t line1[] = {0xfffe, 0x2d00, 0x3dd8, 0x2d00, 0x2d00}; // -x-- where x is a high surrogate (broken utf32) 0286 const char16_t line2[] = {0xfffe, 0x2d00, 0x2d00, 0x38de, 0x2d00}; // --x- where x is a low surrogate (broken utf32) 0287 doc.setText(QString::fromUtf16(line0, 5)); 0288 doc.insertLine(1, QString::fromUtf16(line1, 5)); 0289 doc.insertLine(2, QString::fromUtf16(line2, 5)); 0290 0291 // set to true if you want to see the contents 0292 const bool showView = false; 0293 if (showView) { 0294 doc.createView(nullptr)->show(); 0295 QTest::qWait(5000); 0296 } 0297 0298 // line 0: invalid in utf-32 char 0299 c.setPosition(0, 0); 0300 QVERIFY(c.isValidTextPosition()); 0301 c.setPosition(0, 1); 0302 QVERIFY(c.isValidTextPosition()); 0303 c.setPosition(0, 2); 0304 QVERIFY(!c.isValidTextPosition()); 0305 c.setPosition(0, 3); 0306 QVERIFY(c.isValidTextPosition()); 0307 c.setPosition(0, 4); 0308 QVERIFY(c.isValidTextPosition()); 0309 c.setPosition(0, 5); 0310 QVERIFY(!c.isValidTextPosition()); 0311 0312 // line 1, valid in broken utf-32 char (2nd part missing) 0313 c.setPosition(1, 0); 0314 QVERIFY(c.isValidTextPosition()); 0315 c.setPosition(1, 1); 0316 QVERIFY(c.isValidTextPosition()); 0317 c.setPosition(1, 2); 0318 QVERIFY(c.isValidTextPosition()); 0319 c.setPosition(1, 3); 0320 QVERIFY(c.isValidTextPosition()); 0321 c.setPosition(1, 4); 0322 QVERIFY(c.isValidTextPosition()); 0323 c.setPosition(1, 5); 0324 QVERIFY(!c.isValidTextPosition()); 0325 0326 // line 2, valid in broken utf-32 char (1st part missing) 0327 c.setPosition(2, 0); 0328 QVERIFY(c.isValidTextPosition()); 0329 c.setPosition(2, 1); 0330 QVERIFY(c.isValidTextPosition()); 0331 c.setPosition(2, 2); 0332 QVERIFY(c.isValidTextPosition()); 0333 c.setPosition(2, 3); 0334 QVERIFY(c.isValidTextPosition()); 0335 c.setPosition(2, 4); 0336 QVERIFY(c.isValidTextPosition()); 0337 c.setPosition(2, 5); 0338 QVERIFY(!c.isValidTextPosition()); 0339 0340 // test out-of-range 0341 c.setPosition(-1, 0); 0342 QVERIFY(!c.isValidTextPosition()); 0343 c.setPosition(3, 0); 0344 QVERIFY(!c.isValidTextPosition()); 0345 c.setPosition(0, -1); 0346 QVERIFY(!c.isValidTextPosition()); 0347 } 0348 0349 #include "moc_kte_documentcursor.cpp"