Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
/***************************************************************************
|
2026-04-13 18:55:09 +02:00
|
|
|
* Copyright (C) 2026 by Mudlet Developers *
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
* *
|
|
|
|
|
* 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. *
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Comprehensive tests for Host::resetProfile_phase1() / resetProfile_phase2().
|
|
|
|
|
* Covers temp item removal, permanent item survival, stopwatches, events,
|
|
|
|
|
* Lua state reinit, sysLoadEvent, flags, UI cleanup, two-phase correctness,
|
|
|
|
|
* ANSI colors, map survival, telnet connection, Geyser reload, double reset,
|
|
|
|
|
* and script event handler re-registration.
|
|
|
|
|
*
|
|
|
|
|
* The mudlet instance and profile are created once in initTestCase().
|
|
|
|
|
* Each test calls resetProfile() at the end (via cleanup()) to restore
|
|
|
|
|
* a clean state for the next test.
|
|
|
|
|
*
|
|
|
|
|
* Run with: ctest -R ResetProfileTest -V
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <QtTest/QtTest>
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
#include <chrono>
|
2026-05-08 00:29:22 -04:00
|
|
|
#include <QMouseEvent>
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
|
|
|
|
|
#include "Host.h"
|
2026-07-25 20:25:26 +02:00
|
|
|
#include "LuaInterface.h"
|
Infrastructure: Swap out QtConcurrent module header for sub-module ones (#9246)
#### Brief overview of PR changes/additions
The Qt documentation for `QtConcurrent` points out:
> If you include the `<QtConcurrent>` header, the entire Qt Concurrent
module with the entire Qt Core module will be included, which may
increase compilation times and binary sizes. To use individual functions
from the QtConcurrent namespace, you can include more specific headers.
>
> The table below lists the functions in the QtConcurrent namespace and
their corresponding headers:
|Function|Header|
|--------|------|
|`QtConcurrent::run()`|`<QtConcurrentRun>`|
|`QtConcurrent::task()`| `<QtConcurrentTask>`|
|`QtConcurrent::filter()`,<br>`QtConcurrent::filtered()`,<br>`QtConcurrent::filteredReduced()`|`<QtConcurrentFilter>`|
|`QtConcurrent::map()`,<br>`QtConcurrent::mapped()`,<br>`QtConcurrent::mappedReduced()`|`<QtConcurrentMap>`|
#### Motivation for adding to Mudlet
To speed up the build a little by removing stuff that isn't needed.
#### Other info (issues closed, discussion etc)
In doing this I happened to start cleaning up a couple of header files
`T2DMap.h` and then `mudlet.h`, I then got into converting some
`#include`s into forward declarations in a "include-what-you-use" move.
This then rippled through into a (more than 10!) number of files but
should "improve" things.
Note that the ordering of `#include` in many files seems to be rather
haphazard and is due for some serious overhaul - I suggest that we
should actually declare an "official" style for this project so that
everyone knows what it is.
**During the CI/CB process I discovered that Linux and then MacOS builds
were failing because the file referred to by the `#include
<QtConcurrentTask>` header file was missing, yet was present on my local
PC when I was using the Qt framework from the On-line installer.
Initially I suspected a Debian (and then Devuan - as the packaged
version on my own machine also had this defect AND Ubuntu) package
problem; however it now seems to be an upstream Qt issue as the various
Qt versions & OS combinations suggest that Qt themselves fixed it for Qt
6.10:**
| OS | QtVersion | Missing header |
|--------|-----------------------|----------------|
| Windows| 6.11.0 package | No |
| Devuan | 6.8.2 package | Yes |
| Devuan | 6.10.0 online install | No |
| Ubuntu | 6.9.0 package | Yes |
| Debian | 6.8.2 package | Yes |
| MacOS | 6.9.0 package | Yes |
**To fix this I reverted to an `#include <qtconcurrenttask.h>` for Linux
and MacOS builds - although it would probably have been better to make
it conditional on the Qt Version instead...**
*I have reported this upstream to Debian - see:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1135197*
---------
Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2026-04-29 13:35:29 +01:00
|
|
|
#include "MudletInstanceCoordinator.h"
|
2026-04-13 18:55:09 +02:00
|
|
|
#include "TEvent.h"
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
#include "TKey.h"
|
2026-05-08 00:29:22 -04:00
|
|
|
#include "TLabel.h"
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
#include "TLuaInterpreter.h"
|
|
|
|
|
#include "TMainConsole.h"
|
|
|
|
|
#include "TMap.h"
|
|
|
|
|
#include "TRoomDB.h"
|
|
|
|
|
#include "TScript.h"
|
|
|
|
|
#include "TTimer.h"
|
|
|
|
|
#include "TTrigger.h"
|
2026-07-25 20:25:26 +02:00
|
|
|
#include "TVar.h"
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
#include "TelnetServerStub.h"
|
2026-07-25 20:25:26 +02:00
|
|
|
#include "VarUnit.h"
|
|
|
|
|
#include "XMLexport.h"
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
#include "ctelnet.h"
|
|
|
|
|
#include "dlgConnectionProfiles.h"
|
|
|
|
|
#include "mudlet.h"
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
#if defined(INCLUDE_VERSIONED_LUA_HEADERS)
|
|
|
|
|
#include <lua5.1/lauxlib.h>
|
|
|
|
|
#include <lua5.1/lua.h>
|
|
|
|
|
#include <lua5.1/lualib.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <lauxlib.h>
|
|
|
|
|
#include <lua.h>
|
|
|
|
|
#include <lualib.h>
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
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 initializeQRCResourcesForResetProfileTest();
|
|
|
|
|
|
|
|
|
|
class ResetProfileTest : public QObject {
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
TelnetServerStub *mpServer = nullptr;
|
|
|
|
|
Host *mpHost = nullptr;
|
|
|
|
|
const QString mHostname = "ResetProfile-Test";
|
2026-07-20 09:01:51 +02:00
|
|
|
QString mPort; // assigned the stub's actual ephemeral port in initTestCase()
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
const QString mLocalhost = "localhost";
|
|
|
|
|
|
|
|
|
|
void performReset() {
|
|
|
|
|
mpHost->resetProfile_phase1();
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int countTempTriggers() {
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (auto *trigger : mpHost->getTriggerUnit()->getTriggerRootNodeList()) {
|
|
|
|
|
if (trigger->isTemporary()) {
|
|
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int countTempKeys() {
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (auto *key : mpHost->getKeyUnit()->getKeyRootNodeList()) {
|
|
|
|
|
if (key->isTemporary()) {
|
|
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void initTestCase() {
|
|
|
|
|
initializeQRCResourcesForResetProfileTest();
|
|
|
|
|
|
|
|
|
|
mpServer = new TelnetServerStub(qApp);
|
2026-07-20 09:01:51 +02:00
|
|
|
mpServer->start(mLocalhost, 0); // ephemeral OS-assigned port avoids collisions across concurrent test runs
|
|
|
|
|
mPort = QString::number(mpServer->serverPort());
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
mudlet::start();
|
|
|
|
|
mudlet::self()->setupConfig();
|
|
|
|
|
mudlet::self()->takeOwnershipOfInstanceCoordinator(
|
|
|
|
|
std::make_unique<MudletInstanceCoordinator>(
|
|
|
|
|
"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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Per-test cleanup: reset the profile so each test starts from clean state.
|
|
|
|
|
// Tests that exercise resetProfile() themselves may leave the profile already
|
|
|
|
|
// reset, which is fine — a second reset is harmless.
|
|
|
|
|
void cleanup() {
|
|
|
|
|
if (mpHost && !mpHost->mResetProfile) {
|
|
|
|
|
performReset();
|
|
|
|
|
} else if (mpHost && mpHost->mResetProfile) {
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 1: Temporary Item Removal (#761)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_tempTriggersRemovedAfterReset() {
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
// preinstalled packages (the starter UI) register their own temp triggers
|
|
|
|
|
// and re-register them when the profile comes back, so the count after a
|
|
|
|
|
// reset returns to that baseline rather than zero
|
|
|
|
|
const int baseline = countTempTriggers();
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
int id = mpHost->mLuaInterpreter.startTempTrigger(qsl("test_pattern"),
|
|
|
|
|
qsl(""), -1);
|
|
|
|
|
QVERIFY(id > 0);
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
QVERIFY(countTempTriggers() > baseline);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
QCOMPARE(countTempTriggers(), baseline);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_tempAliasesRemovedAfterReset() {
|
|
|
|
|
int id =
|
|
|
|
|
mpHost->mLuaInterpreter.startTempAlias(qsl("^test_alias$"), qsl(""));
|
|
|
|
|
QVERIFY(id > 0);
|
|
|
|
|
QVERIFY(mpHost->getAliasUnit()->getAlias(id) != nullptr);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
// Our specific temp alias should be gone (Lua scripts may create their own
|
|
|
|
|
// via sysLoadEvent)
|
|
|
|
|
QVERIFY2(mpHost->getAliasUnit()->getAlias(id) == nullptr,
|
|
|
|
|
"Temp alias should be removed after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_tempTimersRemovedAfterReset() {
|
|
|
|
|
auto result = mpHost->mLuaInterpreter.startTempTimer(60.0, qsl(""));
|
|
|
|
|
int id = result.first;
|
|
|
|
|
QVERIFY(id > 0);
|
|
|
|
|
QVERIFY(mpHost->getTimerUnit()->getTimer(id) != nullptr);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(mpHost->getTimerUnit()->getTimer(id) == nullptr,
|
|
|
|
|
"Temp timer should be removed after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_tempKeysRemovedAfterReset() {
|
|
|
|
|
int modifier = Qt::NoModifier;
|
|
|
|
|
int keycode = Qt::Key_F12;
|
|
|
|
|
int id = mpHost->mLuaInterpreter.startTempKey(modifier, keycode, qsl(""));
|
|
|
|
|
QVERIFY(id > 0);
|
|
|
|
|
QVERIFY(countTempKeys() > 0);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QCOMPARE(countTempKeys(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 2: Permanent Item Survival
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_permanentTriggerSurvivesReset() {
|
|
|
|
|
QStringList patterns;
|
|
|
|
|
patterns << qsl("perm_test_pattern");
|
|
|
|
|
auto [id, msg] = mpHost->mLuaInterpreter.startPermSubstringTrigger(
|
|
|
|
|
qsl("perm_trigger"), qsl(""), patterns, qsl(""));
|
|
|
|
|
QVERIFY2(id > 0, qPrintable(msg));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (auto *trigger : mpHost->getTriggerUnit()->getTriggerRootNodeList()) {
|
|
|
|
|
if (trigger->getID() == id) {
|
|
|
|
|
found = true;
|
|
|
|
|
QVERIFY(trigger->isActive());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(found, "Permanent trigger not found after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_permanentAliasSurvivesReset() {
|
|
|
|
|
auto [id, msg] = mpHost->mLuaInterpreter.startPermAlias(
|
|
|
|
|
qsl("perm_alias"), qsl(""), qsl("^perm_test$"), qsl(""));
|
|
|
|
|
QVERIFY2(id > 0, qPrintable(msg));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (auto *alias : mpHost->getAliasUnit()->getAliasRootNodeList()) {
|
|
|
|
|
if (alias->getID() == id) {
|
|
|
|
|
found = true;
|
|
|
|
|
QVERIFY(alias->isActive());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(found, "Permanent alias not found after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_permanentTimerSurvivesReset() {
|
|
|
|
|
auto [id, msg] = mpHost->mLuaInterpreter.startPermTimer(
|
|
|
|
|
qsl("perm_timer"), qsl(""), 300.0, qsl(""));
|
|
|
|
|
QVERIFY2(id > 0, qPrintable(msg));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (auto *timer : mpHost->getTimerUnit()->getTimerRootNodeList()) {
|
|
|
|
|
if (timer->getID() == id) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(found, "Permanent timer not found after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 3: Stopwatch Handling (#4715)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_nonPersistentStopWatchRemovedAfterReset() {
|
|
|
|
|
mpHost->mBlockStopWatchCreation = false;
|
|
|
|
|
auto result = mpHost->createStopWatch(qsl("test_sw"));
|
|
|
|
|
int id = result.first;
|
|
|
|
|
QVERIFY2(id > 0, qPrintable(result.second));
|
|
|
|
|
QVERIFY(mpHost->getStopWatch(id) != nullptr);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(mpHost->getStopWatch(id) == nullptr,
|
|
|
|
|
"Non-persistent stopwatch should be removed after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_persistentStopWatchSurvivesReset() {
|
|
|
|
|
mpHost->mBlockStopWatchCreation = false;
|
|
|
|
|
auto result = mpHost->createStopWatch(qsl("persistent_sw"));
|
|
|
|
|
int id = result.first;
|
|
|
|
|
QVERIFY2(id > 0, qPrintable(result.second));
|
|
|
|
|
mpHost->makeStopWatchPersistent(id, true);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
auto *sw = mpHost->getStopWatch(id);
|
|
|
|
|
QVERIFY2(sw != nullptr, "Persistent stopwatch should survive reset");
|
|
|
|
|
QVERIFY(sw->persistent());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_stopWatchCreationBlockedDuringReset() {
|
|
|
|
|
mpHost->mBlockStopWatchCreation = false;
|
|
|
|
|
|
|
|
|
|
mpHost->resetProfile_phase1();
|
|
|
|
|
// mResetProfile is now true — stopwatch creation should be blocked
|
|
|
|
|
auto result = mpHost->createStopWatch(qsl("blocked_sw"));
|
|
|
|
|
QCOMPARE(result.first, 0);
|
|
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
|
|
|
|
|
// After phase2, creation should work again
|
|
|
|
|
mpHost->mBlockStopWatchCreation = false;
|
|
|
|
|
auto result2 = mpHost->createStopWatch(qsl("unblocked_sw"));
|
|
|
|
|
QVERIFY2(result2.first > 0,
|
|
|
|
|
"Stopwatch creation should work after reset completes");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 4: Event System Cleanup (#4970, #7698)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_eventHandlerMapClearedAfterReset() {
|
|
|
|
|
mpHost->mEventHandlerMap[qsl("testEvent")] = QList<TScript *>();
|
|
|
|
|
QVERIFY(!mpHost->mEventHandlerMap.isEmpty());
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
// mEventHandlerMap is cleared, then repopulated by compileAll
|
|
|
|
|
// re-registering script handlers. Our manually-inserted "testEvent" entry
|
|
|
|
|
// should be gone.
|
|
|
|
|
QVERIFY2(!mpHost->mEventHandlerMap.contains(qsl("testEvent")),
|
|
|
|
|
"Manually inserted event handler should be cleared after reset");
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
void test_anonymousEventHandlersClearedAfterReset() {
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(
|
|
|
|
|
L, "function anonHandlerTestFunc() anonHandlerCalled = true end");
|
|
|
|
|
mpHost->registerAnonymousEventHandler(qsl("testAnonymousEvent"),
|
|
|
|
|
qsl("anonHandlerTestFunc"));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
// The Lua function no longer exists in the new state
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
lua_State *newL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
lua_getglobal(newL, "anonHandlerTestFunc");
|
|
|
|
|
QVERIFY2(lua_isnil(newL, -1), "Lua function referenced by anonymous "
|
|
|
|
|
"handler should not exist in new Lua state");
|
|
|
|
|
lua_pop(newL, 1);
|
2026-04-13 18:55:09 +02:00
|
|
|
|
|
|
|
|
// Raise the event - if the anonymous handler map was properly cleared,
|
|
|
|
|
// this won't attempt to call the now-nonexistent function
|
|
|
|
|
TEvent event{};
|
|
|
|
|
event.mArgumentList.append(qsl("testAnonymousEvent"));
|
|
|
|
|
event.mArgumentTypeList.append(ARGUMENT_TYPE_STRING);
|
|
|
|
|
mpHost->raiseEvent(event);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 5: Lua State Reinitialization (#3692)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_luaCustomGlobalsClearedAfterReset() {
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(L);
|
|
|
|
|
luaL_dostring(L, "resetProfileTestGlobal = 42");
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "resetProfileTestGlobal");
|
|
|
|
|
QVERIFY(!lua_isnil(L, -1));
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *newL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
lua_getglobal(newL, "resetProfileTestGlobal");
|
|
|
|
|
QVERIFY2(lua_isnil(newL, -1),
|
|
|
|
|
"Custom Lua global should be gone after reset");
|
|
|
|
|
lua_pop(newL, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_luaStandardFunctionsAvailableAfterReset() {
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(L);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "assert");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1), "assert should be available after reset");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "pcall");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1), "pcall should be available after reset");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "string");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1),
|
|
|
|
|
"string library should be available after reset");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "table");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1),
|
|
|
|
|
"table library should be available after reset");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_luaStateIsNewAfterReset() {
|
2026-04-03 18:50:08 +02:00
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(L);
|
|
|
|
|
luaL_dostring(L, "resetTestSentinel = 42");
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *newL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(newL);
|
2026-04-03 18:50:08 +02:00
|
|
|
lua_getglobal(newL, "resetTestSentinel");
|
2026-04-13 18:55:09 +02:00
|
|
|
QVERIFY2(lua_isnil(newL, -1), "Lua state should be fresh after reset");
|
2026-04-03 18:50:08 +02:00
|
|
|
lua_pop(newL, 1);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 6: sysLoadEvent (#4779, #5005)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
void test_sysLoadEventFiredExactlyOnce() {
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
auto *pScript = new TScript(qsl("sysLoadEventCounter"), mpHost);
|
|
|
|
|
pScript->setScript(qsl("sysLoadCounter = (sysLoadCounter or 0) + 1"));
|
|
|
|
|
QStringList events;
|
|
|
|
|
events << qsl("sysLoadEvent");
|
|
|
|
|
pScript->setEventHandlerList(events);
|
|
|
|
|
mpHost->getScriptUnit()->registerScript(pScript);
|
|
|
|
|
pScript->setIsActive(true);
|
|
|
|
|
pScript->compile();
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
lua_getglobal(L, "sysLoadCounter");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1),
|
|
|
|
|
"sysLoadCounter should be set by the event handler");
|
|
|
|
|
int counter = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
QCOMPARE(counter, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 7: Flag Lifecycle
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_mResetProfileFlagLifecycle() {
|
|
|
|
|
QVERIFY2(!mpHost->mResetProfile,
|
|
|
|
|
"mResetProfile should be false before reset");
|
|
|
|
|
|
|
|
|
|
mpHost->resetProfile_phase1();
|
|
|
|
|
QVERIFY2(mpHost->mResetProfile,
|
|
|
|
|
"mResetProfile should be true after phase1");
|
|
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
QVERIFY2(!mpHost->mResetProfile,
|
|
|
|
|
"mResetProfile should be false after phase2");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_mBlockScriptCompileFalseAfterReset() {
|
|
|
|
|
mpHost->mBlockScriptCompile = true;
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(!mpHost->mBlockScriptCompile,
|
|
|
|
|
"mBlockScriptCompile should be false after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_mEmergencyStopNotSetDuringReset() {
|
|
|
|
|
QVERIFY2(!mpHost->mEmergencyStop,
|
|
|
|
|
"mEmergencyStop should be false before reset");
|
|
|
|
|
|
|
|
|
|
mpHost->resetProfile_phase1();
|
|
|
|
|
QVERIFY2(!mpHost->mEmergencyStop,
|
|
|
|
|
"mEmergencyStop should stay false during phase1 (phase1 calls "
|
|
|
|
|
"unit-level stop, not Host::stopAllTriggers)");
|
|
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
QVERIFY2(!mpHost->mEmergencyStop,
|
|
|
|
|
"mEmergencyStop should stay false after phase2");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 8: UI Cleanup
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_miniConsolesRemovedAfterReset() {
|
|
|
|
|
auto [ok, msg] =
|
|
|
|
|
mpHost->createMiniConsole(qsl("main"), qsl("test_mc"), 0, 0, 100, 100);
|
|
|
|
|
QVERIFY2(ok, qPrintable(msg));
|
|
|
|
|
QVERIFY(mpHost->mpConsole->mSubConsoleMap.contains(qsl("test_mc")));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(!mpHost->mpConsole->mSubConsoleMap.contains(qsl("test_mc")),
|
|
|
|
|
"Mini console should be removed after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_labelsRemovedAfterReset() {
|
|
|
|
|
auto [ok, msg] = mpHost->createLabel(qsl("main"), qsl("test_label"), 0, 0,
|
|
|
|
|
100, 100, true, false);
|
|
|
|
|
QVERIFY2(ok, qPrintable(msg));
|
|
|
|
|
QVERIFY(mpHost->mpConsole->mLabelMap.contains(qsl("test_label")));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(!mpHost->mpConsole->mLabelMap.contains(qsl("test_label")),
|
|
|
|
|
"Label should be removed after reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 9: Two-Phase Correctness
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_phase2RunsDeferredNotImmediate() {
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
const int baseline = countTempTriggers();
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
int triggerId = mpHost->mLuaInterpreter.startTempTrigger(
|
|
|
|
|
qsl("deferred_test"), qsl(""), -1);
|
|
|
|
|
QVERIFY(triggerId > 0);
|
|
|
|
|
|
|
|
|
|
mpHost->resetProfile_phase1();
|
|
|
|
|
|
|
|
|
|
// Phase2 has NOT run yet
|
|
|
|
|
QVERIFY2(mpHost->mResetProfile,
|
|
|
|
|
"mResetProfile should be true before processEvents");
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
QVERIFY2(countTempTriggers() > baseline,
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
"Temp triggers should still exist before processEvents");
|
|
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(!mpHost->mResetProfile,
|
|
|
|
|
"mResetProfile should be false after processEvents");
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
QCOMPARE(countTempTriggers(), baseline);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 10: ANSI Color Table
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_ansiColorTableUpdatedAfterReset() {
|
|
|
|
|
mpHost->mBlack = QColor(10, 20, 30);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(L);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "color_table");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1), "color_table should exist after reset");
|
|
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "ansi_000");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1), "color_table.ansi_000 should exist");
|
|
|
|
|
|
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
|
int r = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_rawgeti(L, -1, 2);
|
|
|
|
|
int g = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_rawgeti(L, -1, 3);
|
|
|
|
|
int b = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
|
|
QCOMPARE(r, 10);
|
|
|
|
|
QCOMPARE(g, 20);
|
|
|
|
|
QCOMPARE(b, 30);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 11: Map System Survival
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_mapDataSurvivesReset() {
|
|
|
|
|
QVERIFY(mpHost->mpMap);
|
|
|
|
|
int roomId = mpHost->mpMap->createNewRoomID();
|
|
|
|
|
QVERIFY(roomId > 0);
|
|
|
|
|
QVERIFY(mpHost->mpMap->addRoom(roomId));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(mpHost->mpMap, "TMap pointer should survive reset");
|
|
|
|
|
auto *room = mpHost->mpMap->mpRoomDB->getRoom(roomId);
|
|
|
|
|
QVERIFY2(room != nullptr, "Room added before reset should still exist");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 12: Telnet Connection Survives
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_telnetConnectionSurvivesReset() {
|
|
|
|
|
auto stateBefore = mpHost->mTelnet.getConnectionState();
|
|
|
|
|
QCOMPARE(stateBefore, QAbstractSocket::ConnectedState);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
auto stateAfter = mpHost->mTelnet.getConnectionState();
|
|
|
|
|
QCOMPARE(stateAfter, QAbstractSocket::ConnectedState);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 13: Geyser/LuaGlobal Framework Reload
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_geyserFrameworkAvailableAfterReset() {
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(L);
|
|
|
|
|
|
|
|
|
|
lua_getglobal(L, "Geyser");
|
|
|
|
|
QVERIFY2(!lua_isnil(L, -1),
|
|
|
|
|
"Geyser framework should be loaded after reset");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_gmcpTableFreshAfterReset() {
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(L, "gmcp.testField = 'stale_data'");
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
lua_State *newL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
lua_getglobal(newL, "gmcp");
|
|
|
|
|
QVERIFY2(!lua_isnil(newL, -1), "gmcp table should exist after reset");
|
|
|
|
|
|
|
|
|
|
lua_getfield(newL, -1, "testField");
|
|
|
|
|
QVERIFY2(lua_isnil(newL, -1),
|
|
|
|
|
"gmcp.testField should be nil after reset (fresh table)");
|
|
|
|
|
lua_pop(newL, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 14: Double Reset Safety
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
void test_doubleResetIsGuarded() {
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
const int baseline = countTempTriggers();
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
mpHost->mLuaInterpreter.startTempTrigger(qsl("double_reset_test"), qsl(""),
|
|
|
|
|
-1);
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(L, "doubleResetSentinel = 99");
|
|
|
|
|
|
|
|
|
|
// Call phase1 twice - the second call should be a no-op
|
|
|
|
|
QVERIFY2(mpHost->resetProfile_phase1(),
|
|
|
|
|
"First resetProfile_phase1() should succeed");
|
|
|
|
|
QVERIFY2(!mpHost->resetProfile_phase1(),
|
|
|
|
|
"Second resetProfile_phase1() should be guarded");
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
|
2026-04-13 18:55:09 +02:00
|
|
|
// Verify reset actually happened by checking the Lua state is fresh
|
|
|
|
|
lua_State *afterL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
QVERIFY(afterL);
|
|
|
|
|
lua_getglobal(afterL, "doubleResetSentinel");
|
|
|
|
|
QVERIFY2(lua_isnil(afterL, -1), "Lua state should be fresh after reset");
|
|
|
|
|
lua_pop(afterL, 1);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QVERIFY2(!mpHost->mResetProfile,
|
2026-04-13 18:55:09 +02:00
|
|
|
"mResetProfile should be false after reset");
|
add: starter interface with health bars, map and chat for new players (#9454)
#### Brief overview of PR changes/additions
- New "Mudlet base UI" package auto-installed for new players on every
game: adjustable right-side dock with map (placeholder until the game is
mapped), tabbed chat (All/Tells/Channels with unread badges) and themed
HP/MP/MV/XP gauges - only ever built from data the game actually
provides
- Chat capture: GMCP Comm.Channel.Text when available, otherwise a
generic additive trigger layer (line shapes distilled from an audit of
all 216 packages in the Mudlet package repository); nothing is ever
gagged, and the trigger layer retires itself the moment GMCP chat
appears
- Vitals ladder for the gauges: GMCP (several dialect spellings) > MSDP
(negotiated automatically) > self-sufficient prompts (labeled cur/max or
percents) > score-screen harvesting; when a prompt only shows bare
currents, Mudlet sends `score` once - visibly, with an announcement - to
learn the maxima. Maxima are never guessed. An enemy-health bar appears
during fights on games that report it
- `baseui hide` / `baseui show` opt-out persists across restarts;
first-run announcement defers to the UI tour; experienced players never
get the package
- Plays nice with games that provide their own interface: profiles for
games whose bundled loader installs the game's official UI (flagged in
TGameDetails: Carrion Fields, Icesus, MorgenGrauen, Medievia) skip the
starter UI entirely, and when a game pushes a `Client.GUI` package the
starter UI quietly stands aside (via the new `sysServerGuiInstalled`
event) - `baseui show` brings it back for players who prefer it
- `docs/package-capture-audits/` records the chat + vitals capture
audits (with provenance) behind the design
#### Motivation for adding to Mudlet
New players currently get a bare text screen; this gives every game -
GMCP-rich, MSDP-only or plain telnet - an immediate, honest starter UI
out of the box.
#### Other info (issues closed, discussion etc)
Progresses #3071 and #3070 (phase 1 - not closing them).
**Test case:** Fresh install → create a profile for any game → connect.
On GMCP/MSDP games the dock builds with ticking gauges and tabbed chat;
on a game whose prompt carries cur/max values, gauges appear once the
prompt repeats; on a bare-number prompt, `score` is sent once
(announced) to size the gauges; on pure chat games, tells/says/channels
are captured with no gauges invented. `baseui hide` removes it and
survives restart.
https://github.com/user-attachments/assets/56d207cc-5bad-4464-867c-1a810d41cf2f
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
2026-07-26 08:43:21 +02:00
|
|
|
QCOMPARE(countTempTriggers(), baseline);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 15: Script Recompilation and Event Handler Re-registration
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void test_permanentScriptEventHandlerReregisteredAfterReset() {
|
|
|
|
|
const QString eventName = qsl("customResetTestEvent");
|
|
|
|
|
|
|
|
|
|
auto *pScript = new TScript(qsl("eventHandlerScript"), mpHost);
|
|
|
|
|
pScript->setScript(qsl("-- handler for customResetTestEvent"));
|
|
|
|
|
QStringList events;
|
|
|
|
|
events << eventName;
|
|
|
|
|
pScript->setEventHandlerList(events);
|
|
|
|
|
mpHost->getScriptUnit()->registerScript(pScript);
|
|
|
|
|
pScript->setIsActive(true);
|
|
|
|
|
pScript->compile();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(mpHost->mEventHandlerMap.contains(eventName),
|
|
|
|
|
"Event handler should be registered before reset");
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
QVERIFY2(
|
|
|
|
|
mpHost->mEventHandlerMap.contains(eventName),
|
|
|
|
|
"Event handler should be re-registered after reset via compileAll");
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-08 00:29:22 -04:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 16: Lua Registry Corruption (TLabel destructor timing)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// PR #9141 added a TLabel destructor that frees its 7 callback indices
|
|
|
|
|
// via luaL_unref. resetMainConsole() destroys labels via deleteLater(),
|
|
|
|
|
// so without an explicit drain those destructors fire AFTER phase2 has
|
|
|
|
|
// swapped in a new Lua state via initLuaGlobals(). The luaL_unref calls
|
|
|
|
|
// then write into the new state's registry — any slots already populated
|
|
|
|
|
// by compileAll() during the same phase2 (e.g. Adjustable.Container's
|
|
|
|
|
// many label callbacks) get overwritten with freelist-chain numbers,
|
|
|
|
|
// surfacing as "attempt to call a number value" the first time the user
|
|
|
|
|
// hovers a label.
|
|
|
|
|
//
|
|
|
|
|
// The fix in Host::resetProfile_phase2() drains DeferredDelete events
|
|
|
|
|
// between resetMainConsole() and initLuaGlobals(), so the old destructors
|
|
|
|
|
// run their unrefs against the still-live original state. This test
|
|
|
|
|
// reproduces the conditions: a script that creates many labels with
|
|
|
|
|
// click callbacks at top level, so compileAll re-executes it during
|
|
|
|
|
// phase2 and populates the new registry with the exact slot indices the
|
|
|
|
|
// queued old destructors would have corrupted.
|
|
|
|
|
void test_labelCallbacksWorkAfterResetWithManyLabels() {
|
|
|
|
|
const int kNumLabels = 50;
|
|
|
|
|
|
|
|
|
|
auto *pScript = new TScript(qsl("labelCallbackRegressionScript"), mpHost);
|
|
|
|
|
pScript->setScript(qsl("labelCallbackHits = 0\n"
|
|
|
|
|
"for i = 1, %1 do\n"
|
|
|
|
|
" local n = 'cb_label_'..i\n"
|
|
|
|
|
" createLabel(n, 0, 0, 10, 10, true)\n"
|
|
|
|
|
" setLabelClickCallback(n, function()\n"
|
|
|
|
|
" labelCallbackHits = labelCallbackHits + 1\n"
|
|
|
|
|
" end)\n"
|
|
|
|
|
"end\n")
|
|
|
|
|
.arg(kNumLabels));
|
|
|
|
|
mpHost->getScriptUnit()->registerScript(pScript);
|
|
|
|
|
pScript->setIsActive(true);
|
|
|
|
|
pScript->compile();
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
// Force any DeferredDelete events still pending after phase2 to fire
|
|
|
|
|
// before we trigger callbacks. With the fix, phase2 already drained
|
|
|
|
|
// them; without the fix, this is when corruption would land.
|
|
|
|
|
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i <= kNumLabels; ++i) {
|
|
|
|
|
auto *pL = mpHost->mpConsole->mLabelMap.value(qsl("cb_label_%1").arg(i));
|
|
|
|
|
QVERIFY2(pL, qPrintable(qsl("post-reset label cb_label_%1 missing").arg(i)));
|
|
|
|
|
QMouseEvent ev(QEvent::MouseButtonPress, QPointF(1, 1), QPointF(1, 1),
|
|
|
|
|
QPointF(1, 1), Qt::LeftButton, Qt::LeftButton,
|
|
|
|
|
Qt::NoModifier);
|
|
|
|
|
QCoreApplication::sendEvent(pL, &ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
lua_getglobal(L, "labelCallbackHits");
|
|
|
|
|
QVERIFY2(lua_isnumber(L, -1),
|
|
|
|
|
"labelCallbackHits should be a number after firing callbacks");
|
|
|
|
|
int hits = lua_tointeger(L, -1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
QCOMPARE(hits, kNumLabels);
|
|
|
|
|
|
|
|
|
|
// Neutralize the script so it doesn't keep recreating labels in
|
|
|
|
|
// subsequent tests' compileAll passes.
|
|
|
|
|
pScript->setScript(qsl(""));
|
|
|
|
|
pScript->setIsActive(false);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-25 20:25:26 +02:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Group 17: VarUnit saved/hidden variable bookkeeping (#9430 follow-up)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// The VarUnit's savedVars/hiddenByUser sets are name-keyed and independent
|
|
|
|
|
// of the lua_State (VarUnit::clear() deliberately preserves them), and
|
|
|
|
|
// nothing repopulates them after a reset - only XMLimport at profile open
|
|
|
|
|
// does. If replacing the LuaInterface in resetProfile_phase2() loses them,
|
|
|
|
|
// the first profile save after a reset silently drops every user-saved
|
|
|
|
|
// variable and hidden-variable preference from the profile XML.
|
|
|
|
|
void test_savedAndHiddenVarSetsSurviveReset() {
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(L, "resetSavedTestVar = 'important'");
|
|
|
|
|
|
|
|
|
|
LuaInterface *lI = mpHost->getLuaInterface();
|
|
|
|
|
VarUnit *vu = lI->getVarUnit();
|
|
|
|
|
lI->getVars(false);
|
|
|
|
|
TVar *var = findGlobalVar(vu, qsl("resetSavedTestVar"));
|
|
|
|
|
QVERIFY2(var, "test variable not found in the variable tree");
|
|
|
|
|
// as the Variables view does when the user ticks the save checkbox:
|
|
|
|
|
vu->addSavedVar(var);
|
|
|
|
|
// and as it does when the user hides a variable:
|
|
|
|
|
vu->addHidden(qsl("resetHiddenTestVar"));
|
|
|
|
|
QVERIFY(vu->savedVars.contains(qsl("resetSavedTestVar")));
|
|
|
|
|
QVERIFY(vu->hiddenByUser.contains(qsl("resetHiddenTestVar")));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
VarUnit *newVu = mpHost->getLuaInterface()->getVarUnit();
|
|
|
|
|
QVERIFY2(newVu->savedVars.contains(qsl("resetSavedTestVar")),
|
|
|
|
|
"user's saved-variable marking should survive resetProfile()");
|
|
|
|
|
QVERIFY2(newVu->hiddenByUser.contains(qsl("resetHiddenTestVar")),
|
|
|
|
|
"user's hidden-variable preference should survive resetProfile()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// End-to-end version of the above: the saved variable must still be
|
|
|
|
|
// written out to profile XML after a reset.
|
|
|
|
|
void test_savedVariableExportedToXmlAfterReset() {
|
|
|
|
|
lua_State *L = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(L, "xmlSavedTestVar = 'survives'");
|
|
|
|
|
|
|
|
|
|
LuaInterface *lI = mpHost->getLuaInterface();
|
|
|
|
|
VarUnit *vu = lI->getVarUnit();
|
|
|
|
|
lI->getVars(false);
|
|
|
|
|
TVar *var = findGlobalVar(vu, qsl("xmlSavedTestVar"));
|
|
|
|
|
QVERIFY2(var, "test variable not found in the variable tree");
|
|
|
|
|
vu->addSavedVar(var);
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
// the reset wiped the Lua value; user scripts recreate it on
|
|
|
|
|
// sysLoadEvent, and opening the Variables view rebuilds the tree
|
|
|
|
|
lua_State *newL = mpHost->mLuaInterpreter.getLuaGlobalState();
|
|
|
|
|
luaL_dostring(newL, "xmlSavedTestVar = 'survives'");
|
|
|
|
|
mpHost->getLuaInterface()->getVars(false);
|
|
|
|
|
|
|
|
|
|
const QString xmlPath =
|
|
|
|
|
mudlet::getMudletPath(enums::profileHomePath, mHostname) +
|
|
|
|
|
qsl("/reset-var-test.xml");
|
|
|
|
|
auto writer = std::make_shared<XMLexport>(mpHost);
|
|
|
|
|
QVERIFY(writer->exportPackage(xmlPath, true, false));
|
|
|
|
|
QFile file(xmlPath);
|
|
|
|
|
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
|
|
|
|
|
const QString xml = QString::fromUtf8(file.readAll());
|
|
|
|
|
file.close();
|
|
|
|
|
QFile::remove(xmlPath);
|
|
|
|
|
QVERIFY2(xml.contains(qsl("xmlSavedTestVar")),
|
|
|
|
|
"saved variable should still be exported to profile XML after "
|
|
|
|
|
"a reset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A fresh profile load runs hideMudletsVariables() right after
|
|
|
|
|
// loadGlobal() so the Variables view only shows the user's variables;
|
|
|
|
|
// a reset must do the same or the view fills up with Mudlet's entire
|
|
|
|
|
// internal Lua API.
|
|
|
|
|
void test_mudletInternalVariablesHiddenAfterReset() {
|
|
|
|
|
mpHost->hideMudletsVariables();
|
|
|
|
|
VarUnit *vu = mpHost->getLuaInterface()->getVarUnit();
|
|
|
|
|
QVERIFY(vu->hidden.contains(qsl("color_table")));
|
|
|
|
|
QVERIFY(vu->hidden.contains(qsl("Geyser")));
|
|
|
|
|
|
|
|
|
|
performReset();
|
|
|
|
|
|
|
|
|
|
VarUnit *newVu = mpHost->getLuaInterface()->getVarUnit();
|
|
|
|
|
QVERIFY2(newVu->hidden.contains(qsl("color_table")),
|
|
|
|
|
"Mudlet's internal variables should be re-hidden after reset, "
|
|
|
|
|
"as on profile load");
|
|
|
|
|
QVERIFY2(newVu->hidden.contains(qsl("Geyser")),
|
|
|
|
|
"Mudlet's internal variables should be re-hidden after reset, "
|
|
|
|
|
"as on profile load");
|
|
|
|
|
}
|
|
|
|
|
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Helpers (reused from TOscTerminatorTest pattern)
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
2026-07-25 20:25:26 +02:00
|
|
|
TVar *findGlobalVar(VarUnit *vu, const QString &name) {
|
|
|
|
|
for (auto *child : vu->getBase()->getChildren(false)) {
|
|
|
|
|
if (child->getName() == name) {
|
|
|
|
|
return child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
void startProfile(const QString &hostname, const QString &address,
|
|
|
|
|
const QString &port) {
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTimer::singleShot(0ms, qApp, [hostname, address, port]() {
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
mudlet::self()->startAutoLogin({});
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::mouseClick(mudlet::self()->mpConnectionDialog->new_profile_button,
|
|
|
|
|
Qt::LeftButton);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::keyClicks(QApplication::focusWidget(), hostname);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::keyClicks(QApplication::focusWidget(), address);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::keyClick(QApplication::focusWidget(), Qt::Key_Tab);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
QTest::keyClicks(QApplication::focusWidget(), port);
|
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions
Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:
- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`
This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.
#### Motivation for adding to Mudlet
Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.
All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).
#### Other info (issues closed, discussion etc)
Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.
Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
|
|
|
QTest::qWait(100ms);
|
Infrastructure: add comprehensive resetProfile() test suite (#9082)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Add 29 functional tests covering all aspects of Host::resetProfile():
temp item removal, permanent item survival, stopwatches, event system
cleanup, Lua state reinitialization, sysLoadEvent, flag lifecycle, UI
cleanup, two-phase correctness, ANSI colors, map survival, telnet
connection, Geyser/gmcp reload, double reset safety, and script event
handler re-registration.
Also fix qtkeychain include visibility (PRIVATE -> PUBLIC) so functional
tests can build from scratch.
#### Motivation for adding to Mudlet
resetProfile() seems simple, but is quite a complicated function to pull
off, and we haven't had any tests covering the functionality.
#### Other info (issues closed, discussion etc)
Also allows Geyser to be loaded in C++ tests, which it was not being
done before!
2026-04-02 11:33:38 +02:00
|
|
|
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.");
|
|
|
|
|
}
|
|
|
|
|
auto host = mudlet::self()->getActiveHost();
|
|
|
|
|
if (!host) {
|
|
|
|
|
QFAIL("No active host available for the test.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSignalSpy spy2(&(host->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()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dir.removeRecursively();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void initializeQRCResourcesForResetProfileTest() {
|
|
|
|
|
#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 "ResetProfileTest.moc"
|
|
|
|
|
QTEST_MAIN(ResetProfileTest)
|