presenter = new SystemAuditRowPresenter(); } public function testPresentNormalizesEnumsAndFillsDefaults(): void { $out = $this->presenter->present([ 'id' => 42, 'outcome' => 'success', 'channel' => 'web', 'event_type' => 'user.login', ]); $this->assertSame(42, $out['id']); $this->assertSame('success', $out['outcome']); $this->assertSame('user.login', $out['event_type']); $this->assertNotSame('', $out['outcome_label'], 'outcome_label should be translated, not empty'); $this->assertNotSame('', $out['outcome_badge'], 'outcome_badge variant should be set'); $this->assertSame(strtoupper($out['channel_label']), $out['channel_label'], 'channel label is uppercased'); $this->assertSame($out['channel'], $out['channel_label'], 'channel and channel_label stay in sync'); } public function testPresentFallsBackToDefaultsForUnknownEnumValues(): void { $out = $this->presenter->present([ 'outcome' => 'not-a-valid-outcome', 'channel' => 'not-a-valid-channel', ]); $this->assertSame('success', $out['outcome'], 'unknown outcome falls back to success'); $this->assertNotSame('', $out['channel'], 'unknown channel falls back to web/default'); } public function testActorLabelPrefersDisplayName(): void { $out = $this->presenter->present([ 'actor_user_display_name' => 'Alice Doe', 'actor_user_email' => 'alice@example.com', ]); $this->assertSame('Alice Doe', $out['actor_user_label']); $this->assertSame('alice@example.com', $out['actor_user_email']); } public function testActorLabelFallsBackToEmail(): void { $out = $this->presenter->present([ 'actor_user_display_name' => '', 'actor_user_email' => 'bob@example.com', ]); $this->assertSame('bob@example.com', $out['actor_user_label']); } public function testActorLabelFallsBackToDashWhenNothingAvailable(): void { $out = $this->presenter->present([]); $this->assertSame('-', $out['actor_user_label']); } public function testActorLabelTrimsWhitespace(): void { $out = $this->presenter->present([ 'actor_user_display_name' => " \t ", 'actor_user_email' => ' carol@example.com ', ]); $this->assertSame('carol@example.com', $out['actor_user_label']); } public function testMissingFieldsAreSafeDefaults(): void { $out = $this->presenter->present([]); $this->assertSame(0, $out['id']); $this->assertSame('', $out['event_type']); $this->assertSame('', $out['target_type']); $this->assertSame('', $out['target_uuid']); $this->assertSame('', $out['request_id']); $this->assertSame('', $out['error_code']); $this->assertSame(0, $out['actor_user_id']); } public function testPresentAllMapsIterableToList(): void { $rows = (function () { yield ['id' => 1, 'outcome' => 'success']; yield ['id' => 2, 'outcome' => 'failed']; })(); $out = $this->presenter->presentAll($rows); $this->assertCount(2, $out); $this->assertSame(1, $out[0]['id']); $this->assertSame(2, $out[1]['id']); $this->assertSame('failed', $out[1]['outcome']); } public function testPresentAllWithEmptyIterableReturnsEmptyArray(): void { $this->assertSame([], $this->presenter->presentAll([])); } }