File indexing completed on 2024-12-01 12:40:33
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "ktooltiphelper_unittest.h" 0009 0010 #include <KToolTipHelper> 0011 0012 #include <QTest> 0013 0014 #include <QAction> 0015 #include <QApplication> 0016 #include <QFrame> 0017 #include <QHBoxLayout> 0018 #include <QLabel> 0019 #include <QMenu> 0020 #include <QStyle> 0021 #include <QToolButton> 0022 #include <QToolTip> 0023 #include <QWhatsThis> 0024 0025 #include <memory> 0026 0027 QString KToolTipHelper_UnitTest::shownToolTip(QWidget *widget) 0028 { 0029 QTest::mouseMove(m_frameWithoutToolTip); 0030 const bool resetWorked = QTest::qWaitFor( 0031 []() { 0032 return !QToolTip::isVisible(); 0033 }, 0034 3000); 0035 if (!resetWorked) { 0036 qWarning("The tooltip did not properly hide itself after moving to an area without tooltip."); 0037 } 0038 0039 QTest::mouseMove(widget); 0040 if (!QTest::qWaitFor(&QToolTip::isVisible, widget->style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay, nullptr, widget) + 1000)) { 0041 return QStringLiteral(""); 0042 } 0043 return QToolTip::text(); 0044 } 0045 0046 void KToolTipHelper_UnitTest::initTestCase() 0047 { 0048 m_window.reset(new QMainWindow()); 0049 m_centralWidget = new QWidget(m_window.get()); 0050 m_centralWidget->setGeometry(0, 0, 100, 100); 0051 m_window->setCentralWidget(m_centralWidget); 0052 0053 QHBoxLayout *layout = new QHBoxLayout(m_centralWidget); 0054 0055 m_frame = new QFrame(m_centralWidget); 0056 m_frame->setFrameStyle(3); 0057 new QLabel(QStringLiteral("test area"), m_frame); 0058 layout->addWidget(m_frame); 0059 0060 m_toolButton = new QToolButton(m_centralWidget); 0061 layout->addWidget(m_toolButton); 0062 0063 m_frameWithoutToolTip = new QFrame(m_centralWidget); 0064 m_frameWithoutToolTip->setFrameStyle(2); 0065 new QLabel(QStringLiteral("no tooltip"), m_frameWithoutToolTip); 0066 layout->addWidget(m_frameWithoutToolTip); 0067 0068 qApp->installEventFilter(KToolTipHelper::instance()); 0069 0070 m_window->show(); 0071 m_window->ensurePolished(); 0072 } 0073 0074 void KToolTipHelper_UnitTest::testGeneralWidget() 0075 { 0076 // tests without whatsThis() 0077 QVERIFY(shownToolTip(m_frameWithoutToolTip).isEmpty()); 0078 m_frame->setToolTip(QStringLiteral("frame's tooltip")); 0079 QCOMPARE(shownToolTip(m_frame), m_frame->toolTip()); 0080 0081 QHelpEvent *helpEvent = new QHelpEvent(QEvent::ToolTip, QPoint(1, 1), m_frame->mapToGlobal(QPoint(1, 1))); 0082 QVERIFY2(!KToolTipHelper::instance()->eventFilter(m_frame, helpEvent), 0083 "These most basic tooltips should not be filtered so applications can still rely" 0084 "on tooltip events in most cases."); 0085 0086 // tests with whatsThis() 0087 m_frame->setToolTip(QStringLiteral("")); 0088 m_frame->setWhatsThis(QStringLiteral("frame's whatsThis")); 0089 QVERIFY2(shownToolTip(m_frame).isEmpty(), "No whatsThisHint should be shown when no toolTip was set."); 0090 0091 m_frame->setToolTip(KToolTipHelper::whatsThisHintOnly()); 0092 QVERIFY2(shownToolTip(m_frame) != KToolTipHelper::whatsThisHintOnly(), 0093 "The KToolTipHelper::whatsThisHintOnly()-string is no user-facing string" 0094 "and should therefore never actually be displayed."); 0095 0096 // test when whatsThis() == toolTip() 0097 m_frame->setToolTip(QStringLiteral("frame's whatsThis")); 0098 const QString noWhatsThisToolTip = shownToolTip(m_frame); 0099 QVERIFY(noWhatsThisToolTip.contains(m_frame->toolTip())); 0100 QVERIFY2(noWhatsThisToolTip.length() == m_frame->toolTip().length(), "No whatsThisHint should be shown when the toolTip is a similar string."); 0101 0102 m_frame->setToolTip(QStringLiteral("frame's tooltip")); 0103 const QString toolTip = shownToolTip(m_frame); 0104 QVERIFY(toolTip.contains(m_frame->toolTip())); 0105 QVERIFY2(toolTip.length() > m_frame->toolTip().length(), "The frame's toolTip is supposed to contain the whatsThisHint."); 0106 0107 auto layout = new QVBoxLayout(m_frame); 0108 auto subFrame = std::unique_ptr<QFrame>(new QFrame(m_frame)); 0109 new QLabel(QStringLiteral("subFrame"), subFrame.get()); 0110 layout->addWidget(subFrame.get()); 0111 QCOMPARE(shownToolTip(subFrame.get()), toolTip); 0112 0113 subFrame->setToolTip(QStringLiteral("subFrame's tooltip")); 0114 QCOMPARE(shownToolTip(subFrame.get()), subFrame->toolTip()); 0115 } 0116 0117 void KToolTipHelper_UnitTest::testInvokingWhatsThis() 0118 { 0119 m_frame->setWhatsThis(QStringLiteral("frame's whatsThis")); 0120 m_frame->setToolTip(KToolTipHelper::whatsThisHintOnly()); 0121 shownToolTip(m_frame); 0122 QTest::keyClick(m_frame, Qt::Key_Shift); 0123 QVERIFY2(QTest::qWaitFor( 0124 []() { 0125 return !QToolTip::isVisible(); 0126 }, 0127 4000), 0128 "whatsThis should be shown now."); 0129 QVERIFY2(shownToolTip(m_frame).isEmpty(), 0130 "A toolTip was shown which shouldn't be possible because a WhatsThis widget" 0131 "should be displayed at this moment."); 0132 QWhatsThis::hideText(); 0133 QVERIFY2(!shownToolTip(m_frame).isEmpty(), 0134 "A toolTip was not shown although this should now be possible again " 0135 "because the WhatsThis widget was just hidden."); 0136 } 0137 0138 void KToolTipHelper_UnitTest::testQToolButton() 0139 { 0140 QVERIFY(shownToolTip(m_toolButton).isEmpty()); 0141 0142 auto action = std::unique_ptr<QAction>(new QAction(QStringLiteral("action"))); 0143 action->setToolTip(QStringLiteral("action's tooltip")); 0144 m_toolButton->setDefaultAction(action.get()); 0145 QCOMPARE(shownToolTip(m_toolButton), action->toolTip()); 0146 0147 auto helpEvent = std::unique_ptr<QHelpEvent>(new QHelpEvent(QEvent::ToolTip, QPoint(1, 1), m_toolButton->mapToGlobal(QPoint(1, 1)))); 0148 QVERIFY2(!KToolTipHelper::instance()->eventFilter(m_toolButton, helpEvent.get()), 0149 "These most basic tooltips should not be filtered so applications can still rely" 0150 "on tooltip events in most cases."); 0151 0152 action->setShortcut(Qt::CTRL | Qt::Key_K); 0153 const QString toolTip(shownToolTip(m_toolButton)); 0154 QVERIFY(toolTip.contains(action->toolTip())); 0155 // qDebug("%s > %s", qPrintable(toolTip), qPrintable(action->toolTip())); 0156 QVERIFY2(toolTip.length() > action->toolTip().length(), "The Keyboard shortcut should be visible."); 0157 0158 action->setWhatsThis(QStringLiteral("action's whatsThis")); 0159 const QString toolTipWithWhatsThisHint(shownToolTip(m_toolButton)); 0160 QVERIFY(toolTipWithWhatsThisHint.contains(toolTip)); 0161 // qDebug("%s > %s", qPrintable(toolTipWithWhatsThisHint), qPrintable(toolTip)); 0162 QVERIFY2(toolTipWithWhatsThisHint.length() > toolTip.length(), "The whatsThisHint should be visible."); 0163 0164 action->setShortcut(QKeySequence()); 0165 QVERIFY(shownToolTip(m_toolButton).length() < toolTipWithWhatsThisHint.length()); 0166 0167 action->setWhatsThis(QStringLiteral("")); 0168 QCOMPARE(shownToolTip(m_toolButton), action->toolTip()); 0169 0170 action->setToolTip(KToolTipHelper::whatsThisHintOnly()); 0171 QVERIFY2(shownToolTip(m_toolButton).isEmpty(), "It should not show the whatsThisHint if there is no whatsThis text."); 0172 0173 action->setWhatsThis(QStringLiteral("action's whatsThis")); 0174 QVERIFY2(!shownToolTip(m_toolButton).isEmpty(), "The whatsThisHint should be shown."); 0175 } 0176 0177 void KToolTipHelper_UnitTest::testQMenu() 0178 { 0179 auto menu = std::unique_ptr<QMenu>(new QMenu(m_centralWidget)); 0180 auto action = std::unique_ptr<QAction>(new QAction(QStringLiteral("action"))); 0181 action->setDisabled(true); // The tooltip should also be shown for disabled actions. 0182 menu->addAction(action.get()); 0183 menu->show(); 0184 QVERIFY(shownToolTip(menu.get()).isEmpty()); 0185 0186 action->setToolTip(QStringLiteral("action's tooltip")); 0187 const QString toolTip(shownToolTip(menu.get())); 0188 QCOMPARE(toolTip, action->toolTip()); 0189 action->setShortcut(Qt::CTRL | Qt::Key_K); 0190 QCOMPARE(shownToolTip(menu.get()), toolTip); 0191 0192 action->setWhatsThis(QStringLiteral("action's whatsThis")); 0193 const QString toolTipWithWhatsThisHint(shownToolTip(menu.get())); 0194 QVERIFY2(toolTipWithWhatsThisHint.length() > toolTip.length(), "The tooltip is supposed to contain a whatsThisHint."); 0195 0196 action->setToolTip(KToolTipHelper::whatsThisHintOnly()); 0197 QVERIFY(shownToolTip(menu.get()).length() < toolTipWithWhatsThisHint.length()); 0198 0199 action->setWhatsThis(QStringLiteral("")); 0200 QVERIFY(shownToolTip(menu.get()).isEmpty()); 0201 } 0202 0203 void KToolTipHelper_UnitTest::cleanupTestCase() 0204 { 0205 qApp->removeEventFilter(KToolTipHelper::instance()); 0206 } 0207 0208 QTEST_MAIN(KToolTipHelper_UnitTest) 0209 0210 #include "moc_ktooltiphelper_unittest.cpp"