[plasma/ksshaskpass] /: Add autotest

Kai Uwe Broulik <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ceba860b979a8b29148011f8fdf3da802f22aa97 by Kai Uwe Broulik.
Committed on 17/08/2026 at 14:09.
Pushed by broulik into branch 'master'.

Add autotest

Testing various variants of the supported prompts to ensure there
are no regressions when new formats are added.

Adds an "Unknown" display type so we can detect prompt not having
been able to parse the prompt.

M  +9    -0    CMakeLists.txt
A  +8    -0    autotests/CMakeLists.txt
A  +141  -0    autotests/tst_prompt.cpp     [License: GPL(v2.0+)]
M  +1    -0    src/main.cpp
M  +1    -0    src/prompt.h

https://invent.kde.org/plasma/ksshaskpass/-/commit/ceba860b979a8b29148011f8fdf3da802f22aa97

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c459a85..7b9f85e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,11 @@ include(ECMQtDeclareLoggingCategory)
 
 find_package(Qt6  ${QT_MIN_VERSION} REQUIRED COMPONENTS Core)
 
+if (BUILD_TESTING)
+    include(ECMAddTests)
+    find_package(Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS Test)
+endif()
+
 find_package(Qt6Keychain ${QT_KEYCHAIN_MIN_VERSION} REQUIRED)
 
 add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
@@ -57,6 +62,10 @@ if (KF6DocTools_FOUND)
     add_subdirectory(doc)
 endif()
 
+if (BUILD_TESTING)
+    add_subdirectory(autotests)
+endif()
+
 ki18n_install(po)
 
 feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
