Files
HellionChat/HellionChat/SelfTests
JonKazama-Hellion 64f48b1131 chore(release): close the v1.13.0 cycle
Version to 1.13.0 in the csproj, with the changelog and roadmap entries for the
local state. Not published: the public release stays at v1.5.6, repo.json keeps
its 1.5.6.0 manifest and all three download links are untouched.

The changelog leads with the screenshot-mode gap rather than with the typography,
because that is the part that changes what a user's own screenshots contain. An
auto-tell tab is named "Player@World", and three of the four surfaces that draw a
tab name had no rule about it -- so a picture of the default view named the
conversation partner while every message below it was anonymised. Anyone who has
shared a screenshot from an older build should know that.

Config version 26 is in there for the same reason. Its migration marks existing
tell tabs as partner-named, and it says plainly what it cannot do: a tab promoted
to permanent before this version keeps its name and loses every marker, so
nothing in the stored data says where that name came from.

Known issues carry the honest tail: the header recomputes its widths every frame
instead of on the status bar's tick, and all three font handles now rasterise the
full glyph range -- the cost of letting the channel name use the smaller face
without breaking on an umlaut.

The migration self-test asserts what v26 actually does now, rather than only that
the version number moved.
2026-08-19 17:34:49 +02:00
..

HellionChat SelfTest Standard

These steps run in-game via /xlperf. They are HellionChat's real test layer: Dalamud-coupled classes cannot be instantiated in an xUnit AppDomain, so the honest verification path is the running plugin, not a headless harness.

The render-path rule (binding for every step)

A SelfTest exists to catch a broken runtime path. To do that it MUST:

  1. ENTRY = the real runtime entry the game calls per frame or on the real action — HonorificHeader.Draw, ChunkRenderer.DrawChunks, InputBar.TrySend, Sidebar.Draw, MessageList.Draw, Lender<PayloadHandler>.Borrow(). NEVER a helper only the test calls.
  2. ASSERT observable state produced through that entry — a rendered or suppressed slot, a set flag, a held vs. sent message. Do NOT re-implement the helper's logic inside the test and assert against your own copy.
  3. Wire first. Where the real path does not yet call the correct helper, wiring it is part of the restoration work; the SelfTest verifies only after.

Reviewer trick (run before trusting any step)

For every helper a step calls:

grep -rn '<Helper>' HellionChat/ | grep -v SelfTests | grep -v Tests

Zero non-test callers = false-green suspect. The step is passing on dead code.

The hard gate

Green steps + clean build + clean csharpier are NOT sufficient. In-game smoke (Linux/Wine, via /xlperf) is the true gate. Where headless cannot honestly verify (scroll state, real send, atlas rebuild, warm object pools), mark the step explicitly as smoke-only instead of faking a headless pass.

Anti-pattern of record

HonorificService.ShouldRenderSlot once had zero production callers and was green only because the test called it directly — a test passing on a path the game never runs. v1.8.7 retired it: the gate is now wired into the real HonorificHeader.Draw and asserted through it via HonorificHeader.LastTitleRendered (see HonorificHeaderRenderStep). Kept here as the canonical example of the failure this standard prevents.

Step classification

The current real-path / helper-only / mixed classification of every registered step (with false-green suspects flagged) lives in the Obsidian vault: Projekte/FFXIV/Hellion Chat/Audits/HellionChat SelfTest-Klassifikation 2026-05-29.md.