diff options
Diffstat (limited to 'tests/gui/TestGui.cpp')
-rw-r--r-- | tests/gui/TestGui.cpp | 452 |
1 files changed, 261 insertions, 191 deletions
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 9118d3e21..70417dbd5 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -45,6 +45,7 @@ #include "core/Entry.h" #include "core/Group.h" #include "core/Metadata.h" +#include "core/PasswordHealth.h" #include "core/Tools.h" #include "crypto/Crypto.h" #include "crypto/kdf/AesKdf.h" @@ -58,43 +59,64 @@ #include "gui/FileDialog.h" #include "gui/MessageBox.h" #include "gui/PasswordEdit.h" +#include "gui/PasswordGeneratorWidget.h" #include "gui/SearchWidget.h" #include "gui/TotpDialog.h" #include "gui/TotpSetupDialog.h" +#include "gui/databasekey/KeyComponentWidget.h" +#include "gui/databasekey/KeyFileEditWidget.h" +#include "gui/databasekey/PasswordEditWidget.h" #include "gui/dbsettings/DatabaseSettingsDialog.h" #include "gui/entry/EditEntryWidget.h" #include "gui/entry/EntryView.h" #include "gui/group/EditGroupWidget.h" #include "gui/group/GroupModel.h" #include "gui/group/GroupView.h" -#include "gui/masterkey/KeyComponentWidget.h" -#include "gui/masterkey/KeyFileEditWidget.h" -#include "gui/masterkey/PasswordEditWidget.h" #include "gui/wizard/NewDatabaseWizard.h" #include "keys/FileKey.h" #include "keys/PasswordKey.h" -QTEST_MAIN(TestGui) +#define TEST_MODAL_NO_WAIT(TEST_CODE) \ + bool dialogFinished = false; \ + QTimer::singleShot(0, [&]() { TEST_CODE dialogFinished = true; }) + +#define TEST_MODAL(TEST_CODE) \ + TEST_MODAL_NO_WAIT(TEST_CODE); \ + QTRY_VERIFY(dialogFinished) + +int main(int argc, char* argv[]) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif + Application app(argc, argv); + app.setApplicationName("KeePassXC"); + app.setApplicationVersion(KEEPASSXC_VERSION); + app.setQuitOnLastWindowClosed(false); + app.setAttribute(Qt::AA_Use96Dpi, true); + app.applyTheme(); + QTEST_DISABLE_KEYPAD_NAVIGATION + TestGui tc; + QTEST_SET_MAIN_SOURCE_PATH + return QTest::qExec(&tc, argc, argv); +} static QString dbFileName = QStringLiteral(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.kdbx"); void TestGui::initTestCase() { - Application::setApplicationName("KeePassXC"); - Application::setApplicationVersion(KEEPASSXC_VERSION); - QApplication::setQuitOnLastWindowClosed(false); - QVERIFY(Crypto::init()); Config::createTempFileInstance(); // Disable autosave so we can test the modified file indicator - config()->set("AutoSaveAfterEveryChange", false); - config()->set("AutoSaveOnExit", false); + config()->set(Config::AutoSaveAfterEveryChange, false); + config()->set(Config::AutoSaveOnExit, false); // Enable the tray icon so we can test hiding/restoring the windowQByteArray - config()->set("GUI/ShowTrayIcon", true); + config()->set(Config::GUI_ShowTrayIcon, true); // Disable advanced settings mode (activate within individual tests to test advanced settings) - config()->set("GUI/AdvancedSettings", false); + config()->set(Config::GUI_AdvancedSettings, false); // Disable the update check first time alert - config()->set("UpdateCheckMessageShown", true); + config()->set(Config::UpdateCheckMessageShown, true); Bootstrap::bootstrapApplication(); @@ -168,7 +190,7 @@ void TestGui::testSettingsDefaultTabOrder() QTest::keyClick(settingsWidget, Qt::Key::Key_Escape); // check database settings default tab order - triggerAction("actionChangeDatabaseSettings"); + triggerAction("actionDatabaseSettings"); auto* dbSettingsWidget = m_mainWindow->findChild<DatabaseSettingsDialog*>(); QVERIFY(dbSettingsWidget->isVisible()); QCOMPARE(dbSettingsWidget->findChild<CategoryListWidget*>("categoryList")->currentCategory(), 0); @@ -182,7 +204,91 @@ void TestGui::testSettingsDefaultTabOrder() void TestGui::testCreateDatabase() { - QTimer::singleShot(50, this, SLOT(createDatabaseCallback())); + TEST_MODAL_NO_WAIT( + NewDatabaseWizard * wizard; QTRY_VERIFY(wizard = m_tabWidget->findChild<NewDatabaseWizard*>()); + + QTest::keyClicks(wizard->currentPage()->findChild<QLineEdit*>("databaseName"), "Test Name"); + QTest::keyClicks(wizard->currentPage()->findChild<QLineEdit*>("databaseDescription"), "Test Description"); + QCOMPARE(wizard->currentId(), 0); + + QTest::keyClick(wizard, Qt::Key_Enter); + QCOMPARE(wizard->currentId(), 1); + + auto decryptionTimeSlider = wizard->currentPage()->findChild<QSlider*>("decryptionTimeSlider"); + auto algorithmComboBox = wizard->currentPage()->findChild<QComboBox*>("algorithmComboBox"); + QTRY_VERIFY(decryptionTimeSlider->isVisible()); + QVERIFY(!algorithmComboBox->isVisible()); + auto advancedToggle = wizard->currentPage()->findChild<QPushButton*>("advancedSettingsButton"); + QTest::mouseClick(advancedToggle, Qt::MouseButton::LeftButton); + QTRY_VERIFY(!decryptionTimeSlider->isVisible()); + QVERIFY(algorithmComboBox->isVisible()); + + auto rounds = wizard->currentPage()->findChild<QSpinBox*>("transformRoundsSpinBox"); + QVERIFY(rounds); + QVERIFY(rounds->isVisible()); + QTest::mouseClick(rounds, Qt::MouseButton::LeftButton); + QTest::keyClick(rounds, Qt::Key_A, Qt::ControlModifier); + QTest::keyClicks(rounds, "2"); + QTest::keyClick(rounds, Qt::Key_Tab); + QTest::keyClick(rounds, Qt::Key_Tab); + + auto memory = wizard->currentPage()->findChild<QSpinBox*>("memorySpinBox"); + QVERIFY(memory); + QVERIFY(memory->isVisible()); + QTest::mouseClick(memory, Qt::MouseButton::LeftButton); + QTest::keyClick(memory, Qt::Key_A, Qt::ControlModifier); + QTest::keyClicks(memory, "50"); + QTest::keyClick(memory, Qt::Key_Tab); + + auto parallelism = wizard->currentPage()->findChild<QSpinBox*>("parallelismSpinBox"); + QVERIFY(parallelism); + QVERIFY(parallelism->isVisible()); + QTest::mouseClick(parallelism, Qt::MouseButton::LeftButton); + QTest::keyClick(parallelism, Qt::Key_A, Qt::ControlModifier); + QTest::keyClicks(parallelism, "1"); + QTest::keyClick(parallelism, Qt::Key_Enter); + + QCOMPARE(wizard->currentId(), 2); + + // enter password + auto* passwordWidget = wizard->currentPage()->findChild<PasswordEditWidget*>(); + QCOMPARE(passwordWidget->visiblePage(), KeyFileEditWidget::Page::Edit); + auto* passwordEdit = passwordWidget->findChild<QLineEdit*>("enterPasswordEdit"); + auto* passwordRepeatEdit = passwordWidget->findChild<QLineEdit*>("repeatPasswordEdit"); + QTRY_VERIFY(passwordEdit->isVisible()); + QTRY_VERIFY(passwordEdit->hasFocus()); + QTest::keyClicks(passwordEdit, "test"); + QTest::keyClick(passwordEdit, Qt::Key::Key_Tab); + QTest::keyClicks(passwordRepeatEdit, "test"); + + // add key file + auto* additionalOptionsButton = wizard->currentPage()->findChild<QPushButton*>("additionalKeyOptionsToggle"); + auto* keyFileWidget = wizard->currentPage()->findChild<KeyFileEditWidget*>(); + QVERIFY(additionalOptionsButton->isVisible()); + QTest::mouseClick(additionalOptionsButton, Qt::MouseButton::LeftButton); + QTRY_VERIFY(keyFileWidget->isVisible()); + QTRY_VERIFY(!additionalOptionsButton->isVisible()); + QCOMPARE(passwordWidget->visiblePage(), KeyFileEditWidget::Page::Edit); + QTest::mouseClick(keyFileWidget->findChild<QPushButton*>("addButton"), Qt::MouseButton::LeftButton); + auto* fileCombo = keyFileWidget->findChild<QComboBox*>("keyFileCombo"); + QTRY_VERIFY(fileCombo); + QTRY_VERIFY(fileCombo->isVisible()); + fileDialog()->setNextFileName(QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed.key")); + QTest::keyClick(keyFileWidget->findChild<QPushButton*>("addButton"), Qt::Key::Key_Enter); + QVERIFY(fileCombo->hasFocus()); + auto* browseButton = keyFileWidget->findChild<QPushButton*>("browseKeyFileButton"); + QTest::keyClick(browseButton, Qt::Key::Key_Enter); + QCOMPARE(fileCombo->currentText(), QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed.key")); + + // save database to temporary file + TemporaryFile tmpFile; + QVERIFY(tmpFile.open()); + tmpFile.close(); + fileDialog()->setNextFileName(tmpFile.fileName()); + + QTest::keyClick(fileCombo, Qt::Key::Key_Enter); + tmpFile.remove();); + triggerAction("actionDatabaseNew"); // there is a new empty db @@ -208,94 +314,9 @@ void TestGui::testCreateDatabase() // close the new database MessageBox::setNextAnswer(MessageBox::No); triggerAction("actionDatabaseClose"); -} -void TestGui::createDatabaseCallback() -{ - auto* wizard = m_tabWidget->findChild<NewDatabaseWizard*>(); - QVERIFY(wizard); - - QTest::keyClicks(wizard->currentPage()->findChild<QLineEdit*>("databaseName"), "Test Name"); - QTest::keyClicks(wizard->currentPage()->findChild<QLineEdit*>("databaseDescription"), "Test Description"); - QCOMPARE(wizard->currentId(), 0); - - QTest::keyClick(wizard, Qt::Key_Enter); - QCOMPARE(wizard->currentId(), 1); - - auto decryptionTimeSlider = wizard->currentPage()->findChild<QSlider*>("decryptionTimeSlider"); - auto algorithmComboBox = wizard->currentPage()->findChild<QComboBox*>("algorithmComboBox"); - QTRY_VERIFY(decryptionTimeSlider->isVisible()); - QVERIFY(!algorithmComboBox->isVisible()); - auto advancedToggle = wizard->currentPage()->findChild<QPushButton*>("advancedSettingsButton"); - QTest::mouseClick(advancedToggle, Qt::MouseButton::LeftButton); - QTRY_VERIFY(!decryptionTimeSlider->isVisible()); - QVERIFY(algorithmComboBox->isVisible()); - - auto rounds = wizard->currentPage()->findChild<QSpinBox*>("transformRoundsSpinBox"); - QVERIFY(rounds); - QVERIFY(rounds->isVisible()); - QTest::mouseClick(rounds, Qt::MouseButton::LeftButton); - QTest::keyClick(rounds, Qt::Key_A, Qt::ControlModifier); - QTest::keyClicks(rounds, "2"); - QTest::keyClick(rounds, Qt::Key_Tab); - QTest::keyClick(rounds, Qt::Key_Tab); - - auto memory = wizard->currentPage()->findChild<QSpinBox*>("memorySpinBox"); - QVERIFY(memory); - QVERIFY(memory->isVisible()); - QTest::mouseClick(memory, Qt::MouseButton::LeftButton); - QTest::keyClick(memory, Qt::Key_A, Qt::ControlModifier); - QTest::keyClicks(memory, "50"); - QTest::keyClick(memory, Qt::Key_Tab); - - auto parallelism = wizard->currentPage()->findChild<QSpinBox*>("parallelismSpinBox"); - QVERIFY(parallelism); - QVERIFY(parallelism->isVisible()); - QTest::mouseClick(parallelism, Qt::MouseButton::LeftButton); - QTest::keyClick(parallelism, Qt::Key_A, Qt::ControlModifier); - QTest::keyClicks(parallelism, "1"); - QTest::keyClick(parallelism, Qt::Key_Enter); - - QCOMPARE(wizard->currentId(), 2); - - // enter password - auto* passwordWidget = wizard->currentPage()->findChild<PasswordEditWidget*>(); - QCOMPARE(passwordWidget->visiblePage(), KeyFileEditWidget::Page::Edit); - auto* passwordEdit = passwordWidget->findChild<QLineEdit*>("enterPasswordEdit"); - auto* passwordRepeatEdit = passwordWidget->findChild<QLineEdit*>("repeatPasswordEdit"); - QTRY_VERIFY(passwordEdit->isVisible()); - QTRY_VERIFY(passwordEdit->hasFocus()); - QTest::keyClicks(passwordEdit, "test"); - QTest::keyClick(passwordEdit, Qt::Key::Key_Tab); - QTest::keyClicks(passwordRepeatEdit, "test"); - - // add key file - auto* additionalOptionsButton = wizard->currentPage()->findChild<QPushButton*>("additionalKeyOptionsToggle"); - auto* keyFileWidget = wizard->currentPage()->findChild<KeyFileEditWidget*>(); - QVERIFY(additionalOptionsButton->isVisible()); - QTest::mouseClick(additionalOptionsButton, Qt::MouseButton::LeftButton); - QTRY_VERIFY(keyFileWidget->isVisible()); - QTRY_VERIFY(!additionalOptionsButton->isVisible()); - QCOMPARE(passwordWidget->visiblePage(), KeyFileEditWidget::Page::Edit); - QTest::mouseClick(keyFileWidget->findChild<QPushButton*>("addButton"), Qt::MouseButton::LeftButton); - auto* fileCombo = keyFileWidget->findChild<QComboBox*>("keyFileCombo"); - QTRY_VERIFY(fileCombo); - QTRY_VERIFY(fileCombo->isVisible()); - fileDialog()->setNextFileName(QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed.key")); - QTest::keyClick(keyFileWidget->findChild<QPushButton*>("addButton"), Qt::Key::Key_Enter); - QVERIFY(fileCombo->hasFocus()); - auto* browseButton = keyFileWidget->findChild<QPushButton*>("browseKeyFileButton"); - QTest::keyClick(browseButton, Qt::Key::Key_Enter); - QCOMPARE(fileCombo->currentText(), QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed.key")); - - // save database to temporary file - TemporaryFile tmpFile; - QVERIFY(tmpFile.open()); - tmpFile.close(); - fileDialog()->setNextFileName(tmpFile.fileName()); - - QTest::keyClick(fileCombo, Qt::Key::Key_Enter); - tmpFile.remove(); + // Wait for dialog to terminate + QTRY_VERIFY(dialogFinished); } void TestGui::testMergeDatabase() @@ -330,7 +351,7 @@ void TestGui::testMergeDatabase() void TestGui::testAutoreloadDatabase() { - config()->set("AutoReloadOnChange", false); + config()->set(Config::AutoReloadOnChange, false); // Test accepting new file in autoreload MessageBox::setNextAnswer(MessageBox::Yes); @@ -363,7 +384,7 @@ void TestGui::testAutoreloadDatabase() // Test accepting a merge of edits into autoreload // Turn on autoload so we only get one messagebox (for the merge) - config()->set("AutoReloadOnChange", true); + config()->set(Config::AutoReloadOnChange, true); // Modify some entries testEditEntry(); @@ -430,10 +451,21 @@ void TestGui::testEditEntry() QCOMPARE(entry->historyItems().size(), ++editCount); QVERIFY(!applyButton->isEnabled()); + // Test the "known bad" checkbox + editEntryWidget->setCurrentPage(1); + auto knownBadCheckBox = editEntryWidget->findChild<QCheckBox*>("knownBadCheckBox"); + QVERIFY(knownBadCheckBox); + QCOMPARE(knownBadCheckBox->isChecked(), false); + knownBadCheckBox->setChecked(true); + QTest::mouseClick(applyButton, Qt::LeftButton); + QCOMPARE(entry->historyItems().size(), ++editCount); + QCOMPARE(entry->customData()->contains(PasswordHealth::OPTION_KNOWN_BAD), true); + QCOMPARE(entry->customData()->value(PasswordHealth::OPTION_KNOWN_BAD), TRUE_STR); + // Test entry colors (simulate choosing a color) editEntryWidget->setCurrentPage(1); - auto fgColor = QColor(Qt::red); - auto bgColor = QColor(Qt::blue); + auto fgColor = QString("#FF0000"); + auto bgColor = QString("#0000FF"); // Set foreground color auto colorButton = editEntryWidget->findChild<QPushButton*>("fgColorButton"); auto colorCheckBox = editEntryWidget->findChild<QCheckBox*>("fgColorCheckBox"); @@ -460,17 +492,6 @@ void TestGui::testEditEntry() QCOMPARE(attrTextEdit->toPlainText(), attrText); editEntryWidget->setCurrentPage(0); - // Test mismatch passwords - auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit"); - QString originalPassword = passwordEdit->text(); - passwordEdit->setText("newpass"); - QTest::mouseClick(okButton, Qt::LeftButton); - auto* messageWiget = editEntryWidget->findChild<MessageWidget*>("messageWidget"); - QTRY_VERIFY(messageWiget->isVisible()); - QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); - QCOMPARE(passwordEdit->text(), QString("newpass")); - passwordEdit->setText(originalPassword); - // Save the edit (press OK) QTest::mouseClick(okButton, Qt::LeftButton); QApplication::processEvents(); @@ -478,9 +499,9 @@ void TestGui::testEditEntry() // Confirm edit was made QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::ViewMode); QCOMPARE(entry->title(), QString("Sample Entry_test")); - QCOMPARE(entry->foregroundColor(), fgColor); + QCOMPARE(entry->foregroundColor().toUpper(), fgColor.toUpper()); QCOMPARE(entryItem.data(Qt::ForegroundRole), QVariant(fgColor)); - QCOMPARE(entry->backgroundColor(), bgColor); + QCOMPARE(entry->backgroundColor().toUpper(), bgColor.toUpper()); QCOMPARE(entryItem.data(Qt::BackgroundRole), QVariant(bgColor)); QCOMPARE(entry->historyItems().size(), ++editCount); @@ -495,7 +516,6 @@ void TestGui::testEditEntry() titleEdit->setText("multiline\ntitle"); editEntryWidget->findChild<QComboBox*>("usernameComboBox")->lineEdit()->setText("multiline\nusername"); editEntryWidget->findChild<QLineEdit*>("passwordEdit")->setText("multiline\npassword"); - editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit")->setText("multiline\npassword"); editEntryWidget->findChild<QLineEdit*>("urlEdit")->setText("multiline\nurl"); QTest::mouseClick(okButton, Qt::LeftButton); @@ -555,7 +575,7 @@ void TestGui::testSearchEditEntry() // Check the path in header is "parent-group > entry" QCOMPARE(m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget")->findChild<QLabel*>("headerLabel")->text(), - QString("Good > Doggy > Edit entry")); + QStringLiteral("Good \u2B29 Doggy \u2B29 Edit entry")); } void TestGui::testAddEntry() @@ -604,9 +624,7 @@ void TestGui::testAddEntry() QTest::keyClicks(usernameComboBox, "Auto"); QTest::keyPress(usernameComboBox, Qt::Key_Right); auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit"); - auto* passwordRepeatEdit = editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit"); QTest::keyClicks(passwordEdit, "something 2"); - QTest::keyClicks(passwordRepeatEdit, "something 2"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::ViewMode); @@ -652,53 +670,62 @@ void TestGui::testPasswordEntryEntropy() QTest::keyClicks(titleEdit, "test"); // Open the password generator - auto* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton"); - QTest::mouseClick(generatorButton, Qt::LeftButton); - - // Type in some password - auto* editNewPassword = editEntryWidget->findChild<QLineEdit*>("editNewPassword"); - auto* entropyLabel = editEntryWidget->findChild<QLabel*>("entropyLabel"); - auto* strengthLabel = editEntryWidget->findChild<QLabel*>("strengthLabel"); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "hello"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 6.38 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "helloworld"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 13.10 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "password1"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 4.00 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "D0g.................."); - QCOMPARE(entropyLabel->text(), QString("Entropy: 19.02 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "Tr0ub4dour&3"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 30.87 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "correcthorsebatterystaple"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 47.98 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Weak")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "YQC3kbXbjC652dTDH"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 95.83 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Good")); - - editNewPassword->setText(""); - QTest::keyClicks(editNewPassword, "Bs5ZFfthWzR8DGFEjaCM6bGqhmCT4km"); - QCOMPARE(entropyLabel->text(), QString("Entropy: 174.59 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Excellent")); + auto* passwordEdit = editEntryWidget->findChild<PasswordEdit*>(); + QVERIFY(passwordEdit); + QTest::mouseClick(passwordEdit, Qt::LeftButton); + + QTest::keyClick(passwordEdit, Qt::Key_G, Qt::ControlModifier); + + TEST_MODAL(PasswordGeneratorWidget * pwGeneratorWidget; + QTRY_VERIFY(pwGeneratorWidget = m_dbWidget->findChild<PasswordGeneratorWidget*>()); + + // Type in some password + auto* generatedPassword = pwGeneratorWidget->findChild<QLineEdit*>("editNewPassword"); + auto* entropyLabel = pwGeneratorWidget->findChild<QLabel*>("entropyLabel"); + auto* strengthLabel = pwGeneratorWidget->findChild<QLabel*>("strengthLabel"); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "hello"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 6.38 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "helloworld"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 13.10 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "password1"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 4.00 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "D0g.................."); + QCOMPARE(entropyLabel->text(), QString("Entropy: 19.02 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "Tr0ub4dour&3"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 30.87 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Poor")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "correcthorsebatterystaple"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 47.98 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Weak")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "YQC3kbXbjC652dTDH"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 95.83 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Good")); + + generatedPassword->setText(""); + QTest::keyClicks(generatedPassword, "Bs5ZFfthWzR8DGFEjaCM6bGqhmCT4km"); + QCOMPARE(entropyLabel->text(), QString("Entropy: 174.59 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Excellent")); + + QTest::mouseClick(generatedPassword, Qt::LeftButton); + QTest::keyClick(generatedPassword, Qt::Key_Escape);); } void TestGui::testDicewareEntryEntropy() @@ -724,25 +751,38 @@ void TestGui::testDicewareEntryEntropy() QTest::keyClicks(titleEdit, "test"); // Open the password generator - auto* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton"); - QTest::mouseClick(generatorButton, Qt::LeftButton); + auto* passwordEdit = editEntryWidget->findChild<PasswordEdit*>(); + QVERIFY(passwordEdit); + QTest::mouseClick(passwordEdit, Qt::LeftButton); - // Select Diceware - auto* tabWidget = editEntryWidget->findChild<QTabWidget*>("tabWidget"); - auto* dicewareWidget = editEntryWidget->findChild<QWidget*>("dicewareWidget"); - tabWidget->setCurrentWidget(dicewareWidget); + QTest::keyClick(passwordEdit, Qt::Key_G, Qt::ControlModifier); - auto* comboBoxWordList = dicewareWidget->findChild<QComboBox*>("comboBoxWordList"); - comboBoxWordList->setCurrentText("eff_large.wordlist"); - auto* spinBoxWordCount = dicewareWidget->findChild<QSpinBox*>("spinBoxWordCount"); - spinBoxWordCount->setValue(6); + TEST_MODAL(PasswordGeneratorWidget * pwGeneratorWidget; + QTRY_VERIFY(pwGeneratorWidget = m_dbWidget->findChild<PasswordGeneratorWidget*>()); - // Type in some password - auto* entropyLabel = editEntryWidget->findChild<QLabel*>("entropyLabel"); - auto* strengthLabel = editEntryWidget->findChild<QLabel*>("strengthLabel"); + // Select Diceware + auto* generatedPassword = pwGeneratorWidget->findChild<QLineEdit*>("editNewPassword"); + auto* tabWidget = pwGeneratorWidget->findChild<QTabWidget*>("tabWidget"); + auto* dicewareWidget = pwGeneratorWidget->findChild<QWidget*>("dicewareWidget"); + tabWidget->setCurrentWidget(dicewareWidget); - QCOMPARE(entropyLabel->text(), QString("Entropy: 77.55 bit")); - QCOMPARE(strengthLabel->text(), QString("Password Quality: Good")); + auto* comboBoxWordList = dicewareWidget->findChild<QComboBox*>("comboBoxWordList"); + comboBoxWordList->setCurrentText("eff_large.wordlist"); + auto* spinBoxWordCount = dicewareWidget->findChild<QSpinBox*>("spinBoxWordCount"); + spinBoxWordCount->setValue(6); + + // Confirm a password was generated + QVERIFY(!pwGeneratorWidget->getGeneratedPassword().isEmpty()); + + // Verify entropy and strength + auto* entropyLabel = pwGeneratorWidget->findChild<QLabel*>("entropyLabel"); + auto* strengthLabel = pwGeneratorWidget->findChild<QLabel*>("strengthLabel"); + + QCOMPARE(entropyLabel->text(), QString("Entropy: 77.55 bit")); + QCOMPARE(strengthLabel->text(), QString("Password Quality: Good")); + + QTest::mouseClick(generatedPassword, Qt::LeftButton); + QTest::keyClick(generatedPassword, Qt::Key_Escape);); } void TestGui::testTotp() @@ -864,8 +904,8 @@ void TestGui::testSearch() QTest::keyClick(searchTextEdit, Qt::Key_Down); QTRY_VERIFY(entryView->hasFocus()); auto* searchedEntry = entryView->currentEntry(); - // Restore focus and search text selection - QTest::keyClick(m_mainWindow.data(), Qt::Key_F, Qt::ControlModifier); + // Restore focus using F1 key and search text selection + QTest::keyClick(m_mainWindow.data(), Qt::Key_F1); QTRY_COMPARE(searchTextEdit->selectedText(), QString("someTHING")); QTRY_VERIFY(searchTextEdit->hasFocus()); @@ -882,6 +922,7 @@ void TestGui::testSearch() QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); QCOMPARE(searchedEntry->password(), clipboard->text()); // Ensure Down focuses on entry view when search text is selected + QTest::keyClick(searchTextEdit, Qt::Key_A, Qt::ControlModifier); QTest::keyClick(searchTextEdit, Qt::Key_Down); QTRY_VERIFY(entryView->hasFocus()); QCOMPARE(entryView->currentEntry(), searchedEntry); @@ -927,12 +968,14 @@ void TestGui::testSearch() searchWidget->setLimitGroup(false); clickIndex(rootGroupIndex, groupView, Qt::LeftButton); QCOMPARE(groupView->currentGroup(), m_db->rootGroup()); + QVERIFY(!m_dbWidget->isSearchActive()); // Try to edit the first entry from the search view // Refocus back to search edit QTest::mouseClick(searchTextEdit, Qt::LeftButton); QTRY_VERIFY(searchTextEdit->hasFocus()); - QVERIFY(m_dbWidget->isSearchActive()); + QTest::keyClicks(searchTextEdit, "someTHING"); + QTRY_VERIFY(m_dbWidget->isSearchActive()); QModelIndex item = entryView->model()->index(0, 1); Entry* entry = entryView->entryFromIndex(item); @@ -1173,6 +1216,35 @@ void TestGui::testSaveAs() tmpFile.remove(); } +void TestGui::testSaveBackup() +{ + m_db->metadata()->setName("testSaveBackup"); + + QFileInfo fileInfo(m_dbFilePath); + QDateTime lastModified = fileInfo.lastModified(); + + // open temporary file so it creates a filename + TemporaryFile tmpFile; + QVERIFY(tmpFile.open()); + QString tmpFileName = tmpFile.fileName(); + tmpFile.remove(); + + // wait for modified timer + QTRY_COMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("testSaveBackup*")); + + fileDialog()->setNextFileName(tmpFileName); + + triggerAction("actionDatabaseSaveBackup"); + + QCOMPARE(m_tabWidget->tabName(m_tabWidget->currentIndex()), QString("testSaveBackup*")); + + checkDatabase(tmpFileName); + + fileInfo.refresh(); + QCOMPARE(fileInfo.lastModified(), lastModified); + tmpFile.remove(); +} + void TestGui::testSave() { m_db->metadata()->setName("testSave"); @@ -1189,7 +1261,7 @@ void TestGui::testSave() void TestGui::testDatabaseSettings() { m_db->metadata()->setName("testDatabaseSettings"); - triggerAction("actionChangeDatabaseSettings"); + triggerAction("actionDatabaseSettings"); auto* dbSettingsDialog = m_dbWidget->findChild<QWidget*>("databaseSettingsDialog"); auto* transformRoundsSpinBox = dbSettingsDialog->findChild<QSpinBox*>("transformRoundsSpinBox"); auto advancedToggle = dbSettingsDialog->findChild<QCheckBox*>("advancedSettingsToggle"); @@ -1428,7 +1500,6 @@ int TestGui::addCannedEntries() auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget"); auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit"); auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit"); - auto* passwordRepeatEdit = editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit"); // Add entry "test" and confirm added QTest::mouseClick(entryNewWidget, Qt::LeftButton); @@ -1441,7 +1512,6 @@ int TestGui::addCannedEntries() QTest::mouseClick(entryNewWidget, Qt::LeftButton); QTest::keyClicks(titleEdit, "something 2"); QTest::keyClicks(passwordEdit, "something 2"); - QTest::keyClicks(passwordRepeatEdit, "something 2"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); ++entries_added; |