test: add player-name collapse integration coverage

Resolves observation #3 from the final code review. The integration
tests previously asserted Steam-ID elimination, structural
preservation, and idempotence but did not directly verify that
synthetic player names collapse to <player> after redaction.

Adds testFixturePlayerNamesCollapseInCoveredContexts, parameterised
over the five fixtures (chat, cmd, item, map, user) where every
synthetic name appears exclusively in a context the redactor
recognises (ChatMessage author or Steam-ID-followed-by-quoted-name).
The data provider docblock explicitly enumerates which fixtures are
excluded and why — admin and client-action/perk because names appear
in unanchored or bracket-only contexts; pvp because the victim name
after `hit` is a v1 limitation; burd-journals/debug-server because no
synthetic player names are present.

Test count: 255 -> 260 (5 new effective cases from data-provider).
This commit is contained in:
2026-05-01 18:22:25 +00:00
parent 6bf63f1823
commit 50194c72b2

View File

@@ -69,6 +69,38 @@ class ProjectZomboidRedactorIntegrationTest extends TestCase
];
}
/**
* Yields [fixturePath] for the subset of fixtures where every synthetic
* player name (Player1 / Player2 / AdminUser / PlayerSuspect) appears
* exclusively in a context the redactor recognises:
*
* - chat: ChatMessage{author='...'} envelope
* - cmd, item, map, user: 77-char-Steam-ID followed by "..." quoted name
*
* Fixtures intentionally excluded:
*
* - admin: names appear in free-text positions (no Steam-ID anchor,
* no quotes, no Combat:/Safety: prefix). Names survive in v1.
* - client-action,
* perk: names appear inside [...] brackets, not "..." quotes.
* PLAYER_AFTER_STEAMID_REGEX requires double-quotes.
* - pvp: attacker name redacts but victim name after `hit "..."`
* survives in v1 (Task 3 limitation).
* - burd-journals,
* debug-server: no synthetic player names present.
*/
public static function fixturesWhereAllNamesAreInCoveredContextsProvider(): array
{
$dir = self::$fixturesDir;
return [
'chat' => [$dir . '/chat-minimal.txt'],
'cmd' => [$dir . '/cmd-minimal.txt'],
'item' => [$dir . '/item-minimal.txt'],
'map' => [$dir . '/map-minimal.txt'],
'user' => [$dir . '/user-minimal.txt'],
];
}
/**
* Yields [fixturePath, logClass] for the fixtures whose log class parses
* them. All 11 fixtures are represented.
@@ -202,4 +234,39 @@ class ProjectZomboidRedactorIntegrationTest extends TestCase
),
);
}
// ---------------------------------------------------------------------------
// Test 4 — Player-name collapse in fully-covered fixtures
// ---------------------------------------------------------------------------
/**
* For fixtures where every synthetic player name appears exclusively in a
* context the redactor recognises, no synthetic name should remain after
* redaction.
*
* This addresses observation #3 from the final code review (the integration
* tests previously asserted Steam-ID elimination + structural preservation
* + idempotence, but did not directly verify name collapse). The unit tests
* in ProjectZomboidRedactorPlayerNameTest cover this property exhaustively
* per-context; this integration test re-verifies it end-to-end against the
* fixtures that ride into iblogs.
*/
#[DataProvider('fixturesWhereAllNamesAreInCoveredContextsProvider')]
public function testFixturePlayerNamesCollapseInCoveredContexts(string $fixturePath): void
{
$content = (new PathLogFile($fixturePath))->getContent();
$redacted = $this->redact($content);
foreach (['Player1', 'Player2', 'AdminUser', 'PlayerSuspect'] as $name) {
$this->assertStringNotContainsString(
$name,
$redacted,
sprintf(
'Fixture "%s": synthetic name %s survived redaction. Every name in this fixture should appear only in a covered lexical context.',
basename($fixturePath),
$name,
),
);
}
}
}