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