/*************************************************************************** * Copyright (C) 2026 by Vadim Peretokin - vadim.peretokin@mudlet.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /* * Functional tests for the trigger editor and its widgets. * * Run with: ctest -R TriggerEditorTest -V */ #include #include #include #include "MudletInstanceCoordinator.h" #include "SingleLineTextEdit.h" #include "TelnetServerStub.h" #include "dlgConnectionProfiles.h" #include "mudlet.h" using namespace std::chrono_literals; extern void qInitResources_mudlet(); extern void qInitResources_qm(); extern void qInitResources_additional_splash_screens(); extern void qInitResources_mudlet_fonts_common(); extern void qInitResources_mudlet_fonts_posix(); void initializeQRCResourcesForTriggerEditorTest(); class TriggerEditorTest : public QObject { Q_OBJECT private: TelnetServerStub *mpServer = nullptr; Host *mpHost = nullptr; const QString mHostname = "TriggerEditor-Test"; QString mPort; // assigned the stub's actual ephemeral port in initTestCase() const QString mLocalhost = "localhost"; void startProfile(const QString &hostname, const QString &address, const QString &port) { QTimer::singleShot(0ms, qApp, [hostname, address, port]() { mudlet::self()->startAutoLogin({}); QTest::qWait(100ms); QTest::mouseClick(mudlet::self()->mpConnectionDialog->new_profile_button, Qt::LeftButton); QTest::qWait(100ms); QTest::keyClicks(QApplication::focusWidget(), hostname); QTest::qWait(100ms); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab); QTest::qWait(100ms); QTest::keyClicks(QApplication::focusWidget(), address); QTest::qWait(100ms); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab); QTest::qWait(100ms); QTest::keyClicks(QApplication::focusWidget(), port); QTest::qWait(100ms); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Return); }); QSignalSpy spy(mudlet::self(), &mudlet::signal_profileLoaded); if (!spy.wait(1000)) { QFAIL("Profile took too long to load."); } mpHost = mudlet::self()->getActiveHost(); if (!mpHost) { QFAIL("No active host available."); } QSignalSpy spy2(&(mpHost->mTelnet), &cTelnet::signal_connected); if (!spy2.wait(500)) { QFAIL("Could not connect with the host."); } } void deleteProfileDirectory(const QString &profileName) { const QString path = mudlet::getMudletPath(enums::profileHomePath, profileName); QDir dir(path); if (dir.exists()) { dir.removeRecursively(); } } private slots: void initTestCase() { initializeQRCResourcesForTriggerEditorTest(); mpServer = new TelnetServerStub(qApp); mpServer->start(mLocalhost, 0); // ephemeral OS-assigned port avoids collisions across concurrent test runs mPort = QString::number(mpServer->serverPort()); mudlet::start(); mudlet::self()->setupConfig(); mudlet::self()->takeOwnershipOfInstanceCoordinator( std::make_unique( "MudletInstanceCoordinator")); mudlet::self()->init(); mudlet::self()->setStorePasswordsSecurely(false); deleteProfileDirectory(mHostname); startProfile(mHostname, mLocalhost, mPort); mpHost = mudlet::self()->getActiveHost(); QVERIFY2(mpHost, "No active host after profile creation"); } void cleanupTestCase() { mpHost = nullptr; delete mpServer; mpServer = nullptr; deleteProfileDirectory(mHostname); delete mudlet::self(); } // Verify that copying text from the pattern editor strips the middle dot // whitespace markers (U+00B7) that visualise leading/trailing spaces void test_copyFromPatternEditorStripsWhitespaceMarks() { const QChar middleDot(0x00B7); SingleLineTextEdit edit; // Simulate what markQString produces for " ^pattern$ " edit.setPlainText(QString("%1%1^pattern$%1%1").arg(middleDot)); // Select all and copy via keyboard shortcut edit.selectAll(); QTest::keyClick(&edit, Qt::Key_C, Qt::ControlModifier); const QClipboard *clipboard = QGuiApplication::clipboard(); QVERIFY(clipboard); const QString copied = clipboard->text(); QVERIFY2(!copied.contains(middleDot), "Copied text should not contain middle dot formatting marks"); QCOMPARE(copied, qsl(" ^pattern$ ")); } }; void initializeQRCResourcesForTriggerEditorTest() { #ifdef INCLUDE_VARIABLE_SPLASH_SCREEN qInitResources_additional_splash_screens(); #endif #ifdef INCLUDE_FONTS qInitResources_mudlet_fonts_common(); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) qInitResources_mudlet_fonts_posix(); #endif #endif qInitResources_mudlet(); qInitResources_qm(); } #include "TriggerEditorTest.moc" QTEST_MAIN(TriggerEditorTest)