#### Brief overview of PR changes/additions
- `ProfileLifecycleTest` (merged this morning in #9776) seeds
`$XDG_CONFIG_HOME/mudlet` without the `profiles/` subdirectory that
#9712 made the opt-in, so on any machine whose `~/.config/mudlet` holds
profiles it resolves to that instead and fails its own line 331
assertion. Reproduced here before the one-line fix. Its build legs all
finished on 10 Aug 13:52-14:55 UTC and #9712 merged at 22:17 that
evening, so it was merged 16 hours later on green CI that predates the
rule it breaks.
- `XdgRecipeConsistencyTest` stops the next one. It scans `test/*.cpp`
and `test/functional_tests/*.cpp` the way `CMakeListsConsistencyTest`
scans `src/`, and fails on a `mkpath()`/`mkdir()` whose argument spells
a path ending in `/mudlet` unless the file also creates the `profiles/`
opt-in. A test that means it says so with an `xdg-recipe-guard: allow`
comment.
- Comments, strings and raw strings are parsed out first, so a recipe in
prose is not code and an assertion against a `"%1/mudlet"` literal is
not a creation. The sweep reads this file too: its own fixtures spell
the stale recipe out inside string literals.
Test case: the sweep names `ProfileLifecycleTest.cpp:317` before the
fix, and both pre-#9810 files at lines 154 and 173 when those are
checked out of `8901b59d8`; the other 99 test sources are clean, and the
suite is 98/98 locally.
Assisted-by: Claude:claude-opus-5
#### Brief overview of PR changes/additions
- New `ProfileLifecycleTest` (18 test functions) covering the
profile-lifecycle Lua API the busted suite cannot reach, since busted
runs inside a single profile of an application it must leave standing:
`loadProfile`, `setActiveProfile`, `closeProfile`, `closeMudlet`, and
the cross-profile half of `raiseGlobalEvent`.
- Drives each function from a profile's own Lua state and checks the
application state that follows - host pool, tab, main console, active
profile, socket - not just the return value. Teardown is asserted with
`QPointer`s, so the closed profile's objects have to be genuinely gone.
- Runs against a `QTemporaryDir` config dir and an ephemeral stub port,
so it never touches the developer's own profiles and does not collide
with parallel test runs.
#### Motivation for adding to Mudlet
These five functions had no automated coverage at all. Between them they
disagree on almost every convention - `loadProfile`/`closeProfile`
refuse with `nil`, `setActiveProfile` with `false`; all three resolve
names case-insensitively; `raiseGlobalEvent` serialises its arguments to
strings and appends the sender - and none of that was pinned anywhere.
Bug found while writing it, not fixed here: `raiseGlobalEvent`'s
argument-type rejection is a `lua_error()`, which longjmps out of the C
function so the `TEvent` being filled in on the stack is never
destroyed. `raiseGlobalEvent('name', {})` leaks the arguments collected
before the bad one (170 bytes, confirmed under LeakSanitizer). The test
asserts the refusal with the argument-#1 form, which has collected
nothing yet; a comment marks the realistic form as untested until the
leak is fixed.
#### Other info (issues closed, discussion etc)
Coordinated with #9706 (fix-host-child-teardown): no overlap - that PR
covers notepad/IRC/toolbar teardown, this one the Lua API and the host
pool, and both insert into `test/functional_tests/CMakeLists.txt` at
different points.
**Test case:** `ctest -R ProfileLifecycleTest` - 18 tests, ~8s,
LeakSanitizer-checked; full functional suite 59/59 twice;
sabotage-verified by breaking `setActiveProfile`'s tab switch,
`raiseGlobalEvent`'s sender exclusion, `closeProfile`'s close request
and `loadProfile`'s offline flag - 6 of the 18 fail, and only those.
Assisted-by: Claude:claude-opus-5