File indexing completed on 2024-09-15 03:40:08
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "regexpsearch_test.h" 0009 #include "moc_regexpsearch_test.cpp" 0010 0011 #include <katedocument.h> 0012 #include <kateglobal.h> 0013 #include <kateregexpsearch.h> 0014 0015 #include <QRegularExpression> 0016 0017 #include <QTest> 0018 0019 QTEST_MAIN(RegExpSearchTest) 0020 0021 #define testNewRow() (QTest::newRow(QStringLiteral("line %1").arg(__LINE__).toLatin1().data())) 0022 0023 using namespace KTextEditor; 0024 0025 RegExpSearchTest::RegExpSearchTest() 0026 : QObject() 0027 { 0028 KTextEditor::EditorPrivate::enableUnitTestMode(); 0029 } 0030 0031 RegExpSearchTest::~RegExpSearchTest() 0032 { 0033 } 0034 0035 void RegExpSearchTest::testReplaceEscapeSequences_data() 0036 { 0037 QTest::addColumn<QString>("pattern"); 0038 QTest::addColumn<QString>("expected"); 0039 0040 testNewRow() << QStringLiteral("\\") << QStringLiteral("\\"); 0041 testNewRow() << QStringLiteral("\\0") << QStringLiteral("0"); 0042 testNewRow() << QStringLiteral("\\00") << QStringLiteral("00"); 0043 testNewRow() << QStringLiteral("\\000") << QStringLiteral("000"); 0044 testNewRow() << QStringLiteral("\\0000") << QString(QChar(0)); 0045 testNewRow() << QStringLiteral("\\0377") << QString(QChar(0377)); 0046 testNewRow() << QStringLiteral("\\0378") << QStringLiteral("0378"); 0047 testNewRow() << QStringLiteral("\\a") << QStringLiteral("\a"); 0048 testNewRow() << QStringLiteral("\\f") << QStringLiteral("\f"); 0049 testNewRow() << QStringLiteral("\\n") << QStringLiteral("\n"); 0050 testNewRow() << QStringLiteral("\\r") << QStringLiteral("\r"); 0051 testNewRow() << QStringLiteral("\\t") << QStringLiteral("\t"); 0052 testNewRow() << QStringLiteral("\\v") << QStringLiteral("\v"); 0053 testNewRow() << QStringLiteral("\\x") << QStringLiteral("x"); 0054 testNewRow() << QStringLiteral("\\x0") << QStringLiteral("x0"); 0055 testNewRow() << QStringLiteral("\\x00") << QStringLiteral("x00"); 0056 testNewRow() << QStringLiteral("\\x000") << QStringLiteral("x000"); 0057 testNewRow() << QStringLiteral("\\x0000") << QString(QChar(0x0000)); 0058 testNewRow() << QStringLiteral("\\x00000") << QString(QChar(0x0000) + QLatin1Char('0')); 0059 testNewRow() << QStringLiteral("\\xaaaa") << QString(QChar(0xaaaa)); 0060 testNewRow() << QStringLiteral("\\xFFFF") << QString(QChar(0xFFFF)); 0061 testNewRow() << QStringLiteral("\\xFFFg") << QStringLiteral("xFFFg"); 0062 } 0063 0064 void RegExpSearchTest::testReplaceEscapeSequences() 0065 { 0066 QFETCH(QString, pattern); 0067 QFETCH(QString, expected); 0068 0069 const QString result1 = KateRegExpSearch::escapePlaintext(pattern); 0070 const QString result2 = KateRegExpSearch::buildReplacement(pattern, QStringList(), 0); 0071 0072 QCOMPARE(result1, expected); 0073 QCOMPARE(result2, expected); 0074 } 0075 0076 void RegExpSearchTest::testReplacementReferences_data() 0077 { 0078 QTest::addColumn<QString>("pattern"); 0079 QTest::addColumn<QString>("expected"); 0080 QTest::addColumn<QStringList>("capturedTexts"); 0081 0082 testNewRow() << QStringLiteral("\\0") << QStringLiteral("b") << (QStringList() << QStringLiteral("b")); 0083 testNewRow() << QStringLiteral("\\00") << QStringLiteral("b0") << (QStringList() << QStringLiteral("b")); 0084 testNewRow() << QStringLiteral("\\000") << QStringLiteral("b00") << (QStringList() << QStringLiteral("b")); 0085 testNewRow() << QStringLiteral("\\0000") << QString(QChar(0)) << (QStringList() << QStringLiteral("b")); 0086 testNewRow() << QStringLiteral("\\1") << QStringLiteral("1") << (QStringList() << QStringLiteral("b")); 0087 testNewRow() << QStringLiteral("\\0") << QStringLiteral("b") << (QStringList() << QStringLiteral("b") << QStringLiteral("c")); 0088 testNewRow() << QStringLiteral("\\1") << QStringLiteral("c") << (QStringList() << QStringLiteral("b") << QStringLiteral("c")); 0089 } 0090 0091 void RegExpSearchTest::testReplacementReferences() 0092 { 0093 QFETCH(QString, pattern); 0094 QFETCH(QString, expected); 0095 QFETCH(QStringList, capturedTexts); 0096 0097 const QString result = KateRegExpSearch::buildReplacement(pattern, capturedTexts, 1); 0098 0099 QCOMPARE(result, expected); 0100 } 0101 0102 void RegExpSearchTest::testReplacementCaseConversion_data() 0103 { 0104 QTest::addColumn<QString>("pattern"); 0105 QTest::addColumn<QString>("expected"); 0106 0107 testNewRow() << QStringLiteral("a\\Uaa") << QStringLiteral("aAA"); 0108 testNewRow() << QStringLiteral("a\\UAa") << QStringLiteral("aAA"); 0109 testNewRow() << QStringLiteral("a\\UaA") << QStringLiteral("aAA"); 0110 0111 testNewRow() << QStringLiteral("a\\Uáa") << QStringLiteral("aÁA"); 0112 testNewRow() << QStringLiteral("a\\UAá") << QStringLiteral("aAÁ"); 0113 testNewRow() << QStringLiteral("a\\UaÁ") << QStringLiteral("aAÁ"); 0114 0115 testNewRow() << QStringLiteral("a\\uaa") << QStringLiteral("aAa"); 0116 testNewRow() << QStringLiteral("a\\uAa") << QStringLiteral("aAa"); 0117 testNewRow() << QStringLiteral("a\\uaA") << QStringLiteral("aAA"); 0118 0119 testNewRow() << QStringLiteral("a\\uáa") << QStringLiteral("aÁa"); 0120 testNewRow() << QStringLiteral("a\\uÁa") << QStringLiteral("aÁa"); 0121 testNewRow() << QStringLiteral("a\\uáA") << QStringLiteral("aÁA"); 0122 0123 testNewRow() << QStringLiteral("A\\LAA") << QStringLiteral("Aaa"); 0124 testNewRow() << QStringLiteral("A\\LaA") << QStringLiteral("Aaa"); 0125 testNewRow() << QStringLiteral("A\\LAa") << QStringLiteral("Aaa"); 0126 0127 testNewRow() << QStringLiteral("A\\LÁA") << QStringLiteral("Aáa"); 0128 testNewRow() << QStringLiteral("A\\LaÁ") << QStringLiteral("Aaá"); 0129 testNewRow() << QStringLiteral("A\\LÁa") << QStringLiteral("Aáa"); 0130 0131 testNewRow() << QStringLiteral("A\\lAA") << QStringLiteral("AaA"); 0132 testNewRow() << QStringLiteral("A\\lAa") << QStringLiteral("Aaa"); 0133 testNewRow() << QStringLiteral("A\\laA") << QStringLiteral("AaA"); 0134 0135 testNewRow() << QStringLiteral("A\\lÁA") << QStringLiteral("AáA"); 0136 testNewRow() << QStringLiteral("A\\lÁa") << QStringLiteral("Aáa"); 0137 testNewRow() << QStringLiteral("A\\láA") << QStringLiteral("AáA"); 0138 0139 testNewRow() << QStringLiteral("a\\Ubb\\EaA") << QStringLiteral("aBBaA"); 0140 testNewRow() << QStringLiteral("A\\LBB\\EAa") << QStringLiteral("AbbAa"); 0141 0142 testNewRow() << QStringLiteral("a\\Ubb\\EáA") << QStringLiteral("aBBáA"); 0143 testNewRow() << QStringLiteral("A\\LBB\\EÁa") << QStringLiteral("AbbÁa"); 0144 } 0145 0146 void RegExpSearchTest::testReplacementCaseConversion() 0147 { 0148 QFETCH(QString, pattern); 0149 QFETCH(QString, expected); 0150 0151 const QString result = KateRegExpSearch::buildReplacement(pattern, QStringList(), 1); 0152 0153 QCOMPARE(result, expected); 0154 } 0155 0156 void RegExpSearchTest::testReplacementCounter_data() 0157 { 0158 QTest::addColumn<QString>("pattern"); 0159 QTest::addColumn<int>("counter"); 0160 QTest::addColumn<QString>("expected"); 0161 0162 testNewRow() << QStringLiteral("a\\#b") << 1 << QStringLiteral("a1b"); 0163 testNewRow() << QStringLiteral("a\\#b") << 10 << QStringLiteral("a10b"); 0164 testNewRow() << QStringLiteral("a\\#####b") << 1 << QStringLiteral("a00001b"); 0165 } 0166 0167 void RegExpSearchTest::testReplacementCounter() 0168 { 0169 QFETCH(QString, pattern); 0170 QFETCH(int, counter); 0171 QFETCH(QString, expected); 0172 0173 const QString result = KateRegExpSearch::buildReplacement(pattern, QStringList(), counter); 0174 0175 QCOMPARE(result, expected); 0176 } 0177 0178 void RegExpSearchTest::testAnchoredRegexp_data() 0179 { 0180 QTest::addColumn<QString>("pattern"); 0181 QTest::addColumn<Range>("inputRange"); 0182 QTest::addColumn<bool>("backwards"); 0183 QTest::addColumn<Range>("expected"); 0184 0185 testNewRow() << QStringLiteral("fe") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 2); 0186 testNewRow() << QStringLiteral("fe") << Range(0, 0, 0, 8) << true << Range(0, 6, 0, 8); 0187 0188 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 2); 0189 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 1) << false << Range::invalid(); 0190 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 2) << false << Range(0, 0, 0, 2); 0191 testNewRow() << QStringLiteral("^fe") << Range(0, 3, 0, 8) << false << Range::invalid(); // only match at line start 0192 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 2) << true << Range(0, 0, 0, 2); 0193 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 1) << true << Range::invalid(); 0194 testNewRow() << QStringLiteral("^fe") << Range(0, 0, 0, 2) << true << Range(0, 0, 0, 2); 0195 testNewRow() << QStringLiteral("^fe") << Range(0, 3, 0, 8) << true << Range::invalid(); 0196 0197 testNewRow() << QStringLiteral("fe$") << Range(0, 0, 0, 8) << false << Range(0, 6, 0, 8); 0198 testNewRow() << QStringLiteral("fe$") << Range(0, 7, 0, 8) << false << Range::invalid(); 0199 testNewRow() << QStringLiteral("fe$") << Range(0, 6, 0, 8) << false << Range(0, 6, 0, 8); 0200 testNewRow() << QStringLiteral("fe$") << Range(0, 0, 0, 5) << false << Range::invalid(); // only match at line end, fails 0201 testNewRow() << QStringLiteral("fe$") << Range(0, 0, 0, 8) << true << Range(0, 6, 0, 8); 0202 testNewRow() << QStringLiteral("fe$") << Range(0, 7, 0, 8) << true << Range::invalid(); 0203 testNewRow() << QStringLiteral("fe$") << Range(0, 6, 0, 8) << true << Range(0, 6, 0, 8); 0204 testNewRow() << QStringLiteral("fe$") << Range(0, 0, 0, 5) << true << Range::invalid(); 0205 0206 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 8); 0207 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 3, 0, 8) << false << Range::invalid(); 0208 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 0, 0, 5) << false << Range::invalid(); 0209 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 3, 0, 5) << false << Range::invalid(); 0210 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 0, 0, 8) << true << Range(0, 0, 0, 8); 0211 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 3, 0, 8) << true << Range::invalid(); 0212 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 0, 0, 5) << true << Range::invalid(); 0213 testNewRow() << QStringLiteral("^fe fe fe$") << Range(0, 3, 0, 5) << true << Range::invalid(); 0214 0215 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 8); 0216 testNewRow() << QStringLiteral("^fe( fe)*") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 8); 0217 testNewRow() << QStringLiteral("fe( fe)*$") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 8); 0218 testNewRow() << QStringLiteral("fe( fe)*") << Range(0, 0, 0, 8) << false << Range(0, 0, 0, 8); 0219 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 3, 0, 8) << false << Range::invalid(); 0220 testNewRow() << QStringLiteral("fe( fe)*$") << Range(0, 3, 0, 8) << false << Range(0, 3, 0, 8); 0221 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 0, 0, 5) << false << Range::invalid(); 0222 // fails because the whole line is fed to QRegularExpression, then matches 0223 // that end beyond the search range are rejected, see KateRegExpSearch::searchText() 0224 // testNewRow() << "^fe( fe)*" << Range(0, 0, 0, 5) << false << Range(0, 0, 0, 5); 0225 0226 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 0, 0, 8) << true << Range(0, 0, 0, 8); 0227 testNewRow() << QStringLiteral("^fe( fe)*") << Range(0, 0, 0, 8) << true << Range(0, 0, 0, 8); 0228 testNewRow() << QStringLiteral("fe( fe)*$") << Range(0, 0, 0, 8) << true << Range(0, 0, 0, 8); 0229 testNewRow() << QStringLiteral("fe( fe)*") << Range(0, 0, 0, 8) << true << Range(0, 0, 0, 8); 0230 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 3, 0, 8) << true << Range::invalid(); 0231 testNewRow() << QStringLiteral("fe( fe)*$") << Range(0, 3, 0, 8) << true << Range(0, 3, 0, 8); 0232 testNewRow() << QStringLiteral("^fe( fe)*$") << Range(0, 0, 0, 5) << true << Range::invalid(); 0233 0234 testNewRow() << QStringLiteral("^fe|fe$") << Range(0, 0, 0, 5) << false << Range(0, 0, 0, 2); 0235 testNewRow() << QStringLiteral("^fe|fe$") << Range(0, 3, 0, 8) << false << Range(0, 6, 0, 8); 0236 testNewRow() << QStringLiteral("^fe|fe$") << Range(0, 0, 0, 5) << true << Range(0, 0, 0, 2); 0237 testNewRow() << QStringLiteral("^fe|fe$") << Range(0, 3, 0, 8) << true << Range(0, 6, 0, 8); 0238 } 0239 0240 void RegExpSearchTest::testAnchoredRegexp() 0241 { 0242 QFETCH(QString, pattern); 0243 QFETCH(Range, inputRange); 0244 QFETCH(bool, backwards); 0245 QFETCH(Range, expected); 0246 0247 KTextEditor::DocumentPrivate doc; 0248 doc.setText(QStringLiteral("fe fe fe")); 0249 0250 KateRegExpSearch searcher(&doc); 0251 0252 static int i = 0; 0253 if (i == 34 || i == 36) { 0254 qDebug() << i; 0255 } 0256 i++; 0257 0258 const Range result = searcher.search(pattern, inputRange, backwards, QRegularExpression::CaseInsensitiveOption)[0]; 0259 0260 QCOMPARE(result, expected); 0261 } 0262 0263 void RegExpSearchTest::testSearchForward() 0264 { 0265 KTextEditor::DocumentPrivate doc; 0266 doc.setText(QStringLiteral(" \\piinfercong")); 0267 0268 KateRegExpSearch searcher(&doc); 0269 QList<KTextEditor::Range> result = searcher.search(QStringLiteral("\\\\piinfer(\\w)"), Range(0, 2, 0, 15), false); 0270 0271 QCOMPARE(result.at(0), Range(0, 2, 0, 11)); 0272 QCOMPARE(doc.text(result.at(1)), QLatin1Char('c')); 0273 0274 // Test Unicode 0275 doc.setText(QStringLiteral(" \\piinferćong")); 0276 result = searcher.search(QStringLiteral("\\\\piinfer(\\w)"), Range(0, 2, 0, 15), false); 0277 0278 QCOMPARE(result.at(0), Range(0, 2, 0, 11)); 0279 QCOMPARE(doc.text(result.at(1)), QStringLiteral("ć")); 0280 } 0281 0282 void RegExpSearchTest::testSearchBackwardInSelection() 0283 { 0284 KTextEditor::DocumentPrivate doc; 0285 doc.setText(QStringLiteral("foobar foo bar foo bar foo")); 0286 0287 KateRegExpSearch searcher(&doc); 0288 const Range result = searcher.search(QStringLiteral("foo"), Range(0, 0, 0, 15), true)[0]; 0289 0290 QCOMPARE(result, Range(0, 7, 0, 10)); 0291 } 0292 0293 void RegExpSearchTest::test() 0294 { 0295 KTextEditor::DocumentPrivate doc; 0296 doc.setText(QStringLiteral("\\newcommand{\\piReductionOut}")); 0297 0298 KateRegExpSearch searcher(&doc); 0299 const QList<Range> result = searcher.search(QStringLiteral("\\\\piReduction(\\S)"), Range(0, 10, 0, 28), true); 0300 0301 QCOMPARE(result.size(), 2); 0302 QCOMPARE(result[0], Range(0, 12, 0, 25)); 0303 QCOMPARE(result[1], Range(0, 24, 0, 25)); 0304 QCOMPARE(doc.text(result[0]), QStringLiteral("\\piReductionO")); 0305 QCOMPARE(doc.text(result[1]), QStringLiteral("O")); 0306 } 0307 0308 void RegExpSearchTest::testUnicode() 0309 { 0310 KTextEditor::DocumentPrivate doc; 0311 doc.setText(QStringLiteral("\\newcommand{\\piReductionOÓut}")); 0312 0313 KateRegExpSearch searcher(&doc); 0314 const QList<Range> result = searcher.search(QStringLiteral("\\\\piReduction(\\w)(\\w)"), Range(0, 10, 0, 28), true); 0315 0316 QCOMPARE(result.size(), 3); 0317 QCOMPARE(result.at(0), Range(0, 12, 0, 26)); 0318 QCOMPARE(result.at(1), Range(0, 24, 0, 25)); 0319 QCOMPARE(result.at(2), Range(0, 25, 0, 26)); 0320 QCOMPARE(doc.text(result.at(0)), QStringLiteral("\\piReductionOÓ")); 0321 QCOMPARE(doc.text(result.at(1)), QStringLiteral("O")); 0322 QCOMPARE(doc.text(result.at(2)), QStringLiteral("Ó")); 0323 }