#### Brief overview of PR changes/additions
- TelnetServerStub::sendRaw() now queues bytes sent before the server
has accepted the client connection and flushes them on accept, instead
of dropping them with only a warning
- Between sessions it still warns and drops, so a dead session's bytes
cannot leak into the next connection; the destructor reports bytes that
were never delivered
- The flush checks the write() return like the adjacent welcome-message
path
#### Motivation for adding to Mudlet
Tests only wait on the client-side connected signal, which can fire
before the stub's server side accepts - on fast runners the first
payload was lost, failing TelnetStringSequenceRecoveryTest twice in a
row on macOS arm64 in #9861's CI. The stub is shared by ~50 functional
tests.
#### Other info (issues closed, discussion etc)
First validated on #9861 (run 31674918225 failed twice on arm64; run
31687605776 with the fix went green on all four platforms); it will be
dropped from that PR once this merges.
**Test case:** TelnetStringSequenceRecoveryTest,
TriggerSameLineMatchTest and UndoServerWrapTest pass (run twice each
locally with the final version).
Assisted-by: Claude:claude-fable-5
#### 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
https://github.com/user-attachments/assets/49e8a176-899c-43fd-a931-6e04ab5b5efb
#### Brief overview of PR changes/additions
New opt-in profile option that rejoins lines the game hard-wrapped
itself, so triggers see the whole logical line and Mudlet's own wrapping
handles display. Enable in Settings → Main display, or
`setConfig("undoServerWrap", true)`. Prompts, blank lines, MXP `<br>`
and script-fed text never join, and prose/indentation gates keep ASCII
art, menus and tables intact. A one-time callout points the option out,
and games that look like they wrap raise a one-time hint with a
click-to-enable link.
#### Motivation for adding to Mudlet
On games that can't disable server-side wrapping, triggers need fragile
multiline patterns. This fixes it client-side - as far as we know, a
first among MUD clients.
#### Other info (issues closed, discussion etc)
Tests added.
---------
Signed-off-by: Vadim Peretokin <vadim.peretokin@mudlet.org>
#### Brief overview of PR changes/additions
- TelnetServerStub now binds an OS-assigned (ephemeral) port; its log
reports the actual bound port
- All 11 functional tests that hardcoded listen ports (three shared port
4000, two pairs shared 4003/4004) now read the real port back via
serverPort()
#### Motivation for adding to Mudlet
Concurrent test runs (parallel CI jobs, multiple checkouts on one
machine) collided on the fixed ports, causing flaky bind failures and
tests connecting to the wrong run's server.
#### Other info (issues closed, discussion etc)
Follows the pattern GMCPCharLoginTest already used. Verified by running
two copies of TelnetTextDisplayedTest simultaneously - both passed on
distinct ports (37503/42303), impossible before.
**Test case:** Run the functional suite twice in parallel (two build
dirs or ctest -j2 repeated); no "address already in use" failures.
Assisted-by: Claude:claude-opus-4-8
#### Brief overview of PR changes/additions
Skip Happy Eyeballs algorithm for localhost connections, using IPv4
directly instead.
#### Motivation for adding to Mudlet
Happy Eyeballs races IPv4 and IPv6 connections to find the fastest path
- unnecessary overhead for localhost where both work instantly.
#### Other info (issues closed, discussion etc)
**Test case:** Connect to a local server (e.g. `localhost:23`).
Connection should use IPv4 only instead of racing both protocols.
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Adds functional GUI tests simulating a user logging into a MUD via
Mudlet. A mock Telnet server sends messages then we verify the GUI
correctly receives and displays them.
For example, the test checks that a welcome message like:
```
QString messageFromTheMud("\x1B[1z<B>Greetings < hunters & sorcerers</B>\x1B[7z");
QString messageToExpect("Greetings < hunters & sorcerers");
```
is correctly parsed and displayed in the client.
#### Motivation for adding to Mudlet
Allows testing GUI behavior and Telnet messages, including malformed MXP
messages (https://github.com/Mudlet/Mudlet/issues/7896).
#### Other info (issues closed, discussion etc)
This also improves test coverage.
Command that I use:
`ctest --test-dir build/test -L functional --output-on-failure`