new file mode 100644
index 0000000..ddcee07
--- /dev/null
+++ b/autotests/CMakeLists.txt
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: 2026 Kai Uwe Broulik <[email protected]>
+
+set(testWindowPaintData_SRCS test_window_paint_data.cpp)
+add_executable(prompttest tst_prompt.cpp)
+target_link_libraries(prompttest PRIVATE Qt6::Core Qt6::Test ksshaskpass_prompt)
+add_test(NAME prompttest COMMAND prompttest)
+ecm_mark_as_test(prompttest)
diff --git a/autotests/tst_prompt.cpp b/autotests/tst_prompt.cpp
new file mode 100644
index 0000000..fa838a8
--- /dev/null
+++ b/autotests/tst_prompt.cpp
@@ -0,0 +1,141 @@
+/*
+ * SPDX-FileCopyrightText: 2026 Kai Uwe Broulik <[email protected]>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "prompt.h"
+
+#include <QString>
+#include <QTest>
+
+class PromptTest : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testPrompt_data();
+    void testPrompt();
+};
+
+void PromptTest::testPrompt_data()
+{
+    QTest::addColumn<PromptType>("promptType");
+    QTest::addColumn<QString>("prompt");
+
+    QTest::addColumn<QString>("expectedIdentifier");
+    QTest::addColumn<DisplayType>("expectedDisplayType");
+    QTest::addColumn<bool>("expectedIgnoreKeychain");
+
+    // PromptType special cases
+
+    QTest::newRow("confirm") << PromptType::Confirm << QStringLiteral("does not matter") << QString() << DisplayType::Confirm << true;
+
+    QTest::newRow("none") << PromptType::None << QStringLiteral("does not matter") << QString() << DisplayType::ConfirmCancel << true;
+
+    // OpenSSH
+
+    QTest::newRow("ssh-password") << PromptType::Entry << QStringLiteral("[email protected]'s password: ") << QStringLiteral("[email protected]")
+                                  << DisplayType::Password << false;
+
+    QTest::newRow("ssh-pam") << PromptType::Entry << QStringLiteral("([email protected]) Password: ") << QStringLiteral("[email protected]")
+                             << DisplayType::Password << false;
+
+    // Password change
+
+    QTest::newRow("enter-old-password") << PromptType::Entry << QStringLiteral("Enter [email protected]'s old password: ") << QStringLiteral("[email protected]")
+                                        << DisplayType::Password << true;
+
+    QTest::newRow("enter-new-password") << PromptType::Entry << QStringLiteral("Enter [email protected]'s new password: ") << QStringLiteral("[email protected]")
+                                        << DisplayType::Password << true;
+
+    QTest::newRow("retype-new-password") << PromptType::Entry << QStringLiteral("Retype [email protected]'s new password: ")
+                                         << QStringLiteral("[email protected]") << DisplayType::Password << true;
+
+    // SSH keys
+
+    QTest::newRow("rsa-key") << PromptType::Entry << QStringLiteral("Enter passphrase for RSA key '/home/test/.ssh/id_rsa': ")
+                             << QStringLiteral("/home/test/.ssh/id_rsa") << DisplayType::Password << false;
+
+    QTest::newRow("key") << PromptType::Entry << QStringLiteral("Enter passphrase for key '/home/test/.ssh/id_ed25519': ")
+                         << QStringLiteral("/home/test/.ssh/id_ed25519") << DisplayType::Password << false;
+
+    QTest::newRow("ssh-add") << PromptType::Entry << QStringLiteral("Enter passphrase for /home/test/.ssh/id_ed25519: ")
+                             << QStringLiteral("/home/test/.ssh/id_ed25519") << DisplayType::Password << false;
+
+    QTest::newRow("ssh-add-confirm") << PromptType::Entry << QStringLiteral("Enter passphrase for /home/test/.ssh/id_ed25519 (will confirm each use): ")
+                                     << QStringLiteral("/home/test/.ssh/id_ed25519") << DisplayType::Password << false;
+
+    QTest::newRow("ssh-add-retry") << PromptType::Entry << QStringLiteral("Bad passphrase, try again for /home/test/.ssh/id_ed25519: ")
+                                   << QStringLiteral("/home/test/.ssh/id_ed25519") << DisplayType::Password << true;
+
+    QTest::newRow("ssh-add-retry-confirm") << PromptType::Entry
+                                           << QStringLiteral("Bad passphrase, try again for /home/test/.ssh/id_ed25519 (will confirm each use): ")
+                                           << QStringLiteral("/home/test/.ssh/id_ed25519") << DisplayType::Password << true;
+
+    // PGP PIN
+
+    QTest::newRow("pkcs11-pin") << PromptType::Entry << QStringLiteral("Enter PIN for 'OpenPGP': ") << QStringLiteral("OpenPGP") << DisplayType::Password
+                                << false;
+
+    QTest::newRow("security-key-pin") << PromptType::Entry << QStringLiteral("Enter PIN for ED25519-SK key SHA256:abcdef: ")
+                                      << QStringLiteral("PIN:SHA256:abcdef") << DisplayType::Password << true;
+
+    QTest::newRow("security-key-pin-presence") << PromptType::Entry << QStringLiteral("Enter PIN and confirm user presence for ECDSA-SK key SHA256:xyz: ")
+                                               << QStringLiteral("PIN:SHA256:xyz") << DisplayType::Password << true;
+
+    // OTP
+
+    QTest::newRow("verification-code") << PromptType::Entry << QStringLiteral("Verification code: ") << QString() << DisplayType::ClearText << true;
+
+    // Git
+
+    QTest::newRow("git-username") << PromptType::Entry << QStringLiteral("Username: ") << QString() << DisplayType::ClearText << true;
+
+    QTest::newRow("git-password") << PromptType::Entry << QStringLiteral("Password: ") << QString() << DisplayType::Password << true;
+
+    QTest::newRow("git-username-url") << PromptType::Entry << QStringLiteral("Username for 'https://invent.kde.org': ")
+                                      << QStringLiteral("https://invent.kde.org") << DisplayType::ClearText << false;
+
+    QTest::newRow("git-password-url") << PromptType::Entry << QStringLiteral("Password for 'https://invent.kde.org': ")
+                                      << QStringLiteral("https://invent.kde.org") << DisplayType::Password << false;
+
+    // git-lfs
+
+    QTest::newRow("git-lfs-username") << PromptType::Entry << QStringLiteral("Username for \"https://invent.kde.org\"")
+                                      << QStringLiteral("https://invent.kde.org") << DisplayType::ClearText << false;
+
+    QTest::newRow("git-lfs-password") << PromptType::Entry << QStringLiteral("Password for \"https://invent.kde.org\"")
+                                      << QStringLiteral("https://invent.kde.org") << DisplayType::Password << false;
+
+    // Unknown host
+
+    QTest::newRow("unknown-host") << PromptType::Entry
+                                  << QStringLiteral(
+                                         "The authenticity of host 'invent.kde.org (1.2.3.4)' can't be established.\n"
+                                         "ED25519 key fingerprint is SHA256:1234567890abcdef.\n"
+                                         "This key is not known by any other names.\n"
+                                         "Are you sure you want to continue connecting (yes/no/[fingerprint])? ")
+                                  << QString() << DisplayType::UnknownSshHost << true;
+}
+
+void PromptTest::testPrompt()
+{
+    QFETCH(PromptType, promptType);
+    QFETCH(QString, prompt);
+
+    QFETCH(QString, expectedIdentifier);
+    QFETCH(DisplayType, expectedDisplayType);
+    QFETCH(bool, expectedIgnoreKeychain);
+
+    QString identifier;
+    bool ignoreKeychain = false;
+    DisplayType displayType = DisplayType::Unknown;
+    parsePrompt(promptType, prompt, identifier, ignoreKeychain, displayType);
+
+    QCOMPARE(identifier, expectedIdentifier);
+    QCOMPARE(displayType, expectedDisplayType);
+    QCOMPARE(ignoreKeychain, expectedIgnoreKeychain);
+}
+
+QTEST_GUILESS_MAIN(PromptTest)
+#include "tst_prompt.moc"
diff --git a/src/main.cpp b/src/main.cpp
index 0f35f61..ccb598c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -183,6 +183,7 @@ int main(int argc, char **argv)
         item = QStringLiteral("yes\n");
         break;
     }
+    case DisplayType::Unknown: // just in case.
     case DisplayType::ClearText:
     // Should use a dialog with visible input, but KPasswordDialog doesn't support that and
     // other available dialog types don't have a "Keep" checkbox.
diff --git a/src/prompt.h b/src/prompt.h
index 682ffa6..002955b 100644
--- a/src/prompt.h
+++ b/src/prompt.h
@@ -17,6 +17,7 @@ enum class PromptType {
 
 // Implemented UI display types.
 enum class DisplayType {
+    Unknown,
     Password,
     ClearText,
     Confirm,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.