fix: relax DebugServerPattern::LINE for PZ B42 log format

PZ build 42.x dropped the per-line `t:` (microsecond) field and
tightened the spacing between `f:N`, `t:N`, and `st:N,N,N,N>` markers.
The hardcoded `f:\d+,\s+t:\d+,\s+st:` requirement caused every B42
line to fail the parser's LINE regex, leaving ServerLog entries
without their level/prefix and silently disabling
ServerExceptionProblem and ModMissingProblem (the anchorless
EngineVersionInformation still fired against the joined entry text,
which is why the symptom was "one Information, no Problems").

Make `t:N,` optional via `(?:,\s+t:\d+)?` and the comma between
`f:N` and `st:` optional via `,?`. The B41 format remains a strict
match. Add `debug-server-42x-minimal.txt` mirroring the existing
synthetic fixture in the new format, and parameterise
ProjectZomboidServerLogTest with a #[DataProvider] so all four
parser-shape assertions now run against both formats. Spot-check:
analysers emit 3 Problems (2 exceptions, 1 missing mod) and 4
Information entries against the new fixture, identical to B41.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-06 13:33:35 +00:00
parent 45a5e1a3da
commit 0d18cfbfc6
3 changed files with 49 additions and 11 deletions

View File

@@ -6,18 +6,31 @@ use IndifferentKetchup\Codex\Detective\Detective;
use IndifferentKetchup\Codex\Log\File\PathLogFile;
use IndifferentKetchup\Codex\Log\Level;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidServerLog;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class ProjectZomboidServerLogTest extends TestCase
{
private function fixturePath(): string
/**
* Both PZ B41 and B42 line shapes must parse identically. B41 (and the
* fixture used by every analyser test) emits `f:N, t:N, st:N,N,N,N>`;
* B42 (release branch from 2026-04 onward, e.g. build 42.17) drops the
* `t:` microsecond field entirely and tightens whitespace to
* `f:N st:N,N,N,N>`.
*/
public static function fixtureProvider(): array
{
return __DIR__ . '/../../../../src/Games/ProjectZomboid/fixtures/debug-server-minimal.txt';
$base = __DIR__ . '/../../../../src/Games/ProjectZomboid/fixtures';
return [
'pz41-format' => [$base . '/debug-server-minimal.txt'],
'pz42-format' => [$base . '/debug-server-42x-minimal.txt'],
];
}
public function testParsesEntriesWithLevelAndPrefix(): void
#[DataProvider('fixtureProvider')]
public function testParsesEntriesWithLevelAndPrefix(string $fixturePath): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($fixturePath));
$log->parse();
$entries = $log->getEntries();
@@ -29,9 +42,10 @@ class ProjectZomboidServerLogTest extends TestCase
$this->assertNotNull($first->getTime());
}
public function testStackTraceLinesAttachToTriggeringErrorEntry(): void
#[DataProvider('fixtureProvider')]
public function testStackTraceLinesAttachToTriggeringErrorEntry(string $fixturePath): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($fixturePath));
$log->parse();
$errorEntry = null;
@@ -46,19 +60,21 @@ class ProjectZomboidServerLogTest extends TestCase
$this->assertGreaterThan(1, count($errorEntry->getLines()));
}
public function testWarnLevelMapsCorrectly(): void
#[DataProvider('fixtureProvider')]
public function testWarnLevelMapsCorrectly(string $fixturePath): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($fixturePath));
$log->parse();
$warnEntries = array_filter($log->getEntries(), fn($e) => $e->getLevel() === Level::WARNING);
$this->assertNotEmpty($warnEntries);
}
public function testDetectiveDispatchesByContent(): void
#[DataProvider('fixtureProvider')]
public function testDetectiveDispatchesByContent(string $fixturePath): void
{
$detective = (new Detective())
->setLogFile(new PathLogFile($this->fixturePath()))
->setLogFile(new PathLogFile($fixturePath))
->addPossibleLogClass(ProjectZomboidServerLog::class);
$log = $detective->detect();