1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include <QString>
45 #include <QSpinBox>
46 #include <QPushButton>
47 #include <QLineEdit>
48 #include <QComboBox>
49 #include <QDialogButtonBox>
50 #include <qinputdialog.h>
51
52 //TESTED_CLASS=
53 //TESTED_FILES=
54
55 class tst_QInputDialog : public QObject
56 {
57 Q_OBJECT
58 QWidget *parent;
59 QDialog::DialogCode doneCode;
60 void (*testFunc)(QInputDialog *);
61 static void testFuncGetInteger(QInputDialog *dialog);
62 static void testFuncGetDouble(QInputDialog *dialog);
63 static void testFuncGetText(QInputDialog *dialog);
64 static void testFuncGetItem(QInputDialog *dialog);
65 void timerEvent(QTimerEvent *event);
66 private slots:
67 void getInteger_data();
68 void getInteger();
69 void getDouble_data();
70 void getDouble();
71 void task255502getDouble();
72 void getText_data();
73 void getText();
74 void getItem_data();
75 void getItem();
76 void task256299_getTextReturnNullStringOnRejected();
77 void inputMethodHintsOfChildWidget();
78 };
79
stripFraction(const QString & s)80 QString stripFraction(const QString &s)
81 {
82 int period;
83 if (s.contains('.'))
84 period = s.indexOf('.');
85 else if (s.contains(','))
86 period = s.indexOf(',');
87 else
88 return s;
89 int end;
90 for (end = s.size() - 1; end > period && s[end] == '0'; --end) ;
91 return s.left(end + (end == period ? 0 : 1));
92 }
93
normalizeNumericString(const QString & s)94 QString normalizeNumericString(const QString &s)
95 {
96 return stripFraction(s); // assumed to be sufficient
97 }
98
_keyClick(QWidget * widget,char key)99 void _keyClick(QWidget *widget, char key)
100 {
101 QTest::keyClick(widget, key);
102 }
103
_keyClick(QWidget * widget,Qt::Key key)104 void _keyClick(QWidget *widget, Qt::Key key)
105 {
106 QTest::keyClick(widget, key);
107 }
108
109 template <typename SpinBoxType>
testTypingValue(SpinBoxType * sbox,QPushButton * okButton,const QString & value)110 void testTypingValue(
111 SpinBoxType* sbox, QPushButton *okButton, const QString &value)
112 {
113 sbox->selectAll();
114 for (int i = 0; i < value.size(); ++i) {
115 const QChar valChar = value[i];
116 _keyClick(static_cast<QWidget *>(sbox), valChar.toAscii()); // ### always guaranteed to work?
117 if (sbox->hasAcceptableInput())
118 QVERIFY(okButton->isEnabled());
119 else
120 QVERIFY(!okButton->isEnabled());
121 }
122 }
123
testTypingValue(QLineEdit * ledit,QPushButton * okButton,const QString & value)124 void testTypingValue(QLineEdit *ledit, QPushButton *okButton, const QString &value)
125 {
126 ledit->selectAll();
127 for (int i = 0; i < value.size(); ++i) {
128 const QChar valChar = value[i];
129 _keyClick(ledit, valChar.toAscii()); // ### always guaranteed to work?
130 QVERIFY(ledit->hasAcceptableInput());
131 QVERIFY(okButton->isEnabled());
132 }
133 }
134
135 template <typename SpinBoxType, typename ValueType>
testInvalidateAndRestore(SpinBoxType * sbox,QPushButton * okButton,QLineEdit * ledit,ValueType * =0)136 void testInvalidateAndRestore(
137 SpinBoxType* sbox, QPushButton *okButton, QLineEdit *ledit, ValueType * = 0)
138 {
139 const ValueType lastValidValue = sbox->value();
140
141 sbox->selectAll();
142 _keyClick(ledit, Qt::Key_Delete);
143 QVERIFY(!sbox->hasAcceptableInput());
144 QVERIFY(!okButton->isEnabled());
145
146 _keyClick(ledit, Qt::Key_Return); // should work with Qt::Key_Enter too
147 QVERIFY(sbox->hasAcceptableInput());
148 QVERIFY(okButton->isEnabled());
149 QCOMPARE(sbox->value(), lastValidValue);
150 QLocale loc;
151 QCOMPARE(
152 normalizeNumericString(ledit->text()),
153 normalizeNumericString(loc.toString(sbox->value())));
154 }
155
156 template <typename SpinBoxType, typename ValueType>
testGetNumeric(QInputDialog * dialog,SpinBoxType * =0,ValueType * =0)157 void testGetNumeric(QInputDialog *dialog, SpinBoxType * = 0, ValueType * = 0)
158 {
159 SpinBoxType *sbox = qFindChild<SpinBoxType *>(dialog);
160 QVERIFY(sbox != 0);
161
162 QLineEdit *ledit = qFindChild<QLineEdit *>(static_cast<QObject *>(sbox));
163 QVERIFY(ledit != 0);
164
165 QDialogButtonBox *bbox = qFindChild<QDialogButtonBox *>(dialog);
166 QVERIFY(bbox != 0);
167 QPushButton *okButton = bbox->button(QDialogButtonBox::Ok);
168 QVERIFY(okButton != 0);
169
170 QVERIFY(sbox->value() >= sbox->minimum());
171 QVERIFY(sbox->value() <= sbox->maximum());
172 QVERIFY(sbox->hasAcceptableInput());
173 QLocale loc;
174 QCOMPARE(
175 normalizeNumericString(ledit->selectedText()),
176 normalizeNumericString(loc.toString(sbox->value())));
177 QVERIFY(okButton->isEnabled());
178
179 const ValueType origValue = sbox->value();
180
181 testInvalidateAndRestore<SpinBoxType, ValueType>(sbox, okButton, ledit);
182 testTypingValue<SpinBoxType>(sbox, okButton, QString("%1").arg(sbox->minimum()));
183 testTypingValue<SpinBoxType>(sbox, okButton, QString("%1").arg(sbox->maximum()));
184 testTypingValue<SpinBoxType>(sbox, okButton, QString("%1").arg(sbox->minimum() - 1));
185 testTypingValue<SpinBoxType>(sbox, okButton, QString("%1").arg(sbox->maximum() + 1));
186 testTypingValue<SpinBoxType>(sbox, okButton, "0");
187 testTypingValue<SpinBoxType>(sbox, okButton, "0.0");
188 testTypingValue<SpinBoxType>(sbox, okButton, "foobar");
189
190 testTypingValue<SpinBoxType>(sbox, okButton, loc.toString(origValue));
191 }
192
testGetText(QInputDialog * dialog)193 void testGetText(QInputDialog *dialog)
194 {
195 QLineEdit *ledit = qFindChild<QLineEdit *>(dialog);
196 QVERIFY(ledit);
197
198 QDialogButtonBox *bbox = qFindChild<QDialogButtonBox *>(dialog);
199 QVERIFY(bbox);
200 QPushButton *okButton = bbox->button(QDialogButtonBox::Ok);
201 QVERIFY(okButton);
202
203 QVERIFY(ledit->hasAcceptableInput());
204 QCOMPARE(ledit->selectedText(), ledit->text());
205 QVERIFY(okButton->isEnabled());
206 const QString origValue = ledit->text();
207
208 testTypingValue(ledit, okButton, origValue);
209 }
210
testGetItem(QInputDialog * dialog)211 void testGetItem(QInputDialog *dialog)
212 {
213 QComboBox *cbox = qFindChild<QComboBox *>(dialog);
214 QVERIFY(cbox);
215
216 QDialogButtonBox *bbox = qFindChild<QDialogButtonBox *>(dialog);
217 QVERIFY(bbox);
218 QPushButton *okButton = bbox->button(QDialogButtonBox::Ok);
219 QVERIFY(okButton);
220
221 QVERIFY(okButton->isEnabled());
222 const int origIndex = cbox->currentIndex();
223 cbox->setCurrentIndex(origIndex - 1);
224 cbox->setCurrentIndex(origIndex);
225 QVERIFY(okButton->isEnabled());
226 }
227
testFuncGetInteger(QInputDialog * dialog)228 void tst_QInputDialog::testFuncGetInteger(QInputDialog *dialog)
229 {
230 testGetNumeric<QSpinBox, int>(dialog);
231 }
232
testFuncGetDouble(QInputDialog * dialog)233 void tst_QInputDialog::testFuncGetDouble(QInputDialog *dialog)
234 {
235 testGetNumeric<QDoubleSpinBox, double>(dialog);
236 }
237
testFuncGetText(QInputDialog * dialog)238 void tst_QInputDialog::testFuncGetText(QInputDialog *dialog)
239 {
240 ::testGetText(dialog);
241 }
242
testFuncGetItem(QInputDialog * dialog)243 void tst_QInputDialog::testFuncGetItem(QInputDialog *dialog)
244 {
245 ::testGetItem(dialog);
246 }
247
timerEvent(QTimerEvent * event)248 void tst_QInputDialog::timerEvent(QTimerEvent *event)
249 {
250 killTimer(event->timerId());
251 QInputDialog *dialog = qFindChild<QInputDialog *>(parent);
252 QVERIFY(dialog);
253 if (testFunc)
254 testFunc(dialog);
255 dialog->done(doneCode); // cause static function call to return
256 }
257
getInteger_data()258 void tst_QInputDialog::getInteger_data()
259 {
260 QTest::addColumn<int>("min");
261 QTest::addColumn<int>("max");
262 QTest::newRow("getInteger() - -") << -20 << -10;
263 QTest::newRow("getInteger() - 0") << -20 << 0;
264 QTest::newRow("getInteger() - +") << -20 << 20;
265 QTest::newRow("getInteger() 0 +") << 0 << 20;
266 QTest::newRow("getInteger() + +") << 10 << 20;
267 }
268
getInteger()269 void tst_QInputDialog::getInteger()
270 {
271 QFETCH(int, min);
272 QFETCH(int, max);
273 QVERIFY(min < max);
274 parent = new QWidget;
275 doneCode = QDialog::Accepted;
276 testFunc = &tst_QInputDialog::testFuncGetInteger;
277 startTimer(0);
278 bool ok = false;
279 const int value = min + (max - min) / 2;
280 const int result = QInputDialog::getInteger(parent, "", "", value, min, max, 1, &ok);
281 QVERIFY(ok);
282 QCOMPARE(result, value);
283 delete parent;
284 }
285
getDouble_data()286 void tst_QInputDialog::getDouble_data()
287 {
288 QTest::addColumn<double>("min");
289 QTest::addColumn<double>("max");
290 QTest::addColumn<int>("decimals");
291 QTest::newRow("getDouble() - - d0") << -20.0 << -10.0 << 0;
292 QTest::newRow("getDouble() - 0 d0") << -20.0 << 0.0 << 0;
293 QTest::newRow("getDouble() - + d0") << -20.0 << 20.0 << 0;
294 QTest::newRow("getDouble() 0 + d0") << 0.0 << 20.0 << 0;
295 QTest::newRow("getDouble() + + d0") << 10.0 << 20.0 << 0;
296 QTest::newRow("getDouble() - - d1") << -20.5 << -10.5 << 1;
297 QTest::newRow("getDouble() - 0 d1") << -20.5 << 0.0 << 1;
298 QTest::newRow("getDouble() - + d1") << -20.5 << 20.5 << 1;
299 QTest::newRow("getDouble() 0 + d1") << 0.0 << 20.5 << 1;
300 QTest::newRow("getDouble() + + d1") << 10.5 << 20.5 << 1;
301 QTest::newRow("getDouble() - - d2") << -20.05 << -10.05 << 2;
302 QTest::newRow("getDouble() - 0 d2") << -20.05 << 0.0 << 2;
303 QTest::newRow("getDouble() - + d2") << -20.05 << 20.05 << 2;
304 QTest::newRow("getDouble() 0 + d2") << 0.0 << 20.05 << 2;
305 QTest::newRow("getDouble() + + d2") << 10.05 << 20.05 << 2;
306 }
307
getDouble()308 void tst_QInputDialog::getDouble()
309 {
310 QFETCH(double, min);
311 QFETCH(double, max);
312 QFETCH(int, decimals);
313 QVERIFY(min < max && decimals >= 0 && decimals <= 13);
314 parent = new QWidget;
315 doneCode = QDialog::Accepted;
316 testFunc = &tst_QInputDialog::testFuncGetDouble;
317 startTimer(0);
318 bool ok = false;
319 // avoid decimals due to inconsistent roundoff behavior in QInputDialog::getDouble()
320 // (at one decimal, 10.25 is rounded off to 10.2, while at two decimals, 10.025 is
321 // rounded off to 10.03)
322 const double value = static_cast<int>(min + (max - min) / 2);
323 const double result =
324 QInputDialog::getDouble(parent, "", "", value, min, max, decimals, &ok);
325 QVERIFY(ok);
326 QCOMPARE(result, value);
327 delete parent;
328 }
329
task255502getDouble()330 void tst_QInputDialog::task255502getDouble()
331 {
332 parent = new QWidget;
333 doneCode = QDialog::Accepted;
334 testFunc = &tst_QInputDialog::testFuncGetDouble;
335 startTimer(0);
336 bool ok = false;
337 const double value = 0.001;
338 const double result =
339 QInputDialog::getDouble(parent, "", "", value, -1, 1, 4, &ok);
340 QVERIFY(ok);
341 QCOMPARE(result, value);
342 delete parent;
343 }
344
getText_data()345 void tst_QInputDialog::getText_data()
346 {
347 QTest::addColumn<QString>("text");
348 QTest::newRow("getText() 1") << "";
349 QTest::newRow("getText() 2") << "foobar";
350 QTest::newRow("getText() 3") << " foobar";
351 QTest::newRow("getText() 4") << "foobar ";
352 QTest::newRow("getText() 5") << "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?";
353 }
354
getText()355 void tst_QInputDialog::getText()
356 {
357 QFETCH(QString, text);
358 parent = new QWidget;
359 doneCode = QDialog::Accepted;
360 testFunc = &tst_QInputDialog::testFuncGetText;
361 startTimer(0);
362 bool ok = false;
363 const QString result = QInputDialog::getText(parent, "", "", QLineEdit::Normal, text, &ok);
364 QVERIFY(ok);
365 QCOMPARE(result, text);
366 delete parent;
367 }
368
task256299_getTextReturnNullStringOnRejected()369 void tst_QInputDialog::task256299_getTextReturnNullStringOnRejected()
370 {
371 parent = new QWidget;
372 doneCode = QDialog::Rejected;
373 testFunc = 0;
374 startTimer(0);
375 bool ok = true;
376 const QString result = QInputDialog::getText(parent, "", "", QLineEdit::Normal, "foobar", &ok);
377 QVERIFY(!ok);
378 QVERIFY(result.isNull());
379 delete parent;
380 }
381
getItem_data()382 void tst_QInputDialog::getItem_data()
383 {
384 QTest::addColumn<QStringList>("items");
385 QTest::addColumn<bool>("editable");
386 QTest::newRow("getItem() 1 true") << (QStringList() << "") << true;
387 QTest::newRow("getItem() 2 true") <<
388 (QStringList() << "spring" << "summer" << "fall" << "winter") << true;
389 QTest::newRow("getItem() 1 false") << (QStringList() << "") << false;
390 QTest::newRow("getItem() 2 false") <<
391 (QStringList() << "spring" << "summer" << "fall" << "winter") << false;
392 }
393
getItem()394 void tst_QInputDialog::getItem()
395 {
396 QFETCH(QStringList, items);
397 QFETCH(bool, editable);
398 parent = new QWidget;
399 doneCode = QDialog::Accepted;
400 testFunc = &tst_QInputDialog::testFuncGetItem;
401 startTimer(0);
402 bool ok = false;
403 const int index = items.size() / 2;
404 const QString result = QInputDialog::getItem(parent, "", "", items, index, editable, &ok);
405 QVERIFY(ok);
406 QCOMPARE(result, items[index]);
407 delete parent;
408 }
409
inputMethodHintsOfChildWidget()410 void tst_QInputDialog::inputMethodHintsOfChildWidget()
411 {
412 QInputDialog dialog;
413 dialog.setInputMode(QInputDialog::TextInput);
414 QList<QObject *> children = dialog.children();
415 QLineEdit *editWidget = 0;
416 for (int c = 0; c < children.size(); c++) {
417 editWidget = qobject_cast<QLineEdit *>(children.at(c));
418 if (editWidget)
419 break;
420 }
421 QVERIFY(editWidget);
422 QCOMPARE(editWidget->inputMethodHints(), dialog.inputMethodHints());
423 QCOMPARE(editWidget->inputMethodHints(), Qt::ImhNone);
424 dialog.setInputMethodHints(Qt::ImhDigitsOnly);
425 QCOMPARE(editWidget->inputMethodHints(), dialog.inputMethodHints());
426 QCOMPARE(editWidget->inputMethodHints(), Qt::ImhDigitsOnly);
427 }
428
429 QTEST_MAIN(tst_QInputDialog)
430 #include "tst_qinputdialog.moc"
431