File indexing completed on 2024-05-19 05:47:11

0001 /* This file is part of the KDE project
0002     Copyright 2010 David Faure <faure@kde.org>
0003     Copyright 2012 Dawit Alemayehu <adawit@kde.org>
0004 
0005    This program is free software; you can redistribute it and/or modify
0006    it under the terms of the GNU General Public License as published by
0007    the Free Software Foundation; either version 2 of the License or ( at
0008    your option ) version 3 or, at the discretion of KDE e.V. ( which shall
0009    act as a proxy as in section 14 of the GPLv3 ), any later version.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014    GNU General Public License for more details.
0015 
0016    You should have received a copy of the GNU General Public License
0017    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include <kpassworddialog.h>
0022 #include <QApplication>
0023 #include <kpasswdserver.h>
0024 #include <QTest>
0025 #include <QSignalSpy>
0026 
0027 static const char* sigQueryAuthInfoResult = SIGNAL(queryAuthInfoAsyncResult(qlonglong,qlonglong,KIO::AuthInfo));
0028 static const char* sigCheckAuthInfoResult = SIGNAL(checkAuthInfoAsyncResult(qlonglong,qlonglong,KIO::AuthInfo));
0029 
0030 // For the retry dialog (and only that one)
0031 static QDialogButtonBox::StandardButton s_buttonYes = QDialogButtonBox::Yes;
0032 static QDialogButtonBox::StandardButton s_buttonCancel = QDialogButtonBox::Cancel;
0033 
0034 Q_DECLARE_METATYPE(QDialogButtonBox::StandardButton)
0035 Q_DECLARE_METATYPE(QDialog::DialogCode)
0036 
0037 static QString getUserNameFrom(const KIO::AuthInfo& auth)
0038 {
0039     if (auth.username.isEmpty() && !auth.url.userName().isEmpty()) {
0040         return auth.url.userName();
0041     }
0042 
0043     return auth.username;
0044 }
0045 
0046 class KPasswdServerTest : public QObject
0047 {
0048     Q_OBJECT
0049 
0050 private Q_SLOTS:
0051     void initTestCase()
0052     {
0053         qRegisterMetaType<QDialogButtonBox::StandardButton>();
0054         qRegisterMetaType<QDialog::DialogCode>();
0055     }
0056 
0057     void simpleTest()
0058     {
0059         KPasswdServer server(this);
0060         server.setWalletDisabled(true);
0061 
0062         // Check that processRequest doesn't crash when it has nothing to do
0063         server.processRequest();
0064 
0065         KIO::AuthInfo info;
0066         info.url = QUrl(QStringLiteral("http://www.example.com"));
0067 
0068         // Make a check for that host, should say "not found"
0069         QVERIFY(noCheckAuth(server, info));
0070 
0071         // Now add auth to the cache
0072         const qlonglong windowId = 42;
0073         KIO::AuthInfo realInfo = info;
0074         realInfo.username = QStringLiteral("toto"); // you can see I'm french
0075         realInfo.password = QStringLiteral("foobar");
0076         server.addAuthInfo(realInfo, windowId); // seqnr=2
0077 
0078         // queryAuth without the ability to prompt, will just return info unmodified
0079         KIO::AuthInfo resultInfo;
0080         queryAuth(server, info, resultInfo);
0081         QCOMPARE(resultInfo.url, info.url);
0082         QCOMPARE(resultInfo.username, QString());
0083         QCOMPARE(resultInfo.password, QString());
0084         QCOMPARE(resultInfo.isModified(), false);
0085 
0086         // Check that checkAuth finds it
0087         QVERIFY(successCheckAuth(server, info, realInfo));
0088 
0089         // Now remove auth
0090         server.removeAuthInfo(info.url.host(), info.url.scheme(), info.username);
0091         // Check we can't find that auth anymore
0092         QVERIFY(noCheckAuth(server, info));
0093     }
0094 
0095     void testCheckDuringQuery()
0096     {
0097         KPasswdServer server(this);
0098         server.setWalletDisabled(true);
0099         KIO::AuthInfo info;
0100         info.url = QUrl(QStringLiteral("http://www.kde.org"));
0101 
0102         // Start a query
0103         QSignalSpy spyQuery(&server, sigQueryAuthInfoResult);
0104         const qlonglong windowId = 42;
0105         const qlonglong seqNr = 2;
0106         const qlonglong id = server.queryAuthInfoAsync(
0107             info,
0108             QStringLiteral("<NoAuthPrompt>"), // magic string to avoid a dialog
0109             windowId, seqNr, 16 /*usertime*/);
0110 
0111         // Before it is processed, do a check, it will reply delayed.
0112         QSignalSpy spyCheck(&server, sigCheckAuthInfoResult);
0113         const qlonglong idCheck = server.checkAuthInfoAsync(info, windowId, 17 /*usertime*/);
0114         QCOMPARE(idCheck, 0LL); // always
0115         QCOMPARE(spyCheck.count(), 0); // no reply yet
0116 
0117         // Wait for the query to be processed
0118         QVERIFY(QSignalSpy(&server, sigQueryAuthInfoResult).wait(1000));
0119         QCOMPARE(spyQuery.count(), 1);
0120         QCOMPARE(spyQuery[0][0].toLongLong(), id);
0121         KIO::AuthInfo result = spyQuery[0][2].value<KIO::AuthInfo>();
0122 
0123         // Now the check will have replied
0124         QCOMPARE(spyCheck.count(), 1);
0125         QCOMPARE(spyCheck[0][0].toLongLong(), id+1); // it was the next request after the query
0126         KIO::AuthInfo resultCheck = spyCheck[0][2].value<KIO::AuthInfo>();
0127         QCOMPARE(result.username, resultCheck.username);
0128         QCOMPARE(result.password, resultCheck.password);
0129     }
0130 
0131     void testExpiry()
0132     {
0133         KPasswdServer server(this);
0134         server.setWalletDisabled(true);
0135         KIO::AuthInfo info;
0136         info.url = QUrl(QStringLiteral("http://www.example.com"));
0137 
0138         // Add auth to the cache
0139         const qlonglong windowId = 42;
0140         KIO::AuthInfo realInfo = info;
0141         realInfo.username = QStringLiteral("toto");
0142         realInfo.password = QStringLiteral("foobar");
0143         server.addAuthInfo(realInfo, windowId);
0144 
0145         QVERIFY(successCheckAuth(server, info, realInfo));
0146 
0147         // Close another window, shouldn't hurt
0148         server.removeAuthForWindowId(windowId + 1);
0149         QVERIFY(successCheckAuth(server, info, realInfo));
0150 
0151         // Close window
0152         server.removeAuthForWindowId(windowId);
0153 
0154         // Check we can't find that auth anymore
0155         QVERIFY(noCheckAuth(server, info));
0156     }
0157 
0158     void testFillDialog()
0159     {
0160         KPasswdServer server(this);
0161         server.setWalletDisabled(true);
0162         // What the app would ask
0163         KIO::AuthInfo info;
0164         info.url = QUrl(QStringLiteral("http://www.example.com"));
0165 
0166         // What the user would type
0167         KIO::AuthInfo filledInfo(info);
0168         filledInfo.username = QStringLiteral("dfaure");
0169         filledInfo.password = QStringLiteral("toto");
0170 
0171         KIO::AuthInfo result;
0172         queryAuthWithDialog(server, info, filledInfo, result);
0173     }
0174 
0175     void testRejectRetryDialog()
0176     {
0177         KPasswdServer server(this);
0178         server.setWalletDisabled(true);
0179 
0180        // What the app would ask
0181         KIO::AuthInfo info;
0182         info.url = QUrl(QStringLiteral("http://www.example.com"));
0183 
0184         // What the user would type
0185         KIO::AuthInfo filledInfo(info);
0186         filledInfo.username = QStringLiteral("username");
0187         filledInfo.password = QStringLiteral("password");
0188 
0189         KIO::AuthInfo result;
0190         queryAuthWithDialog(server, info, filledInfo, result);
0191 
0192         // Pretend that the returned credentials failed and initiate a retry,
0193         // but cancel the retry dialog.
0194         info.password.clear();
0195         result = KIO::AuthInfo();
0196         queryAuthWithDialog(server, info, filledInfo, result, s_buttonCancel, QDialog::Accepted /*unused*/, QStringLiteral("Invalid username or password"));
0197     }
0198 
0199     void testAcceptRetryDialog()
0200     {
0201         KPasswdServer server(this);
0202         server.setWalletDisabled(true);
0203 
0204        // What the app would ask
0205         KIO::AuthInfo info;
0206         info.url = QUrl(QStringLiteral("http://www.example.com"));
0207 
0208         // What the user would type
0209         KIO::AuthInfo filledInfo(info);
0210         filledInfo.username = QStringLiteral("username");
0211         filledInfo.password = QStringLiteral("password");
0212 
0213         KIO::AuthInfo result;
0214         queryAuthWithDialog(server, info, filledInfo, result);
0215 
0216         // Pretend that the returned credentials failed and initiate a retry,
0217         // but this time continue the retry.
0218         info.password.clear();
0219         result = KIO::AuthInfo();
0220 
0221         queryAuthWithDialog(server, info, filledInfo, result, s_buttonYes, QDialog::Accepted, QStringLiteral("Invalid username or password"));
0222     }
0223 
0224     void testUsernameMistmatch()
0225     {
0226         KPasswdServer server(this);
0227         server.setWalletDisabled(true);
0228 
0229         // What the app would ask. Note the username in the URL.
0230         KIO::AuthInfo info;
0231         info.url = QUrl(QStringLiteral("http://foo@www.example.com"));
0232 
0233         // What the user would type
0234         KIO::AuthInfo filledInfo(info);
0235         filledInfo.username = QStringLiteral("bar");
0236         filledInfo.password = QStringLiteral("blah");
0237 
0238         KIO::AuthInfo result;
0239         queryAuthWithDialog(server, info, filledInfo, result);
0240 
0241         // Check the returned url does not match the request url because of the
0242         // username mismatch between the request URL and the filled in one.
0243         QVERIFY(result.url != filledInfo.url);
0244 
0245         // Verify there is NO cached auth data if the request URL contains the
0246         // original user name (foo).
0247         QVERIFY(noCheckAuth(server, info));
0248 
0249         // Verify there is a cached auth data if the request URL contains the
0250         // new user name (bar).
0251         filledInfo.url = QUrl(QStringLiteral("http://bar@www.example.com"));
0252         QVERIFY(successCheckAuth(server, filledInfo, result));
0253 
0254         // Now the URL check should be valid too.
0255         QCOMPARE(result.url, filledInfo.url);
0256     }
0257 
0258     void testCancelPasswordDialog()
0259     {
0260         KPasswdServer server(this);
0261         server.setWalletDisabled(true);
0262 
0263         // What the app would ask.
0264         KIO::AuthInfo info;
0265         info.url = QUrl(QStringLiteral("http://www.example.com"));
0266         info.username = info.url.userName();
0267 
0268         KIO::AuthInfo result;
0269         queryAuthWithDialog(server, info, KIO::AuthInfo(), result, QDialogButtonBox::NoButton, QDialog::Rejected);
0270     }
0271 
0272     void testVerifyPath()
0273     {
0274         KPasswdServer server(this);
0275         server.setWalletDisabled(true);
0276 
0277         // Add auth to the cache
0278         const qlonglong windowId = 42;
0279         KIO::AuthInfo authInfo;
0280         authInfo.url = QUrl(QStringLiteral("http://www.example.com/test/test.html"));
0281         authInfo.username = QStringLiteral("toto");
0282         authInfo.password = QStringLiteral("foobar");
0283         server.addAuthInfo(authInfo, windowId);
0284 
0285         KIO::AuthInfo queryAuthInfo;
0286         queryAuthInfo.url = QUrl(QStringLiteral("http://www.example.com/test/test2/test.html"));
0287         queryAuthInfo.verifyPath = true;
0288 
0289         KIO::AuthInfo expectedAuthInfo;
0290         expectedAuthInfo.username = QStringLiteral("toto");
0291         expectedAuthInfo.password = QStringLiteral("foobar");
0292 
0293         QVERIFY(successCheckAuth(server, queryAuthInfo, expectedAuthInfo));
0294     }
0295 
0296     void testConcurrentQueryAuth()
0297     {
0298         KPasswdServer server(this);
0299         server.setWalletDisabled(true);
0300 
0301         QList<KIO::AuthInfo> authInfos;
0302         for (int i=0; i < 10; ++i) {
0303            KIO::AuthInfo info;
0304            info.url = QUrl(QLatin1String("http://www.example.com/test") + QString::number(i) + QLatin1String(".html"));
0305            authInfos << info;
0306         }
0307 
0308         // What the user would type
0309         KIO::AuthInfo filledInfo;
0310         filledInfo.username = QStringLiteral("bar");
0311         filledInfo.password = QStringLiteral("blah");
0312 
0313         QList<KIO::AuthInfo> results;
0314         concurrentQueryAuthWithDialog(server, authInfos, filledInfo, results);
0315     }
0316 
0317     void testConcurrentCheckAuth()
0318     {
0319         KPasswdServer server(this);
0320         server.setWalletDisabled(true);
0321 
0322         QList<KIO::AuthInfo> authInfos;
0323         for (int i=0; i < 10; ++i) {
0324            KIO::AuthInfo info;
0325            info.url = QUrl(QLatin1String("http://www.example.com/test") + QString::number(i) + QStringLiteral(".html"));
0326            authInfos << info;
0327         }
0328 
0329         // What the user would type
0330         KIO::AuthInfo filledInfo;
0331         filledInfo.username = QStringLiteral("bar");
0332         filledInfo.password = QStringLiteral("blah");
0333 
0334         QList<KIO::AuthInfo> results;
0335         concurrentQueryAuthWithDialog(server, authInfos, filledInfo, results);
0336     }
0337 
0338 private:
0339     // Checks that no auth is available for @p info
0340     bool noCheckAuth(KPasswdServer& server, const KIO::AuthInfo& info)
0341     {
0342         KIO::AuthInfo result;
0343         checkAuth(server, info, result);
0344         return (result.username == info.username)
0345             && (result.password == info.password)
0346             && !result.isModified();
0347     }
0348 
0349     // Check that the auth is available and equal to @expectedInfo
0350     bool successCheckAuth(KPasswdServer& server, const KIO::AuthInfo& info, const KIO::AuthInfo& expectedInfo)
0351     {
0352         KIO::AuthInfo result;
0353         checkAuth(server, info, result);
0354         return (result.username == expectedInfo.username)
0355             && (result.password == expectedInfo.password)
0356             && result.isModified();
0357     }
0358 
0359     void checkAuth(KPasswdServer& server, const KIO::AuthInfo& info, KIO::AuthInfo& result)
0360     {
0361         QSignalSpy spy(&server, sigCheckAuthInfoResult);
0362         const qlonglong windowId = 42;
0363         const qlonglong id = server.checkAuthInfoAsync(info, windowId, 17 /*usertime*/);
0364         QCOMPARE(id, 0LL); // always
0365         if (spy.isEmpty()) {
0366             QVERIFY(QSignalSpy(&server, sigCheckAuthInfoResult).wait(1000));
0367         }
0368         QCOMPARE(spy.count(), 1);
0369         // kpasswdserver emits a requestId via dbus, we can't get that id here
0370         QVERIFY(spy[0][0].toLongLong() >= 0);
0371         //QCOMPARE(spy[0][1].toLongLong(), 3LL); // seqNr
0372         result = spy[0][2].value<KIO::AuthInfo>();
0373     }
0374 
0375     void queryAuth(KPasswdServer& server, const KIO::AuthInfo& info, KIO::AuthInfo& result)
0376     {
0377         QSignalSpy spy(&server, sigQueryAuthInfoResult);
0378         const qlonglong windowId = 42;
0379         const qlonglong seqNr = 2;
0380         const qlonglong id = server.queryAuthInfoAsync(
0381             info,
0382             QStringLiteral("<NoAuthPrompt>"), // magic string to avoid a dialog
0383             windowId, seqNr, 16 /*usertime*/);
0384         QVERIFY(id >= 0); // requestId, ever increasing
0385         if (spy.isEmpty())
0386             QVERIFY(QSignalSpy(&server, sigQueryAuthInfoResult).wait(1000));
0387         QCOMPARE(spy.count(), 1);
0388         QCOMPARE(spy[0][0].toLongLong(), id);
0389         //QCOMPARE(spy[0][1].toLongLong(), 3LL); // seqNr
0390         result = spy[0][2].value<KIO::AuthInfo>();
0391     }
0392 
0393     void queryAuthWithDialog(KPasswdServer& server, const KIO::AuthInfo& info,
0394                              const KIO::AuthInfo& filledInfo, KIO::AuthInfo& result,
0395                              QDialogButtonBox::StandardButton retryButton = s_buttonYes,
0396                              QDialog::DialogCode code = QDialog::Accepted,
0397                              const QString& errMsg = QString())
0398     {
0399         QSignalSpy spy(&server, sigQueryAuthInfoResult);
0400         const qlonglong windowId = 42;
0401         const qlonglong seqNr = 2;
0402         const qlonglong id = server.queryAuthInfoAsync(
0403             info,
0404             errMsg,
0405             windowId, seqNr, 16 /*usertime*/);
0406         QVERIFY(id >= 0); // requestId, ever increasing
0407         QVERIFY(spy.isEmpty());
0408 
0409         const bool hasErrorMessage = (!errMsg.isEmpty());
0410         const bool isCancelRetryDialogTest = (hasErrorMessage && retryButton == s_buttonCancel);
0411 
0412         if (hasErrorMessage) {
0413             // Retry dialog only knows Yes/No
0414             QMetaObject::invokeMethod(this, "checkRetryDialog",
0415                                       Qt::QueuedConnection, Q_ARG(QDialogButtonBox::StandardButton, retryButton));
0416         }
0417 
0418         if (!isCancelRetryDialogTest) {
0419             QMetaObject::invokeMethod(this, "checkAndFillDialog", Qt::QueuedConnection,
0420                                       Q_ARG(KIO::AuthInfo, info),
0421                                       Q_ARG(KIO::AuthInfo, filledInfo),
0422                                       Q_ARG(QDialog::DialogCode, code ));
0423         }
0424         // Force KPasswdServer to process the request now, otherwise the checkAndFillDialog needs a timer too...
0425         server.processRequest();
0426         if (spy.isEmpty())
0427             QVERIFY(QSignalSpy(&server, sigQueryAuthInfoResult).wait(1000));
0428         QCOMPARE(spy.count(), 1);
0429         QCOMPARE(spy[0][0].toLongLong(), id);
0430         //QCOMPARE(spy[0][1].toLongLong(), 3LL); // seqNr
0431         result = spy[0][2].value<KIO::AuthInfo>();
0432         const QString username = (isCancelRetryDialogTest ? QString() : filledInfo.username);
0433         const QString password = (isCancelRetryDialogTest ? QString() : filledInfo.password);
0434         QCOMPARE(result.username, username);
0435         QCOMPARE(result.password, password);
0436         QCOMPARE(result.isModified(), retryButton == s_buttonYes && code  == QDialog::Accepted);
0437     }
0438 
0439     void concurrentQueryAuthWithDialog(KPasswdServer& server, const QList<KIO::AuthInfo>& infos,
0440                                        const KIO::AuthInfo& filledInfo, QList<KIO::AuthInfo>& results,
0441                                        QDialog::DialogCode code = QDialog::Accepted)
0442     {
0443         QSignalSpy spy(&server, sigQueryAuthInfoResult);
0444         const qlonglong windowId = 42;
0445         qlonglong seqNr = 0;
0446         QList<qlonglong> idList;
0447 
0448         for (const KIO::AuthInfo& info : infos) {
0449             const qlonglong id = server.queryAuthInfoAsync(
0450                 info,
0451                 QString(),
0452                 windowId, seqNr, 16 /*usertime*/);
0453             QVERIFY(id >= 0); // requestId, ever increasing
0454             idList << id;
0455         }
0456 
0457         QVERIFY(spy.isEmpty());
0458         QMetaObject::invokeMethod(this, "checkAndFillDialog", Qt::QueuedConnection,
0459                                   Q_ARG(KIO::AuthInfo, infos.first()),
0460                                   Q_ARG(KIO::AuthInfo,filledInfo),
0461                                   Q_ARG(QDialog::DialogCode, code));
0462 
0463         // Force KPasswdServer to process the request now, otherwise the checkAndFillDialog needs a timer too...
0464         server.processRequest();
0465         while (spy.count() < infos.count())
0466             QVERIFY(QSignalSpy(&server, sigQueryAuthInfoResult).wait(1000));
0467 
0468         QCOMPARE(spy.count(), infos.count());
0469 
0470         for(int i = 0, count = spy.count(); i < count; ++i) {
0471             QCOMPARE(spy[i][0].toLongLong(), idList.at(i));
0472             //QCOMPARE(spy[0][1].toLongLong(), 3LL); // seqNr
0473             KIO::AuthInfo result = spy[i][2].value<KIO::AuthInfo>();
0474             QCOMPARE(result.username, filledInfo.username);
0475             QCOMPARE(result.password, filledInfo.password);
0476             QCOMPARE(result.isModified(), code == QDialog::Accepted);
0477             results << result;
0478         }
0479     }
0480 
0481     void concurrentCheckAuthWithDialog(KPasswdServer& server, const QList<KIO::AuthInfo>& infos,
0482                                        const KIO::AuthInfo& filledInfo, QList<KIO::AuthInfo>& results,
0483                                        QDialog::DialogCode code = QDialog::Accepted)
0484     {
0485         QSignalSpy spy(&server, sigQueryAuthInfoResult);
0486         const qlonglong windowId = 42;
0487         qlonglong seqNr = 0;
0488         QList<qlonglong> idList;
0489 
0490         QListIterator<KIO::AuthInfo> it (infos);
0491         if (it.hasNext()) {
0492             const qlonglong id = server.queryAuthInfoAsync(
0493                 it.next(),
0494                 QString(),
0495                 windowId, seqNr, 16 /*usertime*/);
0496             QVERIFY(id >= 0); // requestId, ever increasing
0497             idList << id;
0498         }
0499 
0500         while (it.hasNext()) {
0501             const qlonglong id = server.checkAuthInfoAsync(it.next(), windowId,16 /*usertime*/);
0502             QVERIFY(id >= 0); // requestId, ever increasing
0503             idList << id;
0504         }
0505 
0506         QVERIFY(spy.isEmpty());
0507         QMetaObject::invokeMethod(this, "checkAndFillDialog", Qt::QueuedConnection,
0508                                   Q_ARG(KIO::AuthInfo, infos.first()),
0509                                   Q_ARG(KIO::AuthInfo,filledInfo),
0510                                   Q_ARG(QDialog::DialogCode, code));
0511 
0512         // Force KPasswdServer to process the request now, otherwise the checkAndFillDialog needs a timer too...
0513         server.processRequest();
0514         if (spy.isEmpty()) {
0515             QVERIFY(QSignalSpy(&server, sigQueryAuthInfoResult).wait(1000));
0516         }
0517 
0518         while ((spy.count()-1) < infos.count()) {
0519             QVERIFY(QSignalSpy(&server, sigCheckAuthInfoResult).wait(1000));
0520         }
0521 
0522         for(int i = 0, count = spy.count(); i < count; ++i) {
0523             QCOMPARE(spy[i][0].toLongLong(), idList.at(i));
0524             //QCOMPARE(spy[0][1].toLongLong(), 3LL); // seqNr
0525             KIO::AuthInfo result = spy[i][2].value<KIO::AuthInfo>();
0526             QCOMPARE(result.username, filledInfo.username);
0527             QCOMPARE(result.password, filledInfo.password);
0528             QCOMPARE(result.isModified(), code == QDialog::Accepted);
0529             results << result;
0530         }
0531     }
0532 
0533 protected Q_SLOTS:
0534     void checkAndFillDialog(const KIO::AuthInfo& info, const KIO::AuthInfo& filledInfo, QDialog::DialogCode code)
0535     {
0536         Q_FOREACH(QWidget *widget, QApplication::topLevelWidgets()) {
0537             if (KPasswordDialog* dialog = qobject_cast<KPasswordDialog *>(widget)) {
0538                 if (code == QDialog::Accepted) {
0539                     QCOMPARE(dialog->username(), getUserNameFrom(info));
0540                     QCOMPARE(dialog->password(), info.password);
0541                     dialog->setUsername(filledInfo.username);
0542                     dialog->setPassword(filledInfo.password);
0543                 }
0544                 dialog->done(code);
0545                 return;
0546             }
0547         }
0548         qWarning() << "No KPasswordDialog found!";
0549     }
0550 
0551     void checkRetryDialog(QDialogButtonBox::StandardButton code = s_buttonYes)
0552     {
0553         Q_FOREACH(QWidget *widget, QApplication::topLevelWidgets()) {
0554             QDialog* dialog = qobject_cast<QDialog*>(widget);
0555             if (dialog && !dialog->inherits("KPasswordDialog")) {
0556                 dialog->done(code);
0557                 return;
0558             }
0559         }
0560         qWarning() << "No retry dialog found";
0561     }
0562 };
0563 
0564 QTEST_MAIN( KPasswdServerTest )
0565 
0566 #include "kpasswdservertest.moc"