Skip to content

Commit

Permalink
test: Add a login screen test for profile creation.
Browse files Browse the repository at this point in the history
One for success and one for failure.
  • Loading branch information
iphydf committed Jan 11, 2025
1 parent e891ce8 commit 4891a05
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 51 deletions.
25 changes: 15 additions & 10 deletions src/nexus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/model/status.h"
#include "src/persistence/profile.h"
#include "src/widget/style.h"
#include "src/widget/tool/imessageboxmanager.h"
#include "src/widget/widget.h"
#include "video/camerasource.h"
#include "widget/loginscreen.h"
Expand Down Expand Up @@ -58,7 +59,7 @@ Nexus::Nexus(Settings& settings_, IMessageBoxManager& messageBoxManager_,
, messageBoxManager{messageBoxManager_}
, ipc{ipc_}
{
QObject::connect(this, &Nexus::saveGlobal, &settings, &Settings::saveGlobal);
connect(this, &Nexus::saveGlobal, &settings, &Settings::saveGlobal);
}

Nexus::~Nexus()
Expand Down Expand Up @@ -170,7 +171,7 @@ int Nexus::showLogin(const QString& profileName)
// This is awkward because the core is in the profile
// The connection order ensures profile will be ready for bootstrap for now
connect(this, &Nexus::currentProfileChanged, this, &Nexus::bootstrapWithProfile);
int returnval = loginScreen.exec();
const int returnval = loginScreen.exec();
if (returnval == QDialog::Rejected) {
// Kriby: This will terminate the main application loop, necessary until we refactor
// away the split startup/return to login behavior.
Expand Down Expand Up @@ -201,17 +202,21 @@ void Nexus::connectLoginScreen(const LoginScreen& loginScreen)
// TODO(kriby): Move connect sequences to a controller class object instead

// Nexus -> LoginScreen
QObject::connect(this, &Nexus::profileLoaded, &loginScreen, &LoginScreen::onProfileLoaded);
QObject::connect(this, &Nexus::profileLoadFailed, &loginScreen, &LoginScreen::onProfileLoadFailed);
connect(this, &Nexus::profileLoaded, &loginScreen, &LoginScreen::onProfileLoaded);
connect(this, &Nexus::profileLoadFailed, &loginScreen, &LoginScreen::onProfileLoadFailed);
// LoginScreen -> Nexus
QObject::connect(&loginScreen, &LoginScreen::createNewProfile, this, &Nexus::onCreateNewProfile);
QObject::connect(&loginScreen, &LoginScreen::loadProfile, this, &Nexus::onLoadProfile);
connect(&loginScreen, &LoginScreen::createNewProfile, this, &Nexus::onCreateNewProfile);
connect(&loginScreen, &LoginScreen::loadProfile, this, &Nexus::onLoadProfile);
// LoginScreen -> Settings
QObject::connect(&loginScreen, &LoginScreen::autoLoginChanged, &settings, &Settings::setAutoLogin);
QObject::connect(&loginScreen, &LoginScreen::autoLoginChanged, &settings, &Settings::saveGlobal);
connect(&loginScreen, &LoginScreen::autoLoginChanged, &settings, &Settings::setAutoLogin);
connect(&loginScreen, &LoginScreen::autoLoginChanged, &settings, &Settings::saveGlobal);
// Settings -> LoginScreen
QObject::connect(&settings, &Settings::autoLoginChanged, &loginScreen,
&LoginScreen::onAutoLoginChanged);
connect(&settings, &Settings::autoLoginChanged, &loginScreen, &LoginScreen::onAutoLoginChanged);
// LoginScreen -> QMessageBox
connect(&loginScreen, &LoginScreen::failure, this,
[this](const QString& title, const QString& message) {
messageBoxManager.showError(title, message);
});
}

void Nexus::showMainGUI()
Expand Down
17 changes: 8 additions & 9 deletions src/widget/loginscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,27 +141,26 @@ void LoginScreen::onCreateNewProfile()
QString pass = ui->newPass->text();

if (name.isEmpty()) {
QMessageBox::critical(this, tr("Couldn't create a new profile"),
tr("The username must not be empty."));
emit failure(tr("Couldn't create a new profile"), tr("The username must not be empty."));
return;
}

if (pass.size() != 0 && pass.size() < 6) {
QMessageBox::critical(this, tr("Couldn't create a new profile"),
tr("The password must be at least 6 characters long."));
emit failure(tr("Couldn't create a new profile"),
tr("The password must be at least 6 characters long."));
return;
}

if (ui->newPassConfirm->text() != pass) {
QMessageBox::critical(this, tr("Couldn't create a new profile"),
tr("The passwords you've entered are different.\nPlease make sure to "
"enter the same password twice."));
emit failure(tr("Couldn't create a new profile"),
tr("The passwords you've entered are different.\n"
"Please make sure to enter the same password twice."));
return;
}

if (Profile::exists(name, paths)) {
QMessageBox::critical(this, tr("Couldn't create a new profile"),
tr("A profile with this name already exists."));
emit failure(tr("Couldn't create a new profile"),
tr("A profile with this name already exists."));
return;
}

Expand Down
1 change: 1 addition & 0 deletions src/widget/loginscreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class LoginScreen : public QDialog
void windowStateChanged(Qt::WindowStates states);
void autoLoginChanged(bool state);
void createNewProfile(QString name, const QString& pass);
void failure(const QString& title, const QString& message);
void loadProfile(QString name, const QString& pass);

public slots:
Expand Down
23 changes: 9 additions & 14 deletions src/widget/tool/messageboxmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,12 @@ bool MessageBoxManager::askQuestion(const QString& title, const QString& msg, co

void MessageBoxManager::confirmExecutableOpen(const QFileInfo& file)
{
static const QStringList dangerousExtensions = {"app", "bat", "com", "cpl", "dmg",
"exe", "hta", "jar", "js", "jse",
"lnk", "msc", "msh", "msh1", "msh1xml",
"msh2", "msh2xml", "mshxml", "msi", "msp",
"pif", "ps1", "ps1xml", "ps2", "ps2xml",
"psc1", "psc2", "py", "reg", "scf",
"sh", "src", "vb", "vbe", "vbs",
"ws", "wsc", "wsf", "wsh"};
static const QStringList dangerousExtensions = {
"app", "bat", "com", "cpl", "dmg", "exe", "hta", "jar", "js", "jse",
"lnk", "msc", "msh", "msh1", "msh1xml", "msh2", "msh2xml", "mshxml", "msi", "msp",
"pif", "ps1", "ps1xml", "ps2", "ps2xml", "psc1", "psc2", "py", "reg", "scf",
"sh", "src", "vb", "vbe", "vbs", "ws", "wsc", "wsf", "wsh",
};

if (dangerousExtensions.contains(file.suffix())) {
bool answer = askQuestion(tr("Executable file", "popup title"),
Expand All @@ -146,20 +144,17 @@ void MessageBoxManager::confirmExecutableOpen(const QFileInfo& file)
// Private implementations
void MessageBoxManager::_showInfo(const QString& title, const QString& msg)
{
QMessageBox messageBox(QMessageBox::Information, title, msg, QMessageBox::Ok, this);
messageBox.exec();
QMessageBox::information(this, title, msg);
}

void MessageBoxManager::_showWarning(const QString& title, const QString& msg)
{
QMessageBox messageBox(QMessageBox::Warning, title, msg, QMessageBox::Ok, this);
messageBox.exec();
QMessageBox::warning(this, title, msg);
}

void MessageBoxManager::_showError(const QString& title, const QString& msg)
{
QMessageBox messageBox(QMessageBox::Critical, title, msg, QMessageBox::Ok, this);
messageBox.exec();
QMessageBox::critical(this, title, msg);
}


Expand Down
File renamed without changes
Binary file added test/resources/images/loginscreen_ok.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion test/resources/test_data.qrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/test">
<file>images/loginscreen.png</file>
<file>images/loginscreen_empty.png</file>
<file>images/loginscreen_ok.png</file>
</qresource>
</RCC>
89 changes: 74 additions & 15 deletions test/widget/loginscreen_test.cpp
Original file line number Diff line number Diff line change
@@ -1,38 +1,97 @@
#include "src/widget/loginscreen.h"

#include <QDebug>
#include <QLineEdit>
#include <QProcessEnvironment>
#include <QPushButton>
#include <QTest>

#include "src/persistence/paths.h"
#include "src/widget/style.h"

namespace {
std::pair<QPixmap, QPixmap> compareScreenshot(QWidget* widget, const QString& path)
{
QPixmap actual = widget->grab();
const auto env = QProcessEnvironment::systemEnvironment();
if (env.contains("BUILD_WORKSPACE_DIRECTORY")) {
const QString actualPath = QStringLiteral("%1/qtox/test/resources/images/%2")
.arg(env.value("BUILD_WORKSPACE_DIRECTORY"), path);
qDebug() << "Saving actual image to" << actualPath;
actual.save(actualPath);
}
QPixmap expected = QPixmap(QStringLiteral(":/test/images/%1").arg(path));
return {std::move(actual), std::move(expected)};
}

#define COMPARE_GRAB(widget, path) \
do { \
const auto [actual, expected] = compareScreenshot(widget, path); \
if (!QTest::qCompare(actual, expected, #widget, path, __FILE__, __LINE__)) \
QTEST_FAIL_ACTION; \
} while (false)

} // namespace

class TestLoginScreen : public QObject
{
Q_OBJECT

private slots:
void testLoginScreen();
};
void testCreateProfile();
void testCreateProfileBadPassword();

void TestLoginScreen::testLoginScreen()
{
Paths paths;
private:
Paths paths{Paths::Portable::Portable};
Style style;
int themeColor = 0; // Default
QString profileName = "test-user";
};

void TestLoginScreen::testLoginScreen()
{
LoginScreen loginScreen(paths, style, themeColor, profileName);

const QPixmap actual = loginScreen.grab();
const auto env = QProcessEnvironment::systemEnvironment();
if (env.contains("BUILD_WORKSPACE_DIRECTORY")) {
const QString actualPath = QStringLiteral("%1/%2")
.arg(env.value("BUILD_WORKSPACE_DIRECTORY"))
.arg("qtox/test/resources/images/loginscreen.png");
qDebug() << "Saving actual image to" << actualPath;
actual.save(actualPath);
}
const QPixmap expected = QPixmap(":/test/images/loginscreen.png");
QCOMPARE(actual, expected);
COMPARE_GRAB(&loginScreen, "loginscreen_empty.png");
}

void TestLoginScreen::testCreateProfile()
{
LoginScreen loginScreen(paths, style, themeColor, profileName);

bool created = false;
QObject::connect(&loginScreen, &LoginScreen::createNewProfile, this,
[&created]() { created = true; });

loginScreen.findChild<QLineEdit*>("newUsername")->setText("test-user");
loginScreen.findChild<QLineEdit*>("newPass")->setText("password");
loginScreen.findChild<QLineEdit*>("newPassConfirm")->setText("password");
loginScreen.findChild<QPushButton*>("createAccountButton")->click();

QVERIFY(created);
COMPARE_GRAB(&loginScreen, "loginscreen_ok.png");
}

void TestLoginScreen::testCreateProfileBadPassword()
{
LoginScreen loginScreen(paths, style, themeColor, profileName);

bool created = false;
connect(&loginScreen, &LoginScreen::createNewProfile, this, [&created]() { created = true; });

QString error;
connect(&loginScreen, &LoginScreen::failure, this,
[&error](const QString& title, const QString& message) { error = message; });

loginScreen.findChild<QLineEdit*>("newUsername")->setText("test-user");
loginScreen.findChild<QLineEdit*>("newPass")->setText("password");
loginScreen.findChild<QLineEdit*>("newPassConfirm")->setText("password2");
QTest::mouseClick(loginScreen.findChild<QPushButton*>("createAccountButton"),
Qt::MouseButton::LeftButton);

QVERIFY(!created);
QVERIFY(error.contains("different"));
}

QTEST_MAIN(TestLoginScreen)
Expand Down
4 changes: 2 additions & 2 deletions translations/pr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ Share it with yer mateys ta start jawin&apos;.</translation>
</message>
<message>
<source>Load</source>
<translation type="unfinished">Bring it aboard</translation>
<translation>Bring aboard</translation>
</message>
<message>
<source>Load Profile</source>
Expand Down Expand Up @@ -1597,7 +1597,7 @@ Best make one.</translation>
</message>
<message>
<source>Import</source>
<translation type="unfinished">Bring from elsewhere</translation>
<translation>Recruit</translation>
</message>
<message>
<source>Username input field</source>
Expand Down

0 comments on commit 4891a05

Please sign in to comment.