1 /* 2 This file is part of the KDE libraries 3 4 SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org> 5 6 SPDX-License-Identifier: LGPL-2.0-or-later 7 */ 8 9 #include <QClipboard> 10 #include <QSignalSpy> 11 #include <QTest> 12 #include <QToolButton> 13 #include <kcompletionbox.h> 14 #include <klineedit.h> 15 16 class KLineEdit_UnitTest : public QObject 17 { 18 Q_OBJECT 19 20 private Q_SLOTS: 21 #if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 83) testPassword()22 void testPassword() 23 { 24 KLineEdit w; 25 w.setPasswordMode(true); 26 QTest::keyClick(&w, Qt::Key_1); 27 QTest::keyClick(&w, Qt::Key_2); 28 QTest::keyClick(&w, Qt::Key_3); 29 QCOMPARE(w.text(), QString("123")); 30 } 31 #endif 32 testReturnPressed()33 void testReturnPressed() 34 { 35 KLineEdit w; 36 w.setText(QStringLiteral("Hello world")); 37 QSignalSpy qReturnPressedSpy(&w, &QLineEdit::returnPressed); 38 39 #if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81) 40 QSignalSpy kReturnPressedSpy(&w, qOverload<const QString &>(&KLineEdit::returnPressed)); 41 #endif 42 QSignalSpy returnKeyPressedSpy(&w, &KLineEdit::returnKeyPressed); 43 44 QTest::keyClick(&w, Qt::Key_Return); 45 QCOMPARE(qReturnPressedSpy.count(), 1); 46 47 #if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81) 48 QCOMPARE(kReturnPressedSpy.count(), 1); 49 QCOMPARE(kReturnPressedSpy[0][0].toString(), QString("Hello world")); 50 #endif 51 QCOMPARE(returnKeyPressedSpy.count(), 1); 52 QCOMPARE(returnKeyPressedSpy.at(0).at(0).toString(), QStringLiteral("Hello world")); 53 } 54 testTextEditedSignals()55 void testTextEditedSignals() 56 { 57 KLineEdit w; 58 QVERIFY(!w.isModified()); 59 60 // setText emits textChanged and userTextChanged, but not textEdited 61 QSignalSpy textChangedSpy(&w, &QLineEdit::textChanged); 62 QSignalSpy textEditedSpy(&w, &QLineEdit::textEdited); 63 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 64 QSignalSpy userTextChangedSpy(&w, &KLineEdit::userTextChanged); 65 #endif 66 w.setText(QStringLiteral("Hello worl")); 67 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 68 QCOMPARE(userTextChangedSpy.count(), 1); 69 QCOMPARE(userTextChangedSpy[0][0].toString(), w.text()); 70 #endif 71 QCOMPARE(textChangedSpy.count(), 1); 72 QCOMPARE(textChangedSpy[0][0].toString(), w.text()); 73 QCOMPARE(textEditedSpy.count(), 0); 74 QVERIFY(!w.isModified()); 75 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 76 userTextChangedSpy.clear(); 77 #endif 78 textChangedSpy.clear(); 79 textEditedSpy.clear(); 80 81 // calling clear should emit textChanged and userTextChanged, but not textEdited 82 w.clear(); 83 QCOMPARE(textChangedSpy.count(), 1); 84 QCOMPARE(textEditedSpy.count(), 0); 85 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 86 QCOMPARE(userTextChangedSpy.count(), 1); 87 #endif 88 89 // if text box is already empty, calling clear() shouldn't emit 90 // any more signals 91 w.clear(); 92 QCOMPARE(textChangedSpy.count(), 1); 93 QCOMPARE(textEditedSpy.count(), 0); 94 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 95 QCOMPARE(userTextChangedSpy.count(), 1); 96 #endif 97 98 // set the text back for further tests below 99 w.setText(QStringLiteral("Hello worl")); 100 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 101 userTextChangedSpy.clear(); 102 #endif 103 textChangedSpy.clear(); 104 textEditedSpy.clear(); 105 106 // typing emits all three signals 107 QTest::keyClick(&w, Qt::Key_D); 108 QCOMPARE(w.text(), QString::fromLatin1("Hello world")); 109 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 110 QCOMPARE(userTextChangedSpy.count(), 1); 111 QCOMPARE(userTextChangedSpy[0][0].toString(), w.text()); 112 #endif 113 QCOMPARE(textChangedSpy.count(), 1); 114 QCOMPARE(textChangedSpy[0][0].toString(), w.text()); 115 QCOMPARE(textEditedSpy.count(), 1); 116 QCOMPARE(textEditedSpy[0][0].toString(), w.text()); 117 QVERIFY(w.isModified()); 118 119 w.setText(QStringLiteral("K")); // prepare for next test 120 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 121 userTextChangedSpy.clear(); 122 #endif 123 textChangedSpy.clear(); 124 textEditedSpy.clear(); 125 QVERIFY(!w.isModified()); 126 127 // the suggestion from auto completion emits textChanged but not userTextChanged nor textEdited 128 w.setCompletionMode(KCompletion::CompletionAuto); 129 KCompletion completion; 130 completion.setSoundsEnabled(false); 131 QStringList items; 132 items << QStringLiteral("KDE is cool") << QStringLiteral("KDE is really cool"); 133 completion.setItems(items); 134 w.setCompletionObject(&completion); 135 136 w.doCompletion(w.text()); 137 QCOMPARE(w.text(), items.at(0)); 138 139 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 140 QCOMPARE(userTextChangedSpy.count(), 0); 141 #endif 142 QCOMPARE(textChangedSpy.count(), 1); 143 QCOMPARE(textChangedSpy[0][0].toString(), w.text()); 144 QCOMPARE(textEditedSpy.count(), 0); 145 QVERIFY(!w.isModified()); 146 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 147 userTextChangedSpy.clear(); 148 #endif 149 textChangedSpy.clear(); 150 textEditedSpy.clear(); 151 152 // accepting the completion suggestion now emits all three signals too 153 QTest::keyClick(&w, Qt::Key_Right); 154 QCOMPARE(w.text(), items.at(0)); 155 156 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 157 QCOMPARE(userTextChangedSpy.count(), 1); 158 QCOMPARE(userTextChangedSpy[0][0].toString(), w.text()); 159 #endif 160 QCOMPARE(textChangedSpy.count(), 1); 161 QCOMPARE(textChangedSpy[0][0].toString(), w.text()); 162 QCOMPARE(textEditedSpy.count(), 1); 163 QCOMPARE(textEditedSpy[0][0].toString(), w.text()); 164 QVERIFY(w.isModified()); 165 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 166 userTextChangedSpy.clear(); 167 #endif 168 textChangedSpy.clear(); 169 textEditedSpy.clear(); 170 171 // Now with popup completion 172 w.setCompletionMode(KCompletion::CompletionPopup); 173 w.setText(QStringLiteral("KDE")); 174 QVERIFY(!w.isModified()); 175 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 176 userTextChangedSpy.clear(); 177 #endif 178 textChangedSpy.clear(); 179 textEditedSpy.clear(); 180 w.doCompletion(w.text()); // popup appears 181 QCOMPARE(w.text(), QString::fromLatin1("KDE")); 182 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 183 QCOMPARE(textChangedSpy.count() + userTextChangedSpy.count() + textEditedSpy.count(), 0); 184 #else 185 QCOMPARE(textChangedSpy.count() + textEditedSpy.count(), 0); 186 #endif 187 w.completionBox()->down(); // select 1st item 188 QCOMPARE(w.text(), items.at(0)); 189 QVERIFY(w.isModified()); 190 w.completionBox()->down(); // select 2nd item 191 QCOMPARE(w.text(), items.at(1)); 192 193 // Selecting an item in the popup completion changes the lineedit text 194 // and emits textChanged and userTextChanged, but not textEdited. 195 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 196 QCOMPARE(userTextChangedSpy.count(), 2); 197 #endif 198 QCOMPARE(textChangedSpy.count(), 2); 199 QCOMPARE(textEditedSpy.count(), 0); 200 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 201 userTextChangedSpy.clear(); 202 #endif 203 textChangedSpy.clear(); 204 textEditedSpy.clear(); 205 206 QTest::keyClick(&w, Qt::Key_Enter); // activate 207 QVERIFY(!w.completionBox()->isVisible()); 208 QCOMPARE(w.text(), items.at(1)); 209 QVERIFY(w.isModified()); 210 // Nothing else happens, the text was already set in the lineedit 211 QCOMPARE(textChangedSpy.count(), 0); 212 QCOMPARE(textEditedSpy.count(), 0); 213 #if KCOMPLETION_ENABLE_DEPRECATED_SINCE(4, 5) 214 QCOMPARE(userTextChangedSpy.count(), 0); 215 #endif 216 217 // Now when using the mouse in the popup completion 218 w.setText(QStringLiteral("KDE")); 219 w.doCompletion(w.text()); // popup appears 220 QCOMPARE(w.text(), QString::fromLatin1("KDE")); 221 // Selecting an item in the popup completion changes the lineedit text and emits all 3 signals 222 const QRect rect = w.completionBox()->visualRect(w.completionBox()->model()->index(1, 0)); 223 224 #if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81) 225 QSignalSpy activatedSpy(w.completionBox(), qOverload<const QString &>(&KCompletionBox::activated)); 226 #endif 227 QSignalSpy textActivatedSpy(w.completionBox(), &KCompletionBox::textActivated); 228 229 QTest::mouseClick(w.completionBox()->viewport(), Qt::LeftButton, Qt::NoModifier, rect.center()); 230 231 #if KCOMPLETION_BUILD_DEPRECATED_SINCE(5, 81) 232 QCOMPARE(activatedSpy.count(), 1); 233 #endif 234 QCOMPARE(textActivatedSpy.count(), 1); 235 236 QCOMPARE(w.text(), items.at(1)); 237 QVERIFY(w.isModified()); 238 } 239 testCompletionBox()240 void testCompletionBox() 241 { 242 KLineEdit w; 243 w.setText(QStringLiteral("/")); 244 w.setCompletionMode(KCompletion::CompletionPopup); 245 KCompletion completion; 246 completion.setSoundsEnabled(false); 247 w.setCompletionObject(&completion); 248 QStringList items; 249 items << QStringLiteral("/home/") << QStringLiteral("/hold/") << QStringLiteral("/hole/"); 250 completion.setItems(items); 251 QTest::keyClick(&w, 'h'); 252 QCOMPARE(w.text(), QString::fromLatin1("/h")); 253 QCOMPARE(w.completionBox()->currentRow(), -1); 254 QCOMPARE(w.completionBox()->items(), items); 255 QTest::keyClick(&w, 'o'); 256 QCOMPARE(w.text(), QString::fromLatin1("/ho")); 257 QCOMPARE(w.completionBox()->currentRow(), -1); 258 w.completionBox()->down(); // select 1st item 259 QCOMPARE(w.text(), items.at(0)); 260 w.completionBox()->down(); // select 2nd item 261 QCOMPARE(w.text(), items.at(1)); 262 w.completionBox()->up(); // select 1st item again 263 QCOMPARE(w.text(), items.at(0)); 264 w.completionBox()->up(); // select last item 265 QCOMPARE(w.text(), items.at(2)); 266 w.completionBox()->down(); // select 1st item again 267 QCOMPARE(w.text(), items.at(0)); 268 269 QStringList newItems; 270 newItems << QStringLiteral("/home/kde"); 271 completion.setItems(newItems); 272 QTest::keyClick(&w, 'k'); 273 QCOMPARE(w.text(), QString("/home/k")); 274 // QCOMPARE(w.completionBox()->currentRow(), -1); // #247552 275 w.completionBox()->down(); // select the item 276 QCOMPARE(w.completionBox()->items(), newItems); 277 QCOMPARE(w.text(), newItems.at(0)); 278 } 279 testPaste()280 void testPaste() 281 { 282 const QString origText = QApplication::clipboard()->text(); 283 const QString pastedText = QStringLiteral("Test paste from klineedit_unittest"); 284 QApplication::clipboard()->setText(pastedText); 285 KLineEdit w; 286 w.setText(QStringLiteral("Hello world")); 287 w.selectAll(); 288 QTest::keyClick(&w, Qt::Key_V, Qt::ControlModifier); 289 QCOMPARE(w.text(), pastedText); 290 QApplication::clipboard()->setText(origText); 291 } 292 testClearButtonClicked()293 void testClearButtonClicked() 294 { 295 KLineEdit w; 296 w.setText(QStringLiteral("Hello world")); 297 w.setClearButtonEnabled(true); 298 w.setClearButtonEnabled(false); 299 w.setClearButtonEnabled(true); 300 QSignalSpy spy(&w, &KLineEdit::clearButtonClicked); 301 QToolButton *tb = w.findChild<QToolButton *>(); 302 QTest::mouseClick(tb, Qt::LeftButton, Qt::NoModifier); 303 QCOMPARE(w.text(), QString()); 304 QCOMPARE(spy.count(), 1); 305 } 306 }; 307 308 QTEST_MAIN(KLineEdit_UnitTest) 309 310 #include "klineedit_unittest.moc" 311