From 50194c72b24a2cd96483ce3e30be9e3eedb61c00 Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Fri, 1 May 2026 18:22:25 +0000 Subject: [PATCH] test: add player-name collapse integration coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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). --- .../ProjectZomboidRedactorIntegrationTest.php | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/test/tests/Util/Redactor/ProjectZomboidRedactorIntegrationTest.php b/test/tests/Util/Redactor/ProjectZomboidRedactorIntegrationTest.php index be54778..6b94d02 100644 --- a/test/tests/Util/Redactor/ProjectZomboidRedactorIntegrationTest.php +++ b/test/tests/Util/Redactor/ProjectZomboidRedactorIntegrationTest.php @@ -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, + ), + ); + } + } }