File indexing completed on 2024-10-13 06:38:58
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2002 David Faure <david@mandrakesoft.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "kreplacetest.h" 0009 0010 #include <assert.h> 0011 #include <stdlib.h> 0012 0013 #include <QApplication> 0014 #include <QDebug> 0015 #include <QEventLoop> 0016 #include <QPushButton> 0017 0018 #include <kreplace.h> 0019 #include <kreplacedialog.h> 0020 0021 void KReplaceTest::enterLoop() 0022 { 0023 QEventLoop eventLoop; 0024 connect(this, &KReplaceTest::exitLoop, &eventLoop, &QEventLoop::quit); 0025 eventLoop.exec(QEventLoop::ExcludeUserInputEvents); 0026 } 0027 0028 KReplaceTest::KReplaceTest(const QStringList &text, const QString &buttonName) 0029 : QObject(nullptr) 0030 , m_text(text) 0031 , m_replace(nullptr) 0032 , m_buttonName(buttonName) 0033 { 0034 } 0035 0036 KReplaceTest::~KReplaceTest() 0037 { 0038 } 0039 0040 void KReplaceTest::replace(const QString &pattern, const QString &replacement, long options) 0041 { 0042 m_needEventLoop = false; 0043 // This creates a replace-next-prompt dialog if needed. 0044 m_replace.reset(new KReplace(pattern, replacement, options)); 0045 0046 // Connect highlight (or textFound) signal to code which handles highlighting of found text. 0047 connect(m_replace.get(), &KFind::textFound, this, &KReplaceTest::slotHighlight); 0048 0049 // Connect findNext signal - called when pressing the button in the dialog 0050 connect(m_replace.get(), &KFind::findNext, this, &KReplaceTest::slotReplaceNext); 0051 0052 // Connect replace signal - called when doing a replacement 0053 connect(m_replace.get(), &KReplace::textReplaced, this, &KReplaceTest::slotReplace); 0054 0055 // Go to initial position 0056 if ((options & KFind::FromCursor) == 0) { 0057 if (m_text.isEmpty()) { 0058 return; 0059 } 0060 if (m_replace->options() & KFind::FindBackwards) { 0061 m_currentPos = --m_text.end(); 0062 } else { 0063 m_currentPos = m_text.begin(); 0064 } 0065 } 0066 0067 // Launch first replacement 0068 slotReplaceNext(); 0069 0070 if (m_needEventLoop) { 0071 enterLoop(); 0072 } 0073 } 0074 0075 void KReplaceTest::slotHighlight(const QString &str, int matchingIndex, int matchedLength) 0076 { 0077 qDebug() << "slotHighlight Index:" << matchingIndex << " Length:" << matchedLength << " Substr:" << str.mid(matchingIndex, matchedLength); 0078 // Emulate the user saying yes 0079 // We need Qt::QueuedConnection (and the enterloop/exitloop) 0080 // otherwise we get an infinite loop (Match never returned, 0081 // so slotReplaceNext never returns) 0082 if (m_replace->options() & KReplaceDialog::PromptOnReplace) { 0083 QDialog *dlg = m_replace->replaceNextDialog(false); 0084 disconnect(dlg, &QDialog::finished, m_replace.get(), nullptr); // hack to avoid slotDialogClosed being called 0085 dlg->hide(); 0086 0087 QPushButton *button = dlg->findChild<QPushButton *>(m_buttonName); 0088 auto clickFunc = [button]() { 0089 button->click(); 0090 }; 0091 QMetaObject::invokeMethod(button, clickFunc, Qt::QueuedConnection); 0092 0093 m_needEventLoop = true; 0094 } 0095 } 0096 0097 void KReplaceTest::slotReplace(const QString &text, int replacementIndex, int replacedLength, int matchedLength) 0098 { 0099 Q_UNUSED(replacementIndex); 0100 Q_UNUSED(replacedLength); 0101 Q_UNUSED(matchedLength); 0102 // qDebug() << "index=" << replacementIndex << " replacedLength=" << replacedLength << " matchedLength=" << matchedLength << " text=" << text.left( 50 ); 0103 *m_currentPos = text; // KReplace hacked the replacement into 'text' in already. 0104 } 0105 0106 void KReplaceTest::slotReplaceNext() 0107 { 0108 // qDebug(); 0109 KFind::Result res = KFind::NoMatch; 0110 int backwards = m_replace->options() & KFind::FindBackwards; 0111 while (res == KFind::NoMatch) { 0112 if (m_replace->needData()) { 0113 m_replace->setData(*m_currentPos); 0114 } 0115 0116 // Let KReplace inspect the text fragment, and display a dialog if a match is found 0117 res = m_replace->replace(); 0118 0119 if (res == KFind::NoMatch) { 0120 QStringList::iterator lastItem = backwards ? m_text.begin() : --m_text.end(); 0121 if (m_currentPos == lastItem) { 0122 break; 0123 } 0124 if (m_replace->options() & KFind::FindBackwards) { 0125 m_currentPos--; 0126 } else { 0127 m_currentPos++; 0128 } 0129 } 0130 } 0131 0132 #if 0 // commented out so that this test doesn't require interaction 0133 if (res == KFind::NoMatch) // i.e. at end 0134 if (m_replace->shouldRestart()) { 0135 if (m_replace->options() & KFind::FindBackwards) { 0136 m_currentPos = m_text.fromLast(); 0137 } else { 0138 m_currentPos = m_text.begin(); 0139 } 0140 slotReplaceNext(); 0141 } 0142 #endif 0143 if (res == KFind::NoMatch && m_needEventLoop) { 0144 Q_EMIT exitLoop(); 0145 } 0146 } 0147 0148 void KReplaceTest::print() 0149 { 0150 QStringList::Iterator it = m_text.begin(); 0151 for (; it != m_text.end(); ++it) { 0152 qDebug() << *it; 0153 } 0154 } 0155 0156 /* button is the button that we emulate pressing, when options includes PromptOnReplace. 0157 Valid possibilities are User1 (replace all) and User3 (replace) */ 0158 static void testReplaceSimple(int options, const QString &buttonName = QString()) 0159 { 0160 qDebug() << "testReplaceSimple: " << options; 0161 KReplaceTest test(QStringList() << QStringLiteral("hellohello"), buttonName); 0162 test.replace(QStringLiteral("hello"), QStringLiteral("HELLO"), options); 0163 QStringList textLines = test.textLines(); 0164 assert(textLines.count() == 1); 0165 if (textLines[0] != QLatin1String("HELLOHELLO")) { 0166 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of 'HELLOHELLO'"; 0167 exit(1); 0168 } 0169 } 0170 0171 // Replacing "a" with "". 0172 // input="aaaaaa", expected output="" 0173 static void testReplaceBlank(int options, const QString &buttonName = QString()) 0174 { 0175 qDebug() << "testReplaceBlank: " << options; 0176 KReplaceTest test(QStringList() << QStringLiteral("aaaaaa"), buttonName); 0177 test.replace(QStringLiteral("a"), QString(), options); 0178 QStringList textLines = test.textLines(); 0179 assert(textLines.count() == 1); 0180 if (!textLines[0].isEmpty()) { 0181 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of ''"; 0182 exit(1); 0183 } 0184 } 0185 0186 // Replacing "" with "foo" 0187 // input="bbbb", expected output="foobfoobfoobfoobfoo" 0188 static void testReplaceBlankSearch(int options, const QString &buttonName = QString()) 0189 { 0190 qDebug() << "testReplaceBlankSearch: " << options; 0191 KReplaceTest test(QStringList() << QStringLiteral("bbbb"), buttonName); 0192 test.replace(QString(), QStringLiteral("foo"), options); 0193 QStringList textLines = test.textLines(); 0194 assert(textLines.count() == 1); 0195 if (textLines[0] != QLatin1String("foobfoobfoobfoobfoo")) { 0196 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of 'foobfoobfoobfoobfoo'"; 0197 exit(1); 0198 } 0199 } 0200 0201 static void testReplaceLonger(int options, const QString &buttonName = QString()) 0202 { 0203 qDebug() << "testReplaceLonger: " << options; 0204 // Standard test of a replacement string longer than the matched string 0205 KReplaceTest test(QStringList() << QStringLiteral("aaaa"), buttonName); 0206 test.replace(QStringLiteral("a"), QStringLiteral("bb"), options); 0207 QStringList textLines = test.textLines(); 0208 assert(textLines.count() == 1); 0209 if (textLines[0] != QLatin1String("bbbbbbbb")) { 0210 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of 'bbbbbbbb'"; 0211 exit(1); 0212 } 0213 } 0214 0215 static void testReplaceLongerInclude(int options, const QString &buttonName = QString()) 0216 { 0217 qDebug() << "testReplaceLongerInclude: " << options; 0218 // Similar test, where the replacement string includes the search string 0219 KReplaceTest test(QStringList() << QStringLiteral("a foo b"), buttonName); 0220 test.replace(QStringLiteral("foo"), QStringLiteral("foobar"), options); 0221 QStringList textLines = test.textLines(); 0222 assert(textLines.count() == 1); 0223 if (textLines[0] != QLatin1String("a foobar b")) { 0224 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of 'a foobar b'"; 0225 exit(1); 0226 } 0227 } 0228 0229 static void testReplaceLongerInclude2(int options, const QString &buttonName = QString()) 0230 { 0231 qDebug() << "testReplaceLongerInclude2: " << options; 0232 // Similar test, but with more chances of matches inside the replacement string 0233 KReplaceTest test(QStringList() << QStringLiteral("aaaa"), buttonName); 0234 test.replace(QStringLiteral("a"), QStringLiteral("aa"), options); 0235 QStringList textLines = test.textLines(); 0236 assert(textLines.count() == 1); 0237 if (textLines[0] != QLatin1String("aaaaaaaa")) { 0238 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of 'aaaaaaaa'"; 0239 exit(1); 0240 } 0241 } 0242 0243 // Test for the \0 backref 0244 static void testReplaceBackRef(int options, const QString &buttonName = QString()) 0245 { 0246 KReplaceTest test(QStringList() << QStringLiteral("abc def"), buttonName); 0247 test.replace(QStringLiteral("abc"), QStringLiteral("(\\0)"), options); 0248 QStringList textLines = test.textLines(); 0249 assert(textLines.count() == 1); 0250 QString expected = options & KReplaceDialog::BackReference ? QStringLiteral("(abc) def") : QStringLiteral("(\\0) def"); 0251 if (textLines[0] != expected) { 0252 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of '" << expected << "'"; 0253 exit(1); 0254 } 0255 } 0256 0257 // Test for other backrefs 0258 static void testReplaceBackRef1(int options, const QString &buttonName = QString()) 0259 { 0260 KReplaceTest test(QStringList() << QStringLiteral("a1 b2 a3"), buttonName); 0261 test.replace(QStringLiteral("([ab])([\\d])"), QStringLiteral("\\1 and \\2 in (\\0)"), options); 0262 QStringList textLines = test.textLines(); 0263 assert(textLines.count() == 1); 0264 QString expected = QStringLiteral("a and 1 in (a1) b and 2 in (b2) a and 3 in (a3)"); 0265 if (textLines[0] != expected) { 0266 qCritical() << "ASSERT FAILED: replaced text is '" << textLines[0] << "' instead of '" << expected << "'"; 0267 exit(1); 0268 } 0269 } 0270 0271 static void testReplacementHistory(const QStringList &findHistory, const QStringList &replaceHistory) 0272 { 0273 KReplaceDialog dlg(nullptr, 0, findHistory, replaceHistory); 0274 dlg.show(); 0275 qDebug() << "testReplacementHistory:" << dlg.replacementHistory(); 0276 assert(dlg.replacementHistory() == replaceHistory); 0277 } 0278 0279 static void testReplacementHistory() 0280 { 0281 QStringList findHistory; 0282 QStringList replaceHistory; 0283 findHistory << QStringLiteral("foo") << QStringLiteral("bar"); 0284 replaceHistory << QStringLiteral("FOO") << QStringLiteral("BAR"); 0285 testReplacementHistory(findHistory, replaceHistory); 0286 0287 findHistory.clear(); 0288 replaceHistory.clear(); 0289 findHistory << QStringLiteral("foo") << QStringLiteral("bar"); 0290 replaceHistory << QString() << QStringLiteral("baz"); // #130831 0291 testReplacementHistory(findHistory, replaceHistory); 0292 } 0293 0294 int main(int argc, char **argv) 0295 { 0296 QApplication::setApplicationName(QStringLiteral("kreplacetest")); 0297 QApplication app(argc, argv); 0298 0299 testReplacementHistory(); // #130831 0300 0301 testReplaceBlank(0); 0302 testReplaceBlank(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0303 testReplaceBlank(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0304 testReplaceBlank(KFind::FindBackwards); 0305 testReplaceBlank(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0306 testReplaceBlank(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0307 0308 testReplaceBlankSearch(0); 0309 testReplaceBlankSearch(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0310 testReplaceBlankSearch(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0311 testReplaceBlankSearch(KFind::FindBackwards); 0312 testReplaceBlankSearch(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0313 testReplaceBlankSearch(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0314 0315 testReplaceSimple(0); 0316 testReplaceSimple(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0317 testReplaceSimple(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0318 testReplaceSimple(KFind::FindBackwards); 0319 testReplaceSimple(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0320 testReplaceSimple(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0321 0322 testReplaceLonger(0); 0323 testReplaceLonger(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0324 testReplaceLonger(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0325 testReplaceLonger(KFind::FindBackwards); 0326 testReplaceLonger(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0327 testReplaceLonger(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0328 0329 testReplaceLongerInclude(0); 0330 testReplaceLongerInclude(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0331 testReplaceLongerInclude(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0332 testReplaceLongerInclude(KFind::FindBackwards); 0333 testReplaceLongerInclude(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0334 testReplaceLongerInclude(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0335 0336 testReplaceLongerInclude2(0); 0337 testReplaceLongerInclude2(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0338 testReplaceLongerInclude2(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0339 testReplaceLongerInclude2(KFind::FindBackwards); 0340 testReplaceLongerInclude2(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0341 testReplaceLongerInclude2(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0342 0343 testReplaceBackRef(0); 0344 testReplaceBackRef(KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0345 testReplaceBackRef(KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0346 0347 testReplaceBackRef(KFind::FindBackwards); 0348 testReplaceBackRef(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0349 testReplaceBackRef(KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0350 testReplaceBackRef(KReplaceDialog::BackReference | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0351 testReplaceBackRef(KReplaceDialog::BackReference | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0352 testReplaceBackRef(KReplaceDialog::BackReference | KFind::FindBackwards); 0353 testReplaceBackRef(KReplaceDialog::BackReference | KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("replaceButton")); // replace 0354 testReplaceBackRef(KReplaceDialog::BackReference | KFind::FindBackwards | KReplaceDialog::PromptOnReplace, QStringLiteral("allButton")); // replace all 0355 0356 testReplaceBackRef1(KReplaceDialog::BackReference | KFind::RegularExpression, QStringLiteral("replaceButton")); // replace 0357 testReplaceBackRef1(KReplaceDialog::BackReference | KFind::RegularExpression, QStringLiteral("allButton")); // replace all 0358 0359 QString text = QLatin1String("This file is part of the KDE project.\n") + QLatin1String("This library is free software; you can redistribute it and/or\n") 0360 + QLatin1String("modify it under the terms of the GNU Library General Public\n") 0361 + QLatin1String("License version 2, as published by the Free Software Foundation.\n") + QLatin1Char('\n') 0362 + QLatin1String(" This library is distributed in the hope that it will be useful,\n") 0363 + QLatin1String(" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") 0364 + QLatin1String(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n") 0365 + QLatin1String(" Library General Public License for more details.\n") + QLatin1Char('\n') 0366 + QLatin1String(" You should have received a copy of the GNU Library General Public License\n") 0367 + QLatin1String(" along with this library; see the file COPYING.LIB. If not, write to\n") 0368 + QLatin1String(" the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n") + QLatin1String(" Boston, MA 02110-1301, USA.\n") 0369 + QLatin1String("More tests:\n") + QLatin1String("ThisThis This, This. This\n") + QLatin1String("aGNU\n") + QLatin1String("free"); 0370 KReplaceTest test(text.split(QLatin1Char('\n')), QStringLiteral("0")); 0371 0372 test.replace(QStringLiteral("GNU"), QStringLiteral("KDE"), 0); 0373 test.replace(QStringLiteral("free"), QStringLiteral("*free*"), 0); 0374 test.replace(QStringLiteral("This"), QStringLiteral("THIS*"), KFind::FindBackwards); 0375 0376 test.print(); 0377 // return app.exec(); 0378 return 0; 0379 } 0380 0381 #include "moc_kreplacetest.cpp"