1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28#include <QtTest/QtTest>
29#include <QMessageBox>
30#include <QDebug>
31#include <QPair>
32#include <QList>
33#include <QPointer>
34#include <QTimer>
35#include <QApplication>
36#include <QPushButton>
37#include <QDialogButtonBox>
38#include <qpa/qplatformtheme.h>
39#include <private/qguiapplication_p.h>
40
41class tst_QMessageBox : public QObject
42{
43 Q_OBJECT
44
45private slots:
46 void sanityTest();
47 void defaultButton();
48 void escapeButton();
49 void button();
50 void statics();
51 void about();
52 void detailsText();
53 void detailsButtonText();
54 void expandDetailsWithoutMoving();
55
56#ifndef Q_OS_MAC
57 void shortcut();
58#endif
59
60 void staticSourceCompat();
61 void instanceSourceCompat();
62
63 void incorrectDefaultButton();
64 void updateSize();
65
66 void setInformativeText();
67 void iconPixmap();
68
69 // QTBUG-44131
70 void acceptedRejectedSignals();
71 void acceptedRejectedSignals_data();
72
73 void cleanup();
74};
75
76class tst_ResizingMessageBox : public QMessageBox
77{
78public:
79 tst_ResizingMessageBox() : QMessageBox(), resized(false) { }
80 bool resized;
81
82protected:
83 void resizeEvent ( QResizeEvent * event ) {
84 resized = true;
85 QMessageBox::resizeEvent(event);
86 }
87};
88
89// ExecCloseHelper: Closes a modal QDialog during its exec() function by either
90// sending a key event or closing it (CloseWindow) once it becomes the active
91// modal window. Pass nullptr to "autodetect" the instance for static methods.
92class ExecCloseHelper : public QObject
93{
94public:
95 enum { CloseWindow = -1 };
96
97 explicit ExecCloseHelper(QObject *parent = nullptr)
98 : QObject(parent), m_key(0), m_timerId(0), m_testCandidate(nullptr) { }
99
100 void start(int key, QWidget *testCandidate = nullptr)
101 {
102 m_key = key;
103 m_testCandidate = testCandidate;
104 m_timerId = startTimer(interval: 50);
105 }
106
107 bool done() const { return !m_timerId; }
108
109protected:
110 void timerEvent(QTimerEvent *te) override;
111
112private:
113 int m_key;
114 int m_timerId;
115 QWidget *m_testCandidate;
116};
117
118void ExecCloseHelper::timerEvent(QTimerEvent *te)
119{
120 if (te->timerId() != m_timerId)
121 return;
122
123 QWidget *modalWidget = QApplication::activeModalWidget();
124
125 if (!m_testCandidate && modalWidget)
126 m_testCandidate = modalWidget;
127
128 if (m_testCandidate && m_testCandidate == modalWidget) {
129 if (m_key == CloseWindow) {
130 m_testCandidate->close();
131 } else {
132 QKeyEvent *ke = new QKeyEvent(QEvent::KeyPress, m_key, Qt::NoModifier);
133 QCoreApplication::postEvent(receiver: m_testCandidate, event: ke);
134 }
135 m_testCandidate = nullptr;
136 killTimer(id: m_timerId);
137 m_timerId = m_key = 0;
138 }
139}
140
141void tst_QMessageBox::cleanup()
142{
143 QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); // OS X requires TRY
144}
145
146void tst_QMessageBox::sanityTest()
147{
148#if defined(Q_OS_MACOS)
149 if (QSysInfo::productVersion() == QLatin1String("10.12")) {
150 QSKIP("Test hangs on macOS 10.12 -- QTQAINFRA-1362");
151 return;
152 }
153#elif defined(Q_OS_WINRT)
154 QSKIP("Test hangs on winrt -- QTBUG-68297");
155#endif
156 QMessageBox msgBox;
157 msgBox.setText("This is insane");
158 for (int i = 0; i < 10; i++)
159 msgBox.setIcon(QMessageBox::Icon(i));
160 msgBox.setIconPixmap(QPixmap());
161 msgBox.setIconPixmap(QPixmap("whatever.png"));
162 msgBox.setTextFormat(Qt::RichText);
163 msgBox.setTextFormat(Qt::PlainText);
164 ExecCloseHelper closeHelper;
165 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox);
166 msgBox.exec();
167}
168
169void tst_QMessageBox::button()
170{
171 QMessageBox msgBox;
172 msgBox.addButton(text: "retry", role: QMessageBox::DestructiveRole);
173 QVERIFY(msgBox.button(QMessageBox::Ok) == nullptr); // not added yet
174 QPushButton *b1 = msgBox.addButton(button: QMessageBox::Ok);
175 QCOMPARE(msgBox.button(QMessageBox::Ok), static_cast<QAbstractButton *>(b1)); // just added
176 QCOMPARE(msgBox.standardButton(b1), QMessageBox::Ok);
177 msgBox.addButton(button: QMessageBox::Cancel);
178 QCOMPARE(msgBox.standardButtons(), QMessageBox::Ok | QMessageBox::Cancel);
179
180 // remove the cancel, should not exist anymore
181 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
182 QVERIFY(!msgBox.button(QMessageBox::Cancel));
183 QVERIFY(msgBox.button(QMessageBox::Yes) != nullptr);
184
185 // should not crash
186 QPushButton *b4 = new QPushButton;
187 msgBox.addButton(button: b4, role: QMessageBox::DestructiveRole);
188 msgBox.addButton(button: nullptr, role: QMessageBox::ActionRole);
189}
190
191void tst_QMessageBox::defaultButton()
192{
193 QMessageBox msgBox;
194 QVERIFY(!msgBox.defaultButton());
195 msgBox.addButton(button: QMessageBox::Ok);
196 msgBox.addButton(button: QMessageBox::Cancel);
197 QVERIFY(!msgBox.defaultButton());
198 QPushButton pushButton;
199 msgBox.setDefaultButton(&pushButton);
200 QVERIFY(msgBox.defaultButton() == nullptr); // we have not added it yet
201 QPushButton *retryButton = msgBox.addButton(button: QMessageBox::Retry);
202 msgBox.setDefaultButton(retryButton);
203 QCOMPARE(msgBox.defaultButton(), retryButton);
204 ExecCloseHelper closeHelper;
205 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox);
206 msgBox.exec();
207 QCOMPARE(msgBox.clickedButton(), msgBox.button(QMessageBox::Cancel));
208
209 closeHelper.start(key: Qt::Key_Enter, testCandidate: &msgBox);
210 msgBox.exec();
211 QCOMPARE(msgBox.clickedButton(), static_cast<QAbstractButton *>(retryButton));
212
213 QAbstractButton *okButton = msgBox.button(which: QMessageBox::Ok);
214 msgBox.setDefaultButton(QMessageBox::Ok);
215 QCOMPARE(msgBox.defaultButton(), static_cast<QPushButton *>(okButton));
216 closeHelper.start(key: Qt::Key_Enter, testCandidate: &msgBox);
217 msgBox.exec();
218 QCOMPARE(msgBox.clickedButton(), okButton);
219 msgBox.setDefaultButton(QMessageBox::Yes); // its not in there!
220 QCOMPARE(msgBox.defaultButton(), okButton);
221 msgBox.removeButton(button: okButton);
222 delete okButton;
223 okButton = nullptr;
224 QVERIFY(!msgBox.defaultButton());
225 msgBox.setDefaultButton(QMessageBox::Ok);
226 QVERIFY(!msgBox.defaultButton());
227}
228
229void tst_QMessageBox::escapeButton()
230{
231 QMessageBox msgBox;
232 QVERIFY(!msgBox.escapeButton());
233 msgBox.addButton(button: QMessageBox::Ok);
234 ExecCloseHelper closeHelper;
235 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox);
236 msgBox.exec();
237 QVERIFY(msgBox.clickedButton() == msgBox.button(QMessageBox::Ok)); // auto detected (one button only)
238 msgBox.addButton(button: QMessageBox::Cancel);
239 QVERIFY(!msgBox.escapeButton());
240 QPushButton invalidButton;
241 msgBox.setEscapeButton(&invalidButton);
242 QVERIFY(!msgBox.escapeButton());
243 QAbstractButton *retryButton = msgBox.addButton(button: QMessageBox::Retry);
244
245 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox);
246 msgBox.exec();
247 QVERIFY(msgBox.clickedButton() == msgBox.button(QMessageBox::Cancel)); // auto detected (cancel)
248
249 msgBox.setEscapeButton(retryButton);
250 QCOMPARE(msgBox.escapeButton(), static_cast<QAbstractButton *>(retryButton));
251
252 // with escape
253 closeHelper.start(key: Qt::Key_Escape, testCandidate: &msgBox);
254 msgBox.exec();
255 QCOMPARE(msgBox.clickedButton(), retryButton);
256
257 // with close
258 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox);
259 msgBox.exec();
260 QCOMPARE(msgBox.clickedButton(), static_cast<QAbstractButton *>(retryButton));
261
262 QAbstractButton *okButton = msgBox.button(which: QMessageBox::Ok);
263 msgBox.setEscapeButton(QMessageBox::Ok);
264 QCOMPARE(msgBox.escapeButton(), okButton);
265 closeHelper.start(key: Qt::Key_Escape, testCandidate: &msgBox);
266 msgBox.exec();
267 QCOMPARE(msgBox.clickedButton(), okButton);
268 msgBox.setEscapeButton(QMessageBox::Yes); // its not in there!
269 QCOMPARE(msgBox.escapeButton(), okButton);
270 msgBox.removeButton(button: okButton);
271 delete okButton;
272 okButton = nullptr;
273 QVERIFY(!msgBox.escapeButton());
274 msgBox.setEscapeButton(QMessageBox::Ok);
275 QVERIFY(!msgBox.escapeButton());
276
277 QMessageBox msgBox2;
278 msgBox2.addButton(button: QMessageBox::Yes);
279 msgBox2.addButton(button: QMessageBox::No);
280 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2);
281 msgBox2.exec();
282 QVERIFY(msgBox2.clickedButton() == msgBox2.button(QMessageBox::No)); // auto detected (one No button only)
283
284 QPushButton *rejectButton = new QPushButton;
285 msgBox2.addButton(button: rejectButton, role: QMessageBox::RejectRole);
286 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2);
287 msgBox2.exec();
288 QVERIFY(msgBox2.clickedButton() == rejectButton); // auto detected (one reject button only)
289
290 msgBox2.addButton(button: new QPushButton, role: QMessageBox::RejectRole);
291 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2);
292 msgBox2.exec();
293 QVERIFY(msgBox2.clickedButton() == msgBox2.button(QMessageBox::No)); // auto detected (one No button only)
294
295 QMessageBox msgBox3;
296 msgBox3.setDetailedText("Details");
297 closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox3);
298 msgBox3.exec();
299 QVERIFY(msgBox3.clickedButton() == msgBox3.button(QMessageBox::Ok)); // auto detected
300}
301
302void tst_QMessageBox::statics()
303{
304 QMessageBox::StandardButton (*statics[4])(QWidget *, const QString &,
305 const QString&, QMessageBox::StandardButtons buttons,
306 QMessageBox::StandardButton);
307
308 statics[0] = QMessageBox::information;
309 statics[1] = QMessageBox::critical;
310 statics[2] = QMessageBox::question;
311 statics[3] = QMessageBox::warning;
312
313 ExecCloseHelper closeHelper;
314 for (int i = 0; i < 4; i++) {
315 closeHelper.start(key: Qt::Key_Escape);
316 QMessageBox::StandardButton sb = (*statics[i])(nullptr, "caption",
317 "text", QMessageBox::Yes | QMessageBox::No | QMessageBox::Help | QMessageBox::Cancel,
318 QMessageBox::NoButton);
319 QCOMPARE(sb, QMessageBox::Cancel);
320 QVERIFY(closeHelper.done());
321
322 closeHelper.start(key: ExecCloseHelper::CloseWindow);
323 sb = (*statics[i])(nullptr, "caption",
324 "text", QMessageBox::Yes | QMessageBox::No | QMessageBox::Help | QMessageBox::Cancel,
325 QMessageBox::NoButton);
326 QCOMPARE(sb, QMessageBox::Cancel);
327 QVERIFY(closeHelper.done());
328
329 closeHelper.start(key: Qt::Key_Enter);
330 sb = (*statics[i])(nullptr, "caption",
331 "text", QMessageBox::Yes | QMessageBox::No | QMessageBox::Help,
332 QMessageBox::Yes);
333 QCOMPARE(sb, QMessageBox::Yes);
334 QVERIFY(closeHelper.done());
335
336 closeHelper.start(key: Qt::Key_Enter);
337 sb = (*statics[i])(nullptr, "caption",
338 "text", QMessageBox::Yes | QMessageBox::No | QMessageBox::Help,
339 QMessageBox::No);
340 QCOMPARE(sb, QMessageBox::No);
341 QVERIFY(closeHelper.done());
342 }
343}
344
345// shortcuts are not used on OS X
346#ifndef Q_OS_MAC
347void tst_QMessageBox::shortcut()
348{
349 QMessageBox msgBox;
350 msgBox.addButton(text: "O&k", role: QMessageBox::YesRole);
351 msgBox.addButton(text: "&No", role: QMessageBox::YesRole);
352 msgBox.addButton(text: "&Maybe", role: QMessageBox::YesRole);
353 ExecCloseHelper closeHelper;
354 closeHelper.start(key: Qt::Key_M, testCandidate: &msgBox);
355 QCOMPARE(msgBox.exec(), 2);
356}
357#endif
358
359void tst_QMessageBox::about()
360{
361 ExecCloseHelper closeHelper;
362 closeHelper.start(key: Qt::Key_Escape);
363 QMessageBox::about(parent: nullptr, title: "Caption", text: "This is an auto test");
364 // On Mac, about and aboutQt are not modal, so we need to
365 // explicitly run the event loop
366#ifdef Q_OS_MAC
367 QTRY_VERIFY(closeHelper.done());
368#else
369 QVERIFY(closeHelper.done());
370#endif
371
372 const int keyToSend = Qt::Key_Enter;
373
374 closeHelper.start(key: keyToSend);
375 QMessageBox::aboutQt(parent: nullptr, title: "Caption");
376#ifdef Q_OS_MAC
377 QTRY_VERIFY(closeHelper.done());
378#else
379 QVERIFY(closeHelper.done());
380#endif
381}
382
383void tst_QMessageBox::staticSourceCompat()
384{
385 int ret;
386
387 // source compat tests for < 4.2
388 ExecCloseHelper closeHelper;
389 closeHelper.start(key: Qt::Key_Enter);
390 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0: QMessageBox::Yes, button1: QMessageBox::No);
391 int expectedButton = int(QMessageBox::Yes);
392 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
393 const int dialogButtonBoxLayout = theme->themeHint(hint: QPlatformTheme::DialogButtonBoxLayout).toInt();
394 if (dialogButtonBoxLayout == QDialogButtonBox::MacLayout
395 || dialogButtonBoxLayout == QDialogButtonBox::GnomeLayout)
396 expectedButton = int(QMessageBox::No);
397 }
398 QCOMPARE(ret, expectedButton);
399 QVERIFY(closeHelper.done());
400
401 closeHelper.start(key: Qt::Key_Enter);
402 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", buttons: QMessageBox::Yes | QMessageBox::Default, defaultButton: QMessageBox::No);
403 QCOMPARE(ret, int(QMessageBox::Yes));
404 QVERIFY(closeHelper.done());
405
406 closeHelper.start(key: Qt::Key_Enter);
407 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0: QMessageBox::Yes, button1: QMessageBox::No | QMessageBox::Default);
408 QCOMPARE(ret, int(QMessageBox::No));
409 QVERIFY(closeHelper.done());
410
411 closeHelper.start(key: Qt::Key_Enter);
412 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0: QMessageBox::Yes | QMessageBox::Default, button1: QMessageBox::No | QMessageBox::Escape);
413 QCOMPARE(ret, int(QMessageBox::Yes));
414 QVERIFY(closeHelper.done());
415
416 closeHelper.start(key: Qt::Key_Enter);
417 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0: QMessageBox::Yes | QMessageBox::Escape, button1: QMessageBox::No | QMessageBox::Default);
418 QCOMPARE(ret, int(QMessageBox::No));
419 QVERIFY(closeHelper.done());
420
421 // the button text versions
422 closeHelper.start(key: Qt::Key_Enter);
423 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0Text: "Yes", button1Text: "No", button2Text: QString(), defaultButtonNumber: 1);
424 QCOMPARE(ret, 1);
425 QVERIFY(closeHelper.done());
426
427 if (0) { // don't run these tests since the dialog won't close!
428 closeHelper.start(key: Qt::Key_Escape);
429 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0Text: "Yes", button1Text: "No", button2Text: QString(), defaultButtonNumber: 1);
430 QCOMPARE(ret, -1);
431 QVERIFY(closeHelper.done());
432
433 closeHelper.start(key: Qt::Key_Escape);
434 ret = QMessageBox::information(parent: nullptr, title: "title", text: "text", button0Text: "Yes", button1Text: "No", button2Text: QString(), defaultButtonNumber: 0, escapeButtonNumber: 1);
435 QCOMPARE(ret, 1);
436 QVERIFY(closeHelper.done());
437 }
438}
439
440void tst_QMessageBox::instanceSourceCompat()
441{
442 QMessageBox mb("Application name here",
443 "Saving the file will overwrite the original file on the disk.\n"
444 "Do you really want to save?",
445 QMessageBox::Information,
446 QMessageBox::Yes | QMessageBox::Default,
447 QMessageBox::No,
448 QMessageBox::Cancel | QMessageBox::Escape);
449 mb.setButtonText(button: QMessageBox::Yes, text: "Save");
450 mb.setButtonText(button: QMessageBox::No, text: "Discard");
451 mb.addButton(text: "&Revert", role: QMessageBox::RejectRole);
452 mb.addButton(text: "&Zoo", role: QMessageBox::ActionRole);
453
454 ExecCloseHelper closeHelper;
455 closeHelper.start(key: Qt::Key_Enter, testCandidate: &mb);
456 QCOMPARE(mb.exec(), int(QMessageBox::Yes));
457 closeHelper.start(key: Qt::Key_Escape, testCandidate: &mb);
458 QCOMPARE(mb.exec(), int(QMessageBox::Cancel));
459#ifndef Q_OS_MAC
460 // mnemonics are not used on OS X
461 closeHelper.start(key: Qt::ALT + Qt::Key_R, testCandidate: &mb);
462 QCOMPARE(mb.exec(), 0);
463 closeHelper.start(key: Qt::ALT + Qt::Key_Z, testCandidate: &mb);
464 QCOMPARE(mb.exec(), 1);
465#endif
466}
467
468void tst_QMessageBox::detailsText()
469{
470 QMessageBox box;
471 QString text("This is the details text.");
472 box.setDetailedText(text);
473 QCOMPARE(box.detailedText(), text);
474 box.show();
475 QVERIFY(QTest::qWaitForWindowExposed(&box));
476 // QTBUG-39334, the box should now have the default "Ok" button as well as
477 // the "Show Details.." button.
478 QCOMPARE(box.findChildren<QAbstractButton *>().size(), 2);
479}
480
481void tst_QMessageBox::detailsButtonText()
482{
483 QMessageBox box;
484 box.setDetailedText("bla");
485 box.open();
486 QApplication::postEvent(receiver: &box, event: new QEvent(QEvent::LanguageChange));
487 QApplication::processEvents();
488 QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>(aName: "qt_msgbox_buttonbox");
489 QVERIFY(bb); //get the detail button
490
491 auto list = bb->buttons();
492 for (auto btn : list) {
493 if (btn && (btn->inherits(classname: "QPushButton"))) {
494 if (btn->text().remove(c: QLatin1Char('&')) != QMessageBox::tr(s: "OK")
495 && btn->text() != QMessageBox::tr(s: "Show Details...")) {
496 QFAIL(qPrintable(QString("Unexpected messagebox button text: %1").arg(btn->text())));
497 }
498 }
499 }
500}
501
502void tst_QMessageBox::expandDetailsWithoutMoving() // QTBUG-32473
503{
504 tst_ResizingMessageBox box;
505 box.setDetailedText("bla");
506 box.show();
507 QApplication::postEvent(receiver: &box, event: new QEvent(QEvent::LanguageChange));
508 QApplication::processEvents();
509 QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>(aName: "qt_msgbox_buttonbox");
510 QVERIFY(bb);
511
512 auto list = bb->buttons();
513 auto it = std::find_if(first: list.rbegin(), last: list.rend(), pred: [&](QAbstractButton *btn) {
514 return btn && bb->buttonRole(button: btn) == QDialogButtonBox::ActionRole; });
515 QVERIFY(it != list.rend());
516 auto moreButton = *it;
517
518 QVERIFY(QTest::qWaitForWindowExposed(&box));
519 QTRY_VERIFY2(!box.geometry().topLeft().isNull(), "window manager is expected to decorate and position the dialog");
520 QRect geom = box.geometry();
521 box.resized = false;
522 // now click the "more" button, and verify that the dialog resizes but does not move
523 moreButton->click();
524 QTRY_VERIFY(box.resized);
525 QVERIFY(box.geometry().height() > geom.height());
526 QCOMPARE(box.geometry().topLeft(), geom.topLeft());
527}
528
529void tst_QMessageBox::incorrectDefaultButton()
530{
531 ExecCloseHelper closeHelper;
532 closeHelper.start(key: Qt::Key_Escape);
533 //Do not crash here
534 QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
535 QMessageBox::question(parent: nullptr, title: "", text: "I've been hit!",buttons: QMessageBox::Ok | QMessageBox::Cancel,defaultButton: QMessageBox::Save);
536 QVERIFY(closeHelper.done());
537
538 closeHelper.start(key: Qt::Key_Escape);
539 QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
540 QMessageBox::question(parent: nullptr, title: "", text: "I've been hit!",buttons: QFlag(QMessageBox::Ok | QMessageBox::Cancel),defaultButton: QMessageBox::Save);
541 QVERIFY(closeHelper.done());
542
543 closeHelper.start(key: Qt::Key_Escape);
544 QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
545 QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
546 //do not crash here -> call old function of QMessageBox in this case
547 QMessageBox::question(parent: nullptr, title: "", text: "I've been hit!",button0: QMessageBox::Ok | QMessageBox::Cancel,button1: QMessageBox::Save | QMessageBox::Cancel,button2: QMessageBox::Ok);
548 QVERIFY(closeHelper.done());
549}
550
551void tst_QMessageBox::updateSize()
552{
553 QMessageBox box;
554 box.setText("This is awesome");
555 box.show();
556 QSize oldSize = box.size();
557 QString longText;
558 for (int i = 0; i < 20; i++)
559 longText += box.text();
560 box.setText(longText);
561 QVERIFY(box.size() != oldSize); // should have grown
562 QVERIFY(box.width() > oldSize.width() || box.height() > oldSize.height());
563 oldSize = box.size();
564 box.setStandardButtons(QMessageBox::StandardButtons(0xFFFF));
565 QVERIFY(box.size() != oldSize); // should have grown
566 QVERIFY(box.width() > oldSize.width() || box.height() > oldSize.height());
567}
568
569void tst_QMessageBox::setInformativeText()
570{
571 QMessageBox msgbox(QMessageBox::Warning, "", "", QMessageBox::Ok);
572 QString itext = "This is a very long message and it should make the dialog have enough width to fit this message in";
573 msgbox.setInformativeText(itext);
574 msgbox.show();
575 QCOMPARE(msgbox.informativeText(), itext);
576 QVERIFY2(msgbox.width() > 190, //verify it's big enough (task181688)
577 qPrintable(QString("%1 > 190").arg(msgbox.width())));
578}
579
580void tst_QMessageBox::iconPixmap()
581{
582 QMessageBox messageBox;
583 QCOMPARE(messageBox.iconPixmap(), QPixmap());
584}
585
586using SignalSignature = void(QDialog::*)();
587Q_DECLARE_METATYPE(SignalSignature);
588Q_DECLARE_METATYPE(QMessageBox::ButtonRole)
589
590using ButtonsCreator = std::function<QVector<QPushButton*>(QMessageBox &)>;
591Q_DECLARE_METATYPE(ButtonsCreator);
592
593using RoleSet = QSet<QMessageBox::ButtonRole>;
594Q_DECLARE_METATYPE(RoleSet);
595
596void tst_QMessageBox::acceptedRejectedSignals()
597{
598 QMessageBox messageBox(QMessageBox::Information, "Test window", "Test text");
599
600 QFETCH(ButtonsCreator, buttonsCreator);
601 QVERIFY(buttonsCreator);
602
603 const auto buttons = buttonsCreator(messageBox);
604 QVERIFY(!buttons.isEmpty());
605
606 QFETCH(RoleSet, roles);
607 QFETCH(SignalSignature, signalSignature);
608 for (auto button: buttons) {
609 QVERIFY(button);
610
611 messageBox.show();
612 QVERIFY(QTest::qWaitForWindowExposed(&messageBox));
613
614 QSignalSpy spy(&messageBox, signalSignature);
615 QVERIFY(spy.isValid());
616 button->click();
617
618 if (roles.contains(value: messageBox.buttonRole(button)))
619 QCOMPARE(spy.count(), 1);
620 else
621 QVERIFY(spy.isEmpty());
622 }
623}
624
625static void addAcceptedRow(const char *title, ButtonsCreator bc)
626{
627 QTest::newRow(dataTag: title) << (RoleSet() << QMessageBox::AcceptRole << QMessageBox::YesRole)
628 << &QDialog::accepted << bc;
629}
630
631static void addRejectedRow(const char *title, ButtonsCreator bc)
632{
633 QTest::newRow(dataTag: title) << (RoleSet() << QMessageBox::RejectRole << QMessageBox::NoRole)
634 << &QDialog::rejected << bc;
635}
636
637static void addCustomButtonsData()
638{
639 ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) {
640 QVector<QPushButton*> buttons(QMessageBox::NRoles);
641 for (int i = QMessageBox::AcceptRole; i < QMessageBox::NRoles; ++i) {
642 buttons[i] = messageBox.addButton(
643 text: QString("Button role: %1").arg(a: i), role: QMessageBox::ButtonRole(i));
644 }
645
646 return buttons;
647 };
648
649 addAcceptedRow(title: "Accepted_CustomButtons", bc: buttonsCreator);
650 addRejectedRow(title: "Rejected_CustomButtons", bc: buttonsCreator);
651}
652
653static void addStandardButtonsData()
654{
655 ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) {
656 QVector<QPushButton*> buttons;
657 for (int i = QMessageBox::FirstButton; i <= QMessageBox::LastButton; i <<= 1)
658 buttons << messageBox.addButton(button: QMessageBox::StandardButton(i));
659
660 return buttons;
661 };
662
663 addAcceptedRow(title: "Accepted_StandardButtons", bc: buttonsCreator);
664 addRejectedRow(title: "Rejected_StandardButtons", bc: buttonsCreator);
665}
666
667void tst_QMessageBox::acceptedRejectedSignals_data()
668{
669 QTest::addColumn<RoleSet>(name: "roles");
670 QTest::addColumn<SignalSignature>(name: "signalSignature");
671 QTest::addColumn<ButtonsCreator>(name: "buttonsCreator");
672
673 addStandardButtonsData();
674 addCustomButtonsData();
675}
676
677QTEST_MAIN(tst_QMessageBox)
678#include "tst_qmessagebox.moc"
679

source code of qtbase/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp